1*5ffd940aSRaphael Isemann //===- FileCheck.cpp - Check that File's Contents match what is expected --===// 2*5ffd940aSRaphael Isemann // 3*5ffd940aSRaphael Isemann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd940aSRaphael Isemann // See https://llvm.org/LICENSE.txt for license information. 5*5ffd940aSRaphael Isemann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd940aSRaphael Isemann // 7*5ffd940aSRaphael Isemann //===----------------------------------------------------------------------===// 8*5ffd940aSRaphael Isemann // 9*5ffd940aSRaphael Isemann // FileCheck does a line-by line check of a file that validates whether it 10*5ffd940aSRaphael Isemann // contains the expected content. This is useful for regression tests etc. 11*5ffd940aSRaphael Isemann // 12*5ffd940aSRaphael Isemann // This file implements most of the API that will be used by the FileCheck utility 13*5ffd940aSRaphael Isemann // as well as various unittests. 14*5ffd940aSRaphael Isemann //===----------------------------------------------------------------------===// 15*5ffd940aSRaphael Isemann 16*5ffd940aSRaphael Isemann #include "llvm/FileCheck/FileCheck.h" 17*5ffd940aSRaphael Isemann #include "FileCheckImpl.h" 18*5ffd940aSRaphael Isemann #include "llvm/ADT/STLExtras.h" 19*5ffd940aSRaphael Isemann #include "llvm/ADT/StringSet.h" 20*5ffd940aSRaphael Isemann #include "llvm/ADT/Twine.h" 21*5ffd940aSRaphael Isemann #include "llvm/Support/CheckedArithmetic.h" 22*5ffd940aSRaphael Isemann #include "llvm/Support/FormatVariadic.h" 23*5ffd940aSRaphael Isemann #include <cstdint> 24*5ffd940aSRaphael Isemann #include <list> 25*5ffd940aSRaphael Isemann #include <tuple> 26*5ffd940aSRaphael Isemann #include <utility> 27*5ffd940aSRaphael Isemann 28*5ffd940aSRaphael Isemann using namespace llvm; 29*5ffd940aSRaphael Isemann 30*5ffd940aSRaphael Isemann StringRef ExpressionFormat::toString() const { 31*5ffd940aSRaphael Isemann switch (Value) { 32*5ffd940aSRaphael Isemann case Kind::NoFormat: 33*5ffd940aSRaphael Isemann return StringRef("<none>"); 34*5ffd940aSRaphael Isemann case Kind::Unsigned: 35*5ffd940aSRaphael Isemann return StringRef("%u"); 36*5ffd940aSRaphael Isemann case Kind::Signed: 37*5ffd940aSRaphael Isemann return StringRef("%d"); 38*5ffd940aSRaphael Isemann case Kind::HexUpper: 39*5ffd940aSRaphael Isemann return StringRef("%X"); 40*5ffd940aSRaphael Isemann case Kind::HexLower: 41*5ffd940aSRaphael Isemann return StringRef("%x"); 42*5ffd940aSRaphael Isemann } 43*5ffd940aSRaphael Isemann llvm_unreachable("unknown expression format"); 44*5ffd940aSRaphael Isemann } 45*5ffd940aSRaphael Isemann 46*5ffd940aSRaphael Isemann Expected<std::string> ExpressionFormat::getWildcardRegex() const { 47*5ffd940aSRaphael Isemann auto CreatePrecisionRegex = [this](StringRef S) { 48*5ffd940aSRaphael Isemann return (S + Twine('{') + Twine(Precision) + "}").str(); 49*5ffd940aSRaphael Isemann }; 50*5ffd940aSRaphael Isemann 51*5ffd940aSRaphael Isemann switch (Value) { 52*5ffd940aSRaphael Isemann case Kind::Unsigned: 53*5ffd940aSRaphael Isemann if (Precision) 54*5ffd940aSRaphael Isemann return CreatePrecisionRegex("([1-9][0-9]*)?[0-9]"); 55*5ffd940aSRaphael Isemann return std::string("[0-9]+"); 56*5ffd940aSRaphael Isemann case Kind::Signed: 57*5ffd940aSRaphael Isemann if (Precision) 58*5ffd940aSRaphael Isemann return CreatePrecisionRegex("-?([1-9][0-9]*)?[0-9]"); 59*5ffd940aSRaphael Isemann return std::string("-?[0-9]+"); 60*5ffd940aSRaphael Isemann case Kind::HexUpper: 61*5ffd940aSRaphael Isemann if (Precision) 62*5ffd940aSRaphael Isemann return CreatePrecisionRegex("([1-9A-F][0-9A-F]*)?[0-9A-F]"); 63*5ffd940aSRaphael Isemann return std::string("[0-9A-F]+"); 64*5ffd940aSRaphael Isemann case Kind::HexLower: 65*5ffd940aSRaphael Isemann if (Precision) 66*5ffd940aSRaphael Isemann return CreatePrecisionRegex("([1-9a-f][0-9a-f]*)?[0-9a-f]"); 67*5ffd940aSRaphael Isemann return std::string("[0-9a-f]+"); 68*5ffd940aSRaphael Isemann default: 69*5ffd940aSRaphael Isemann return createStringError(std::errc::invalid_argument, 70*5ffd940aSRaphael Isemann "trying to match value with invalid format"); 71*5ffd940aSRaphael Isemann } 72*5ffd940aSRaphael Isemann } 73*5ffd940aSRaphael Isemann 74*5ffd940aSRaphael Isemann Expected<std::string> 75*5ffd940aSRaphael Isemann ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const { 76*5ffd940aSRaphael Isemann uint64_t AbsoluteValue; 77*5ffd940aSRaphael Isemann StringRef SignPrefix = IntegerValue.isNegative() ? "-" : ""; 78*5ffd940aSRaphael Isemann 79*5ffd940aSRaphael Isemann if (Value == Kind::Signed) { 80*5ffd940aSRaphael Isemann Expected<int64_t> SignedValue = IntegerValue.getSignedValue(); 81*5ffd940aSRaphael Isemann if (!SignedValue) 82*5ffd940aSRaphael Isemann return SignedValue.takeError(); 83*5ffd940aSRaphael Isemann if (*SignedValue < 0) 84*5ffd940aSRaphael Isemann AbsoluteValue = cantFail(IntegerValue.getAbsolute().getUnsignedValue()); 85*5ffd940aSRaphael Isemann else 86*5ffd940aSRaphael Isemann AbsoluteValue = *SignedValue; 87*5ffd940aSRaphael Isemann } else { 88*5ffd940aSRaphael Isemann Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue(); 89*5ffd940aSRaphael Isemann if (!UnsignedValue) 90*5ffd940aSRaphael Isemann return UnsignedValue.takeError(); 91*5ffd940aSRaphael Isemann AbsoluteValue = *UnsignedValue; 92*5ffd940aSRaphael Isemann } 93*5ffd940aSRaphael Isemann 94*5ffd940aSRaphael Isemann std::string AbsoluteValueStr; 95*5ffd940aSRaphael Isemann switch (Value) { 96*5ffd940aSRaphael Isemann case Kind::Unsigned: 97*5ffd940aSRaphael Isemann case Kind::Signed: 98*5ffd940aSRaphael Isemann AbsoluteValueStr = utostr(AbsoluteValue); 99*5ffd940aSRaphael Isemann break; 100*5ffd940aSRaphael Isemann case Kind::HexUpper: 101*5ffd940aSRaphael Isemann case Kind::HexLower: 102*5ffd940aSRaphael Isemann AbsoluteValueStr = utohexstr(AbsoluteValue, Value == Kind::HexLower); 103*5ffd940aSRaphael Isemann break; 104*5ffd940aSRaphael Isemann default: 105*5ffd940aSRaphael Isemann return createStringError(std::errc::invalid_argument, 106*5ffd940aSRaphael Isemann "trying to match value with invalid format"); 107*5ffd940aSRaphael Isemann } 108*5ffd940aSRaphael Isemann 109*5ffd940aSRaphael Isemann if (Precision > AbsoluteValueStr.size()) { 110*5ffd940aSRaphael Isemann unsigned LeadingZeros = Precision - AbsoluteValueStr.size(); 111*5ffd940aSRaphael Isemann return (Twine(SignPrefix) + std::string(LeadingZeros, '0') + 112*5ffd940aSRaphael Isemann AbsoluteValueStr) 113*5ffd940aSRaphael Isemann .str(); 114*5ffd940aSRaphael Isemann } 115*5ffd940aSRaphael Isemann 116*5ffd940aSRaphael Isemann return (Twine(SignPrefix) + AbsoluteValueStr).str(); 117*5ffd940aSRaphael Isemann } 118*5ffd940aSRaphael Isemann 119*5ffd940aSRaphael Isemann Expected<ExpressionValue> 120*5ffd940aSRaphael Isemann ExpressionFormat::valueFromStringRepr(StringRef StrVal, 121*5ffd940aSRaphael Isemann const SourceMgr &SM) const { 122*5ffd940aSRaphael Isemann bool ValueIsSigned = Value == Kind::Signed; 123*5ffd940aSRaphael Isemann StringRef OverflowErrorStr = "unable to represent numeric value"; 124*5ffd940aSRaphael Isemann if (ValueIsSigned) { 125*5ffd940aSRaphael Isemann int64_t SignedValue; 126*5ffd940aSRaphael Isemann 127*5ffd940aSRaphael Isemann if (StrVal.getAsInteger(10, SignedValue)) 128*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr); 129*5ffd940aSRaphael Isemann 130*5ffd940aSRaphael Isemann return ExpressionValue(SignedValue); 131*5ffd940aSRaphael Isemann } 132*5ffd940aSRaphael Isemann 133*5ffd940aSRaphael Isemann bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower; 134*5ffd940aSRaphael Isemann uint64_t UnsignedValue; 135*5ffd940aSRaphael Isemann if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue)) 136*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr); 137*5ffd940aSRaphael Isemann 138*5ffd940aSRaphael Isemann return ExpressionValue(UnsignedValue); 139*5ffd940aSRaphael Isemann } 140*5ffd940aSRaphael Isemann 141*5ffd940aSRaphael Isemann static int64_t getAsSigned(uint64_t UnsignedValue) { 142*5ffd940aSRaphael Isemann // Use memcpy to reinterpret the bitpattern in Value since casting to 143*5ffd940aSRaphael Isemann // signed is implementation-defined if the unsigned value is too big to be 144*5ffd940aSRaphael Isemann // represented in the signed type and using an union violates type aliasing 145*5ffd940aSRaphael Isemann // rules. 146*5ffd940aSRaphael Isemann int64_t SignedValue; 147*5ffd940aSRaphael Isemann memcpy(&SignedValue, &UnsignedValue, sizeof(SignedValue)); 148*5ffd940aSRaphael Isemann return SignedValue; 149*5ffd940aSRaphael Isemann } 150*5ffd940aSRaphael Isemann 151*5ffd940aSRaphael Isemann Expected<int64_t> ExpressionValue::getSignedValue() const { 152*5ffd940aSRaphael Isemann if (Negative) 153*5ffd940aSRaphael Isemann return getAsSigned(Value); 154*5ffd940aSRaphael Isemann 155*5ffd940aSRaphael Isemann if (Value > (uint64_t)std::numeric_limits<int64_t>::max()) 156*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 157*5ffd940aSRaphael Isemann 158*5ffd940aSRaphael Isemann // Value is in the representable range of int64_t so we can use cast. 159*5ffd940aSRaphael Isemann return static_cast<int64_t>(Value); 160*5ffd940aSRaphael Isemann } 161*5ffd940aSRaphael Isemann 162*5ffd940aSRaphael Isemann Expected<uint64_t> ExpressionValue::getUnsignedValue() const { 163*5ffd940aSRaphael Isemann if (Negative) 164*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 165*5ffd940aSRaphael Isemann 166*5ffd940aSRaphael Isemann return Value; 167*5ffd940aSRaphael Isemann } 168*5ffd940aSRaphael Isemann 169*5ffd940aSRaphael Isemann ExpressionValue ExpressionValue::getAbsolute() const { 170*5ffd940aSRaphael Isemann if (!Negative) 171*5ffd940aSRaphael Isemann return *this; 172*5ffd940aSRaphael Isemann 173*5ffd940aSRaphael Isemann int64_t SignedValue = getAsSigned(Value); 174*5ffd940aSRaphael Isemann int64_t MaxInt64 = std::numeric_limits<int64_t>::max(); 175*5ffd940aSRaphael Isemann // Absolute value can be represented as int64_t. 176*5ffd940aSRaphael Isemann if (SignedValue >= -MaxInt64) 177*5ffd940aSRaphael Isemann return ExpressionValue(-getAsSigned(Value)); 178*5ffd940aSRaphael Isemann 179*5ffd940aSRaphael Isemann // -X == -(max int64_t + Rem), negate each component independently. 180*5ffd940aSRaphael Isemann SignedValue += MaxInt64; 181*5ffd940aSRaphael Isemann uint64_t RemainingValueAbsolute = -SignedValue; 182*5ffd940aSRaphael Isemann return ExpressionValue(MaxInt64 + RemainingValueAbsolute); 183*5ffd940aSRaphael Isemann } 184*5ffd940aSRaphael Isemann 185*5ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand, 186*5ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 187*5ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) { 188*5ffd940aSRaphael Isemann int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 189*5ffd940aSRaphael Isemann int64_t RightValue = cantFail(RightOperand.getSignedValue()); 190*5ffd940aSRaphael Isemann Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue); 191*5ffd940aSRaphael Isemann if (!Result) 192*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 193*5ffd940aSRaphael Isemann 194*5ffd940aSRaphael Isemann return ExpressionValue(*Result); 195*5ffd940aSRaphael Isemann } 196*5ffd940aSRaphael Isemann 197*5ffd940aSRaphael Isemann // (-A) + B == B - A. 198*5ffd940aSRaphael Isemann if (LeftOperand.isNegative()) 199*5ffd940aSRaphael Isemann return RightOperand - LeftOperand.getAbsolute(); 200*5ffd940aSRaphael Isemann 201*5ffd940aSRaphael Isemann // A + (-B) == A - B. 202*5ffd940aSRaphael Isemann if (RightOperand.isNegative()) 203*5ffd940aSRaphael Isemann return LeftOperand - RightOperand.getAbsolute(); 204*5ffd940aSRaphael Isemann 205*5ffd940aSRaphael Isemann // Both values are positive at this point. 206*5ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 207*5ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 208*5ffd940aSRaphael Isemann Optional<uint64_t> Result = 209*5ffd940aSRaphael Isemann checkedAddUnsigned<uint64_t>(LeftValue, RightValue); 210*5ffd940aSRaphael Isemann if (!Result) 211*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 212*5ffd940aSRaphael Isemann 213*5ffd940aSRaphael Isemann return ExpressionValue(*Result); 214*5ffd940aSRaphael Isemann } 215*5ffd940aSRaphael Isemann 216*5ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand, 217*5ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 218*5ffd940aSRaphael Isemann // Result will be negative and thus might underflow. 219*5ffd940aSRaphael Isemann if (LeftOperand.isNegative() && !RightOperand.isNegative()) { 220*5ffd940aSRaphael Isemann int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 221*5ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 222*5ffd940aSRaphael Isemann // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement. 223*5ffd940aSRaphael Isemann if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max()) 224*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 225*5ffd940aSRaphael Isemann Optional<int64_t> Result = 226*5ffd940aSRaphael Isemann checkedSub(LeftValue, static_cast<int64_t>(RightValue)); 227*5ffd940aSRaphael Isemann if (!Result) 228*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 229*5ffd940aSRaphael Isemann 230*5ffd940aSRaphael Isemann return ExpressionValue(*Result); 231*5ffd940aSRaphael Isemann } 232*5ffd940aSRaphael Isemann 233*5ffd940aSRaphael Isemann // (-A) - (-B) == B - A. 234*5ffd940aSRaphael Isemann if (LeftOperand.isNegative()) 235*5ffd940aSRaphael Isemann return RightOperand.getAbsolute() - LeftOperand.getAbsolute(); 236*5ffd940aSRaphael Isemann 237*5ffd940aSRaphael Isemann // A - (-B) == A + B. 238*5ffd940aSRaphael Isemann if (RightOperand.isNegative()) 239*5ffd940aSRaphael Isemann return LeftOperand + RightOperand.getAbsolute(); 240*5ffd940aSRaphael Isemann 241*5ffd940aSRaphael Isemann // Both values are positive at this point. 242*5ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 243*5ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 244*5ffd940aSRaphael Isemann if (LeftValue >= RightValue) 245*5ffd940aSRaphael Isemann return ExpressionValue(LeftValue - RightValue); 246*5ffd940aSRaphael Isemann else { 247*5ffd940aSRaphael Isemann uint64_t AbsoluteDifference = RightValue - LeftValue; 248*5ffd940aSRaphael Isemann uint64_t MaxInt64 = std::numeric_limits<int64_t>::max(); 249*5ffd940aSRaphael Isemann // Value might underflow. 250*5ffd940aSRaphael Isemann if (AbsoluteDifference > MaxInt64) { 251*5ffd940aSRaphael Isemann AbsoluteDifference -= MaxInt64; 252*5ffd940aSRaphael Isemann int64_t Result = -MaxInt64; 253*5ffd940aSRaphael Isemann int64_t MinInt64 = std::numeric_limits<int64_t>::min(); 254*5ffd940aSRaphael Isemann // Underflow, tested by: 255*5ffd940aSRaphael Isemann // abs(Result + (max int64_t)) > abs((min int64_t) + (max int64_t)) 256*5ffd940aSRaphael Isemann if (AbsoluteDifference > static_cast<uint64_t>(-(MinInt64 - Result))) 257*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 258*5ffd940aSRaphael Isemann Result -= static_cast<int64_t>(AbsoluteDifference); 259*5ffd940aSRaphael Isemann return ExpressionValue(Result); 260*5ffd940aSRaphael Isemann } 261*5ffd940aSRaphael Isemann 262*5ffd940aSRaphael Isemann return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference)); 263*5ffd940aSRaphael Isemann } 264*5ffd940aSRaphael Isemann } 265*5ffd940aSRaphael Isemann 266*5ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand, 267*5ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 268*5ffd940aSRaphael Isemann // -A * -B == A * B 269*5ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) 270*5ffd940aSRaphael Isemann return LeftOperand.getAbsolute() * RightOperand.getAbsolute(); 271*5ffd940aSRaphael Isemann 272*5ffd940aSRaphael Isemann // A * -B == -B * A 273*5ffd940aSRaphael Isemann if (RightOperand.isNegative()) 274*5ffd940aSRaphael Isemann return RightOperand * LeftOperand; 275*5ffd940aSRaphael Isemann 276*5ffd940aSRaphael Isemann assert(!RightOperand.isNegative() && "Unexpected negative operand!"); 277*5ffd940aSRaphael Isemann 278*5ffd940aSRaphael Isemann // Result will be negative and can underflow. 279*5ffd940aSRaphael Isemann if (LeftOperand.isNegative()) { 280*5ffd940aSRaphael Isemann auto Result = LeftOperand.getAbsolute() * RightOperand.getAbsolute(); 281*5ffd940aSRaphael Isemann if (!Result) 282*5ffd940aSRaphael Isemann return Result; 283*5ffd940aSRaphael Isemann 284*5ffd940aSRaphael Isemann return ExpressionValue(0) - *Result; 285*5ffd940aSRaphael Isemann } 286*5ffd940aSRaphael Isemann 287*5ffd940aSRaphael Isemann // Result will be positive and can overflow. 288*5ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 289*5ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 290*5ffd940aSRaphael Isemann Optional<uint64_t> Result = 291*5ffd940aSRaphael Isemann checkedMulUnsigned<uint64_t>(LeftValue, RightValue); 292*5ffd940aSRaphael Isemann if (!Result) 293*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 294*5ffd940aSRaphael Isemann 295*5ffd940aSRaphael Isemann return ExpressionValue(*Result); 296*5ffd940aSRaphael Isemann } 297*5ffd940aSRaphael Isemann 298*5ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand, 299*5ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 300*5ffd940aSRaphael Isemann // -A / -B == A / B 301*5ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) 302*5ffd940aSRaphael Isemann return LeftOperand.getAbsolute() / RightOperand.getAbsolute(); 303*5ffd940aSRaphael Isemann 304*5ffd940aSRaphael Isemann // Check for divide by zero. 305*5ffd940aSRaphael Isemann if (RightOperand == ExpressionValue(0)) 306*5ffd940aSRaphael Isemann return make_error<OverflowError>(); 307*5ffd940aSRaphael Isemann 308*5ffd940aSRaphael Isemann // Result will be negative and can underflow. 309*5ffd940aSRaphael Isemann if (LeftOperand.isNegative() || RightOperand.isNegative()) 310*5ffd940aSRaphael Isemann return ExpressionValue(0) - 311*5ffd940aSRaphael Isemann cantFail(LeftOperand.getAbsolute() / RightOperand.getAbsolute()); 312*5ffd940aSRaphael Isemann 313*5ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 314*5ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 315*5ffd940aSRaphael Isemann return ExpressionValue(LeftValue / RightValue); 316*5ffd940aSRaphael Isemann } 317*5ffd940aSRaphael Isemann 318*5ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand, 319*5ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 320*5ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) { 321*5ffd940aSRaphael Isemann int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 322*5ffd940aSRaphael Isemann int64_t RightValue = cantFail(RightOperand.getSignedValue()); 323*5ffd940aSRaphael Isemann return ExpressionValue(std::max(LeftValue, RightValue)); 324*5ffd940aSRaphael Isemann } 325*5ffd940aSRaphael Isemann 326*5ffd940aSRaphael Isemann if (!LeftOperand.isNegative() && !RightOperand.isNegative()) { 327*5ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 328*5ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 329*5ffd940aSRaphael Isemann return ExpressionValue(std::max(LeftValue, RightValue)); 330*5ffd940aSRaphael Isemann } 331*5ffd940aSRaphael Isemann 332*5ffd940aSRaphael Isemann if (LeftOperand.isNegative()) 333*5ffd940aSRaphael Isemann return RightOperand; 334*5ffd940aSRaphael Isemann 335*5ffd940aSRaphael Isemann return LeftOperand; 336*5ffd940aSRaphael Isemann } 337*5ffd940aSRaphael Isemann 338*5ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand, 339*5ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 340*5ffd940aSRaphael Isemann if (cantFail(max(LeftOperand, RightOperand)) == LeftOperand) 341*5ffd940aSRaphael Isemann return RightOperand; 342*5ffd940aSRaphael Isemann 343*5ffd940aSRaphael Isemann return LeftOperand; 344*5ffd940aSRaphael Isemann } 345*5ffd940aSRaphael Isemann 346*5ffd940aSRaphael Isemann Expected<ExpressionValue> NumericVariableUse::eval() const { 347*5ffd940aSRaphael Isemann Optional<ExpressionValue> Value = Variable->getValue(); 348*5ffd940aSRaphael Isemann if (Value) 349*5ffd940aSRaphael Isemann return *Value; 350*5ffd940aSRaphael Isemann 351*5ffd940aSRaphael Isemann return make_error<UndefVarError>(getExpressionStr()); 352*5ffd940aSRaphael Isemann } 353*5ffd940aSRaphael Isemann 354*5ffd940aSRaphael Isemann Expected<ExpressionValue> BinaryOperation::eval() const { 355*5ffd940aSRaphael Isemann Expected<ExpressionValue> LeftOp = LeftOperand->eval(); 356*5ffd940aSRaphael Isemann Expected<ExpressionValue> RightOp = RightOperand->eval(); 357*5ffd940aSRaphael Isemann 358*5ffd940aSRaphael Isemann // Bubble up any error (e.g. undefined variables) in the recursive 359*5ffd940aSRaphael Isemann // evaluation. 360*5ffd940aSRaphael Isemann if (!LeftOp || !RightOp) { 361*5ffd940aSRaphael Isemann Error Err = Error::success(); 362*5ffd940aSRaphael Isemann if (!LeftOp) 363*5ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), LeftOp.takeError()); 364*5ffd940aSRaphael Isemann if (!RightOp) 365*5ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), RightOp.takeError()); 366*5ffd940aSRaphael Isemann return std::move(Err); 367*5ffd940aSRaphael Isemann } 368*5ffd940aSRaphael Isemann 369*5ffd940aSRaphael Isemann return EvalBinop(*LeftOp, *RightOp); 370*5ffd940aSRaphael Isemann } 371*5ffd940aSRaphael Isemann 372*5ffd940aSRaphael Isemann Expected<ExpressionFormat> 373*5ffd940aSRaphael Isemann BinaryOperation::getImplicitFormat(const SourceMgr &SM) const { 374*5ffd940aSRaphael Isemann Expected<ExpressionFormat> LeftFormat = LeftOperand->getImplicitFormat(SM); 375*5ffd940aSRaphael Isemann Expected<ExpressionFormat> RightFormat = RightOperand->getImplicitFormat(SM); 376*5ffd940aSRaphael Isemann if (!LeftFormat || !RightFormat) { 377*5ffd940aSRaphael Isemann Error Err = Error::success(); 378*5ffd940aSRaphael Isemann if (!LeftFormat) 379*5ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), LeftFormat.takeError()); 380*5ffd940aSRaphael Isemann if (!RightFormat) 381*5ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), RightFormat.takeError()); 382*5ffd940aSRaphael Isemann return std::move(Err); 383*5ffd940aSRaphael Isemann } 384*5ffd940aSRaphael Isemann 385*5ffd940aSRaphael Isemann if (*LeftFormat != ExpressionFormat::Kind::NoFormat && 386*5ffd940aSRaphael Isemann *RightFormat != ExpressionFormat::Kind::NoFormat && 387*5ffd940aSRaphael Isemann *LeftFormat != *RightFormat) 388*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 389*5ffd940aSRaphael Isemann SM, getExpressionStr(), 390*5ffd940aSRaphael Isemann "implicit format conflict between '" + LeftOperand->getExpressionStr() + 391*5ffd940aSRaphael Isemann "' (" + LeftFormat->toString() + ") and '" + 392*5ffd940aSRaphael Isemann RightOperand->getExpressionStr() + "' (" + RightFormat->toString() + 393*5ffd940aSRaphael Isemann "), need an explicit format specifier"); 394*5ffd940aSRaphael Isemann 395*5ffd940aSRaphael Isemann return *LeftFormat != ExpressionFormat::Kind::NoFormat ? *LeftFormat 396*5ffd940aSRaphael Isemann : *RightFormat; 397*5ffd940aSRaphael Isemann } 398*5ffd940aSRaphael Isemann 399*5ffd940aSRaphael Isemann Expected<std::string> NumericSubstitution::getResult() const { 400*5ffd940aSRaphael Isemann assert(ExpressionPointer->getAST() != nullptr && 401*5ffd940aSRaphael Isemann "Substituting empty expression"); 402*5ffd940aSRaphael Isemann Expected<ExpressionValue> EvaluatedValue = 403*5ffd940aSRaphael Isemann ExpressionPointer->getAST()->eval(); 404*5ffd940aSRaphael Isemann if (!EvaluatedValue) 405*5ffd940aSRaphael Isemann return EvaluatedValue.takeError(); 406*5ffd940aSRaphael Isemann ExpressionFormat Format = ExpressionPointer->getFormat(); 407*5ffd940aSRaphael Isemann return Format.getMatchingString(*EvaluatedValue); 408*5ffd940aSRaphael Isemann } 409*5ffd940aSRaphael Isemann 410*5ffd940aSRaphael Isemann Expected<std::string> StringSubstitution::getResult() const { 411*5ffd940aSRaphael Isemann // Look up the value and escape it so that we can put it into the regex. 412*5ffd940aSRaphael Isemann Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr); 413*5ffd940aSRaphael Isemann if (!VarVal) 414*5ffd940aSRaphael Isemann return VarVal.takeError(); 415*5ffd940aSRaphael Isemann return Regex::escape(*VarVal); 416*5ffd940aSRaphael Isemann } 417*5ffd940aSRaphael Isemann 418*5ffd940aSRaphael Isemann bool Pattern::isValidVarNameStart(char C) { return C == '_' || isAlpha(C); } 419*5ffd940aSRaphael Isemann 420*5ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> 421*5ffd940aSRaphael Isemann Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) { 422*5ffd940aSRaphael Isemann if (Str.empty()) 423*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Str, "empty variable name"); 424*5ffd940aSRaphael Isemann 425*5ffd940aSRaphael Isemann size_t I = 0; 426*5ffd940aSRaphael Isemann bool IsPseudo = Str[0] == '@'; 427*5ffd940aSRaphael Isemann 428*5ffd940aSRaphael Isemann // Global vars start with '$'. 429*5ffd940aSRaphael Isemann if (Str[0] == '$' || IsPseudo) 430*5ffd940aSRaphael Isemann ++I; 431*5ffd940aSRaphael Isemann 432*5ffd940aSRaphael Isemann if (!isValidVarNameStart(Str[I++])) 433*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Str, "invalid variable name"); 434*5ffd940aSRaphael Isemann 435*5ffd940aSRaphael Isemann for (size_t E = Str.size(); I != E; ++I) 436*5ffd940aSRaphael Isemann // Variable names are composed of alphanumeric characters and underscores. 437*5ffd940aSRaphael Isemann if (Str[I] != '_' && !isAlnum(Str[I])) 438*5ffd940aSRaphael Isemann break; 439*5ffd940aSRaphael Isemann 440*5ffd940aSRaphael Isemann StringRef Name = Str.take_front(I); 441*5ffd940aSRaphael Isemann Str = Str.substr(I); 442*5ffd940aSRaphael Isemann return VariableProperties {Name, IsPseudo}; 443*5ffd940aSRaphael Isemann } 444*5ffd940aSRaphael Isemann 445*5ffd940aSRaphael Isemann // StringRef holding all characters considered as horizontal whitespaces by 446*5ffd940aSRaphael Isemann // FileCheck input canonicalization. 447*5ffd940aSRaphael Isemann constexpr StringLiteral SpaceChars = " \t"; 448*5ffd940aSRaphael Isemann 449*5ffd940aSRaphael Isemann // Parsing helper function that strips the first character in S and returns it. 450*5ffd940aSRaphael Isemann static char popFront(StringRef &S) { 451*5ffd940aSRaphael Isemann char C = S.front(); 452*5ffd940aSRaphael Isemann S = S.drop_front(); 453*5ffd940aSRaphael Isemann return C; 454*5ffd940aSRaphael Isemann } 455*5ffd940aSRaphael Isemann 456*5ffd940aSRaphael Isemann char OverflowError::ID = 0; 457*5ffd940aSRaphael Isemann char UndefVarError::ID = 0; 458*5ffd940aSRaphael Isemann char ErrorDiagnostic::ID = 0; 459*5ffd940aSRaphael Isemann char NotFoundError::ID = 0; 460*5ffd940aSRaphael Isemann 461*5ffd940aSRaphael Isemann Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( 462*5ffd940aSRaphael Isemann StringRef &Expr, FileCheckPatternContext *Context, 463*5ffd940aSRaphael Isemann Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat, 464*5ffd940aSRaphael Isemann const SourceMgr &SM) { 465*5ffd940aSRaphael Isemann Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM); 466*5ffd940aSRaphael Isemann if (!ParseVarResult) 467*5ffd940aSRaphael Isemann return ParseVarResult.takeError(); 468*5ffd940aSRaphael Isemann StringRef Name = ParseVarResult->Name; 469*5ffd940aSRaphael Isemann 470*5ffd940aSRaphael Isemann if (ParseVarResult->IsPseudo) 471*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 472*5ffd940aSRaphael Isemann SM, Name, "definition of pseudo numeric variable unsupported"); 473*5ffd940aSRaphael Isemann 474*5ffd940aSRaphael Isemann // Detect collisions between string and numeric variables when the latter 475*5ffd940aSRaphael Isemann // is created later than the former. 476*5ffd940aSRaphael Isemann if (Context->DefinedVariableTable.find(Name) != 477*5ffd940aSRaphael Isemann Context->DefinedVariableTable.end()) 478*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 479*5ffd940aSRaphael Isemann SM, Name, "string variable with name '" + Name + "' already exists"); 480*5ffd940aSRaphael Isemann 481*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 482*5ffd940aSRaphael Isemann if (!Expr.empty()) 483*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 484*5ffd940aSRaphael Isemann SM, Expr, "unexpected characters after numeric variable name"); 485*5ffd940aSRaphael Isemann 486*5ffd940aSRaphael Isemann NumericVariable *DefinedNumericVariable; 487*5ffd940aSRaphael Isemann auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); 488*5ffd940aSRaphael Isemann if (VarTableIter != Context->GlobalNumericVariableTable.end()) { 489*5ffd940aSRaphael Isemann DefinedNumericVariable = VarTableIter->second; 490*5ffd940aSRaphael Isemann if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat) 491*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 492*5ffd940aSRaphael Isemann SM, Expr, "format different from previous variable definition"); 493*5ffd940aSRaphael Isemann } else 494*5ffd940aSRaphael Isemann DefinedNumericVariable = 495*5ffd940aSRaphael Isemann Context->makeNumericVariable(Name, ImplicitFormat, LineNumber); 496*5ffd940aSRaphael Isemann 497*5ffd940aSRaphael Isemann return DefinedNumericVariable; 498*5ffd940aSRaphael Isemann } 499*5ffd940aSRaphael Isemann 500*5ffd940aSRaphael Isemann Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( 501*5ffd940aSRaphael Isemann StringRef Name, bool IsPseudo, Optional<size_t> LineNumber, 502*5ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 503*5ffd940aSRaphael Isemann if (IsPseudo && !Name.equals("@LINE")) 504*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 505*5ffd940aSRaphael Isemann SM, Name, "invalid pseudo numeric variable '" + Name + "'"); 506*5ffd940aSRaphael Isemann 507*5ffd940aSRaphael Isemann // Numeric variable definitions and uses are parsed in the order in which 508*5ffd940aSRaphael Isemann // they appear in the CHECK patterns. For each definition, the pointer to the 509*5ffd940aSRaphael Isemann // class instance of the corresponding numeric variable definition is stored 510*5ffd940aSRaphael Isemann // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer 511*5ffd940aSRaphael Isemann // we get below is null, it means no such variable was defined before. When 512*5ffd940aSRaphael Isemann // that happens, we create a dummy variable so that parsing can continue. All 513*5ffd940aSRaphael Isemann // uses of undefined variables, whether string or numeric, are then diagnosed 514*5ffd940aSRaphael Isemann // in printSubstitutions() after failing to match. 515*5ffd940aSRaphael Isemann auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); 516*5ffd940aSRaphael Isemann NumericVariable *NumericVariable; 517*5ffd940aSRaphael Isemann if (VarTableIter != Context->GlobalNumericVariableTable.end()) 518*5ffd940aSRaphael Isemann NumericVariable = VarTableIter->second; 519*5ffd940aSRaphael Isemann else { 520*5ffd940aSRaphael Isemann NumericVariable = Context->makeNumericVariable( 521*5ffd940aSRaphael Isemann Name, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); 522*5ffd940aSRaphael Isemann Context->GlobalNumericVariableTable[Name] = NumericVariable; 523*5ffd940aSRaphael Isemann } 524*5ffd940aSRaphael Isemann 525*5ffd940aSRaphael Isemann Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber(); 526*5ffd940aSRaphael Isemann if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber) 527*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 528*5ffd940aSRaphael Isemann SM, Name, 529*5ffd940aSRaphael Isemann "numeric variable '" + Name + 530*5ffd940aSRaphael Isemann "' defined earlier in the same CHECK directive"); 531*5ffd940aSRaphael Isemann 532*5ffd940aSRaphael Isemann return std::make_unique<NumericVariableUse>(Name, NumericVariable); 533*5ffd940aSRaphael Isemann } 534*5ffd940aSRaphael Isemann 535*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand( 536*5ffd940aSRaphael Isemann StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint, 537*5ffd940aSRaphael Isemann Optional<size_t> LineNumber, FileCheckPatternContext *Context, 538*5ffd940aSRaphael Isemann const SourceMgr &SM) { 539*5ffd940aSRaphael Isemann if (Expr.startswith("(")) { 540*5ffd940aSRaphael Isemann if (AO != AllowedOperand::Any) 541*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 542*5ffd940aSRaphael Isemann SM, Expr, "parenthesized expression not permitted here"); 543*5ffd940aSRaphael Isemann return parseParenExpr(Expr, LineNumber, Context, SM); 544*5ffd940aSRaphael Isemann } 545*5ffd940aSRaphael Isemann 546*5ffd940aSRaphael Isemann if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { 547*5ffd940aSRaphael Isemann // Try to parse as a numeric variable use. 548*5ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> ParseVarResult = 549*5ffd940aSRaphael Isemann parseVariable(Expr, SM); 550*5ffd940aSRaphael Isemann if (ParseVarResult) { 551*5ffd940aSRaphael Isemann // Try to parse a function call. 552*5ffd940aSRaphael Isemann if (Expr.ltrim(SpaceChars).startswith("(")) { 553*5ffd940aSRaphael Isemann if (AO != AllowedOperand::Any) 554*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, ParseVarResult->Name, 555*5ffd940aSRaphael Isemann "unexpected function call"); 556*5ffd940aSRaphael Isemann 557*5ffd940aSRaphael Isemann return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context, 558*5ffd940aSRaphael Isemann SM); 559*5ffd940aSRaphael Isemann } 560*5ffd940aSRaphael Isemann 561*5ffd940aSRaphael Isemann return parseNumericVariableUse(ParseVarResult->Name, 562*5ffd940aSRaphael Isemann ParseVarResult->IsPseudo, LineNumber, 563*5ffd940aSRaphael Isemann Context, SM); 564*5ffd940aSRaphael Isemann } 565*5ffd940aSRaphael Isemann 566*5ffd940aSRaphael Isemann if (AO == AllowedOperand::LineVar) 567*5ffd940aSRaphael Isemann return ParseVarResult.takeError(); 568*5ffd940aSRaphael Isemann // Ignore the error and retry parsing as a literal. 569*5ffd940aSRaphael Isemann consumeError(ParseVarResult.takeError()); 570*5ffd940aSRaphael Isemann } 571*5ffd940aSRaphael Isemann 572*5ffd940aSRaphael Isemann // Otherwise, parse it as a literal. 573*5ffd940aSRaphael Isemann int64_t SignedLiteralValue; 574*5ffd940aSRaphael Isemann uint64_t UnsignedLiteralValue; 575*5ffd940aSRaphael Isemann StringRef SaveExpr = Expr; 576*5ffd940aSRaphael Isemann // Accept both signed and unsigned literal, default to signed literal. 577*5ffd940aSRaphael Isemann if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0, 578*5ffd940aSRaphael Isemann UnsignedLiteralValue)) 579*5ffd940aSRaphael Isemann return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), 580*5ffd940aSRaphael Isemann UnsignedLiteralValue); 581*5ffd940aSRaphael Isemann Expr = SaveExpr; 582*5ffd940aSRaphael Isemann if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue)) 583*5ffd940aSRaphael Isemann return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), 584*5ffd940aSRaphael Isemann SignedLiteralValue); 585*5ffd940aSRaphael Isemann 586*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 587*5ffd940aSRaphael Isemann SM, Expr, 588*5ffd940aSRaphael Isemann Twine("invalid ") + 589*5ffd940aSRaphael Isemann (MaybeInvalidConstraint ? "matching constraint or " : "") + 590*5ffd940aSRaphael Isemann "operand format"); 591*5ffd940aSRaphael Isemann } 592*5ffd940aSRaphael Isemann 593*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> 594*5ffd940aSRaphael Isemann Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber, 595*5ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 596*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 597*5ffd940aSRaphael Isemann assert(Expr.startswith("(")); 598*5ffd940aSRaphael Isemann 599*5ffd940aSRaphael Isemann // Parse right operand. 600*5ffd940aSRaphael Isemann Expr.consume_front("("); 601*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 602*5ffd940aSRaphael Isemann if (Expr.empty()) 603*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, "missing operand in expression"); 604*5ffd940aSRaphael Isemann 605*5ffd940aSRaphael Isemann // Note: parseNumericOperand handles nested opening parentheses. 606*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> SubExprResult = parseNumericOperand( 607*5ffd940aSRaphael Isemann Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, 608*5ffd940aSRaphael Isemann Context, SM); 609*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 610*5ffd940aSRaphael Isemann while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) { 611*5ffd940aSRaphael Isemann StringRef OrigExpr = Expr; 612*5ffd940aSRaphael Isemann SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false, 613*5ffd940aSRaphael Isemann LineNumber, Context, SM); 614*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 615*5ffd940aSRaphael Isemann } 616*5ffd940aSRaphael Isemann if (!SubExprResult) 617*5ffd940aSRaphael Isemann return SubExprResult; 618*5ffd940aSRaphael Isemann 619*5ffd940aSRaphael Isemann if (!Expr.consume_front(")")) { 620*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, 621*5ffd940aSRaphael Isemann "missing ')' at end of nested expression"); 622*5ffd940aSRaphael Isemann } 623*5ffd940aSRaphael Isemann return SubExprResult; 624*5ffd940aSRaphael Isemann } 625*5ffd940aSRaphael Isemann 626*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> 627*5ffd940aSRaphael Isemann Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr, 628*5ffd940aSRaphael Isemann std::unique_ptr<ExpressionAST> LeftOp, 629*5ffd940aSRaphael Isemann bool IsLegacyLineExpr, Optional<size_t> LineNumber, 630*5ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 631*5ffd940aSRaphael Isemann RemainingExpr = RemainingExpr.ltrim(SpaceChars); 632*5ffd940aSRaphael Isemann if (RemainingExpr.empty()) 633*5ffd940aSRaphael Isemann return std::move(LeftOp); 634*5ffd940aSRaphael Isemann 635*5ffd940aSRaphael Isemann // Check if this is a supported operation and select a function to perform 636*5ffd940aSRaphael Isemann // it. 637*5ffd940aSRaphael Isemann SMLoc OpLoc = SMLoc::getFromPointer(RemainingExpr.data()); 638*5ffd940aSRaphael Isemann char Operator = popFront(RemainingExpr); 639*5ffd940aSRaphael Isemann binop_eval_t EvalBinop; 640*5ffd940aSRaphael Isemann switch (Operator) { 641*5ffd940aSRaphael Isemann case '+': 642*5ffd940aSRaphael Isemann EvalBinop = operator+; 643*5ffd940aSRaphael Isemann break; 644*5ffd940aSRaphael Isemann case '-': 645*5ffd940aSRaphael Isemann EvalBinop = operator-; 646*5ffd940aSRaphael Isemann break; 647*5ffd940aSRaphael Isemann default: 648*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 649*5ffd940aSRaphael Isemann SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); 650*5ffd940aSRaphael Isemann } 651*5ffd940aSRaphael Isemann 652*5ffd940aSRaphael Isemann // Parse right operand. 653*5ffd940aSRaphael Isemann RemainingExpr = RemainingExpr.ltrim(SpaceChars); 654*5ffd940aSRaphael Isemann if (RemainingExpr.empty()) 655*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, RemainingExpr, 656*5ffd940aSRaphael Isemann "missing operand in expression"); 657*5ffd940aSRaphael Isemann // The second operand in a legacy @LINE expression is always a literal. 658*5ffd940aSRaphael Isemann AllowedOperand AO = 659*5ffd940aSRaphael Isemann IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any; 660*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> RightOpResult = 661*5ffd940aSRaphael Isemann parseNumericOperand(RemainingExpr, AO, /*MaybeInvalidConstraint=*/false, 662*5ffd940aSRaphael Isemann LineNumber, Context, SM); 663*5ffd940aSRaphael Isemann if (!RightOpResult) 664*5ffd940aSRaphael Isemann return RightOpResult; 665*5ffd940aSRaphael Isemann 666*5ffd940aSRaphael Isemann Expr = Expr.drop_back(RemainingExpr.size()); 667*5ffd940aSRaphael Isemann return std::make_unique<BinaryOperation>(Expr, EvalBinop, std::move(LeftOp), 668*5ffd940aSRaphael Isemann std::move(*RightOpResult)); 669*5ffd940aSRaphael Isemann } 670*5ffd940aSRaphael Isemann 671*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> 672*5ffd940aSRaphael Isemann Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName, 673*5ffd940aSRaphael Isemann Optional<size_t> LineNumber, 674*5ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 675*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 676*5ffd940aSRaphael Isemann assert(Expr.startswith("(")); 677*5ffd940aSRaphael Isemann 678*5ffd940aSRaphael Isemann auto OptFunc = StringSwitch<Optional<binop_eval_t>>(FuncName) 679*5ffd940aSRaphael Isemann .Case("add", operator+) 680*5ffd940aSRaphael Isemann .Case("div", operator/) 681*5ffd940aSRaphael Isemann .Case("max", max) 682*5ffd940aSRaphael Isemann .Case("min", min) 683*5ffd940aSRaphael Isemann .Case("mul", operator*) 684*5ffd940aSRaphael Isemann .Case("sub", operator-) 685*5ffd940aSRaphael Isemann .Default(None); 686*5ffd940aSRaphael Isemann 687*5ffd940aSRaphael Isemann if (!OptFunc) 688*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 689*5ffd940aSRaphael Isemann SM, FuncName, Twine("call to undefined function '") + FuncName + "'"); 690*5ffd940aSRaphael Isemann 691*5ffd940aSRaphael Isemann Expr.consume_front("("); 692*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 693*5ffd940aSRaphael Isemann 694*5ffd940aSRaphael Isemann // Parse call arguments, which are comma separated. 695*5ffd940aSRaphael Isemann SmallVector<std::unique_ptr<ExpressionAST>, 4> Args; 696*5ffd940aSRaphael Isemann while (!Expr.empty() && !Expr.startswith(")")) { 697*5ffd940aSRaphael Isemann if (Expr.startswith(",")) 698*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, "missing argument"); 699*5ffd940aSRaphael Isemann 700*5ffd940aSRaphael Isemann // Parse the argument, which is an arbitary expression. 701*5ffd940aSRaphael Isemann StringRef OuterBinOpExpr = Expr; 702*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> Arg = parseNumericOperand( 703*5ffd940aSRaphael Isemann Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, 704*5ffd940aSRaphael Isemann Context, SM); 705*5ffd940aSRaphael Isemann while (Arg && !Expr.empty()) { 706*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 707*5ffd940aSRaphael Isemann // Have we reached an argument terminator? 708*5ffd940aSRaphael Isemann if (Expr.startswith(",") || Expr.startswith(")")) 709*5ffd940aSRaphael Isemann break; 710*5ffd940aSRaphael Isemann 711*5ffd940aSRaphael Isemann // Arg = Arg <op> <expr> 712*5ffd940aSRaphael Isemann Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber, 713*5ffd940aSRaphael Isemann Context, SM); 714*5ffd940aSRaphael Isemann } 715*5ffd940aSRaphael Isemann 716*5ffd940aSRaphael Isemann // Prefer an expression error over a generic invalid argument message. 717*5ffd940aSRaphael Isemann if (!Arg) 718*5ffd940aSRaphael Isemann return Arg.takeError(); 719*5ffd940aSRaphael Isemann Args.push_back(std::move(*Arg)); 720*5ffd940aSRaphael Isemann 721*5ffd940aSRaphael Isemann // Have we parsed all available arguments? 722*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 723*5ffd940aSRaphael Isemann if (!Expr.consume_front(",")) 724*5ffd940aSRaphael Isemann break; 725*5ffd940aSRaphael Isemann 726*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 727*5ffd940aSRaphael Isemann if (Expr.startswith(")")) 728*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, "missing argument"); 729*5ffd940aSRaphael Isemann } 730*5ffd940aSRaphael Isemann 731*5ffd940aSRaphael Isemann if (!Expr.consume_front(")")) 732*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, 733*5ffd940aSRaphael Isemann "missing ')' at end of call expression"); 734*5ffd940aSRaphael Isemann 735*5ffd940aSRaphael Isemann const unsigned NumArgs = Args.size(); 736*5ffd940aSRaphael Isemann if (NumArgs == 2) 737*5ffd940aSRaphael Isemann return std::make_unique<BinaryOperation>(Expr, *OptFunc, std::move(Args[0]), 738*5ffd940aSRaphael Isemann std::move(Args[1])); 739*5ffd940aSRaphael Isemann 740*5ffd940aSRaphael Isemann // TODO: Support more than binop_eval_t. 741*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, FuncName, 742*5ffd940aSRaphael Isemann Twine("function '") + FuncName + 743*5ffd940aSRaphael Isemann Twine("' takes 2 arguments but ") + 744*5ffd940aSRaphael Isemann Twine(NumArgs) + " given"); 745*5ffd940aSRaphael Isemann } 746*5ffd940aSRaphael Isemann 747*5ffd940aSRaphael Isemann Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock( 748*5ffd940aSRaphael Isemann StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable, 749*5ffd940aSRaphael Isemann bool IsLegacyLineExpr, Optional<size_t> LineNumber, 750*5ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 751*5ffd940aSRaphael Isemann std::unique_ptr<ExpressionAST> ExpressionASTPointer = nullptr; 752*5ffd940aSRaphael Isemann StringRef DefExpr = StringRef(); 753*5ffd940aSRaphael Isemann DefinedNumericVariable = None; 754*5ffd940aSRaphael Isemann ExpressionFormat ExplicitFormat = ExpressionFormat(); 755*5ffd940aSRaphael Isemann unsigned Precision = 0; 756*5ffd940aSRaphael Isemann 757*5ffd940aSRaphael Isemann // Parse format specifier (NOTE: ',' is also an argument seperator). 758*5ffd940aSRaphael Isemann size_t FormatSpecEnd = Expr.find(','); 759*5ffd940aSRaphael Isemann size_t FunctionStart = Expr.find('('); 760*5ffd940aSRaphael Isemann if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) { 761*5ffd940aSRaphael Isemann StringRef FormatExpr = Expr.take_front(FormatSpecEnd); 762*5ffd940aSRaphael Isemann Expr = Expr.drop_front(FormatSpecEnd + 1); 763*5ffd940aSRaphael Isemann FormatExpr = FormatExpr.trim(SpaceChars); 764*5ffd940aSRaphael Isemann if (!FormatExpr.consume_front("%")) 765*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 766*5ffd940aSRaphael Isemann SM, FormatExpr, 767*5ffd940aSRaphael Isemann "invalid matching format specification in expression"); 768*5ffd940aSRaphael Isemann 769*5ffd940aSRaphael Isemann // Parse precision. 770*5ffd940aSRaphael Isemann if (FormatExpr.consume_front(".")) { 771*5ffd940aSRaphael Isemann if (FormatExpr.consumeInteger(10, Precision)) 772*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, FormatExpr, 773*5ffd940aSRaphael Isemann "invalid precision in format specifier"); 774*5ffd940aSRaphael Isemann } 775*5ffd940aSRaphael Isemann 776*5ffd940aSRaphael Isemann if (!FormatExpr.empty()) { 777*5ffd940aSRaphael Isemann // Check for unknown matching format specifier and set matching format in 778*5ffd940aSRaphael Isemann // class instance representing this expression. 779*5ffd940aSRaphael Isemann SMLoc FmtLoc = SMLoc::getFromPointer(FormatExpr.data()); 780*5ffd940aSRaphael Isemann switch (popFront(FormatExpr)) { 781*5ffd940aSRaphael Isemann case 'u': 782*5ffd940aSRaphael Isemann ExplicitFormat = 783*5ffd940aSRaphael Isemann ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision); 784*5ffd940aSRaphael Isemann break; 785*5ffd940aSRaphael Isemann case 'd': 786*5ffd940aSRaphael Isemann ExplicitFormat = 787*5ffd940aSRaphael Isemann ExpressionFormat(ExpressionFormat::Kind::Signed, Precision); 788*5ffd940aSRaphael Isemann break; 789*5ffd940aSRaphael Isemann case 'x': 790*5ffd940aSRaphael Isemann ExplicitFormat = 791*5ffd940aSRaphael Isemann ExpressionFormat(ExpressionFormat::Kind::HexLower, Precision); 792*5ffd940aSRaphael Isemann break; 793*5ffd940aSRaphael Isemann case 'X': 794*5ffd940aSRaphael Isemann ExplicitFormat = 795*5ffd940aSRaphael Isemann ExpressionFormat(ExpressionFormat::Kind::HexUpper, Precision); 796*5ffd940aSRaphael Isemann break; 797*5ffd940aSRaphael Isemann default: 798*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, FmtLoc, 799*5ffd940aSRaphael Isemann "invalid format specifier in expression"); 800*5ffd940aSRaphael Isemann } 801*5ffd940aSRaphael Isemann } 802*5ffd940aSRaphael Isemann 803*5ffd940aSRaphael Isemann FormatExpr = FormatExpr.ltrim(SpaceChars); 804*5ffd940aSRaphael Isemann if (!FormatExpr.empty()) 805*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 806*5ffd940aSRaphael Isemann SM, FormatExpr, 807*5ffd940aSRaphael Isemann "invalid matching format specification in expression"); 808*5ffd940aSRaphael Isemann } 809*5ffd940aSRaphael Isemann 810*5ffd940aSRaphael Isemann // Save variable definition expression if any. 811*5ffd940aSRaphael Isemann size_t DefEnd = Expr.find(':'); 812*5ffd940aSRaphael Isemann if (DefEnd != StringRef::npos) { 813*5ffd940aSRaphael Isemann DefExpr = Expr.substr(0, DefEnd); 814*5ffd940aSRaphael Isemann Expr = Expr.substr(DefEnd + 1); 815*5ffd940aSRaphael Isemann } 816*5ffd940aSRaphael Isemann 817*5ffd940aSRaphael Isemann // Parse matching constraint. 818*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 819*5ffd940aSRaphael Isemann bool HasParsedValidConstraint = false; 820*5ffd940aSRaphael Isemann if (Expr.consume_front("==")) 821*5ffd940aSRaphael Isemann HasParsedValidConstraint = true; 822*5ffd940aSRaphael Isemann 823*5ffd940aSRaphael Isemann // Parse the expression itself. 824*5ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 825*5ffd940aSRaphael Isemann if (Expr.empty()) { 826*5ffd940aSRaphael Isemann if (HasParsedValidConstraint) 827*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 828*5ffd940aSRaphael Isemann SM, Expr, "empty numeric expression should not have a constraint"); 829*5ffd940aSRaphael Isemann } else { 830*5ffd940aSRaphael Isemann Expr = Expr.rtrim(SpaceChars); 831*5ffd940aSRaphael Isemann StringRef OuterBinOpExpr = Expr; 832*5ffd940aSRaphael Isemann // The first operand in a legacy @LINE expression is always the @LINE 833*5ffd940aSRaphael Isemann // pseudo variable. 834*5ffd940aSRaphael Isemann AllowedOperand AO = 835*5ffd940aSRaphael Isemann IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any; 836*5ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> ParseResult = parseNumericOperand( 837*5ffd940aSRaphael Isemann Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM); 838*5ffd940aSRaphael Isemann while (ParseResult && !Expr.empty()) { 839*5ffd940aSRaphael Isemann ParseResult = parseBinop(OuterBinOpExpr, Expr, std::move(*ParseResult), 840*5ffd940aSRaphael Isemann IsLegacyLineExpr, LineNumber, Context, SM); 841*5ffd940aSRaphael Isemann // Legacy @LINE expressions only allow 2 operands. 842*5ffd940aSRaphael Isemann if (ParseResult && IsLegacyLineExpr && !Expr.empty()) 843*5ffd940aSRaphael Isemann return ErrorDiagnostic::get( 844*5ffd940aSRaphael Isemann SM, Expr, 845*5ffd940aSRaphael Isemann "unexpected characters at end of expression '" + Expr + "'"); 846*5ffd940aSRaphael Isemann } 847*5ffd940aSRaphael Isemann if (!ParseResult) 848*5ffd940aSRaphael Isemann return ParseResult.takeError(); 849*5ffd940aSRaphael Isemann ExpressionASTPointer = std::move(*ParseResult); 850*5ffd940aSRaphael Isemann } 851*5ffd940aSRaphael Isemann 852*5ffd940aSRaphael Isemann // Select format of the expression, i.e. (i) its explicit format, if any, 853*5ffd940aSRaphael Isemann // otherwise (ii) its implicit format, if any, otherwise (iii) the default 854*5ffd940aSRaphael Isemann // format (unsigned). Error out in case of conflicting implicit format 855*5ffd940aSRaphael Isemann // without explicit format. 856*5ffd940aSRaphael Isemann ExpressionFormat Format; 857*5ffd940aSRaphael Isemann if (ExplicitFormat) 858*5ffd940aSRaphael Isemann Format = ExplicitFormat; 859*5ffd940aSRaphael Isemann else if (ExpressionASTPointer) { 860*5ffd940aSRaphael Isemann Expected<ExpressionFormat> ImplicitFormat = 861*5ffd940aSRaphael Isemann ExpressionASTPointer->getImplicitFormat(SM); 862*5ffd940aSRaphael Isemann if (!ImplicitFormat) 863*5ffd940aSRaphael Isemann return ImplicitFormat.takeError(); 864*5ffd940aSRaphael Isemann Format = *ImplicitFormat; 865*5ffd940aSRaphael Isemann } 866*5ffd940aSRaphael Isemann if (!Format) 867*5ffd940aSRaphael Isemann Format = ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision); 868*5ffd940aSRaphael Isemann 869*5ffd940aSRaphael Isemann std::unique_ptr<Expression> ExpressionPointer = 870*5ffd940aSRaphael Isemann std::make_unique<Expression>(std::move(ExpressionASTPointer), Format); 871*5ffd940aSRaphael Isemann 872*5ffd940aSRaphael Isemann // Parse the numeric variable definition. 873*5ffd940aSRaphael Isemann if (DefEnd != StringRef::npos) { 874*5ffd940aSRaphael Isemann DefExpr = DefExpr.ltrim(SpaceChars); 875*5ffd940aSRaphael Isemann Expected<NumericVariable *> ParseResult = parseNumericVariableDefinition( 876*5ffd940aSRaphael Isemann DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM); 877*5ffd940aSRaphael Isemann 878*5ffd940aSRaphael Isemann if (!ParseResult) 879*5ffd940aSRaphael Isemann return ParseResult.takeError(); 880*5ffd940aSRaphael Isemann DefinedNumericVariable = *ParseResult; 881*5ffd940aSRaphael Isemann } 882*5ffd940aSRaphael Isemann 883*5ffd940aSRaphael Isemann return std::move(ExpressionPointer); 884*5ffd940aSRaphael Isemann } 885*5ffd940aSRaphael Isemann 886*5ffd940aSRaphael Isemann bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, 887*5ffd940aSRaphael Isemann SourceMgr &SM, const FileCheckRequest &Req) { 888*5ffd940aSRaphael Isemann bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; 889*5ffd940aSRaphael Isemann IgnoreCase = Req.IgnoreCase; 890*5ffd940aSRaphael Isemann 891*5ffd940aSRaphael Isemann PatternLoc = SMLoc::getFromPointer(PatternStr.data()); 892*5ffd940aSRaphael Isemann 893*5ffd940aSRaphael Isemann if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) 894*5ffd940aSRaphael Isemann // Ignore trailing whitespace. 895*5ffd940aSRaphael Isemann while (!PatternStr.empty() && 896*5ffd940aSRaphael Isemann (PatternStr.back() == ' ' || PatternStr.back() == '\t')) 897*5ffd940aSRaphael Isemann PatternStr = PatternStr.substr(0, PatternStr.size() - 1); 898*5ffd940aSRaphael Isemann 899*5ffd940aSRaphael Isemann // Check that there is something on the line. 900*5ffd940aSRaphael Isemann if (PatternStr.empty() && CheckTy != Check::CheckEmpty) { 901*5ffd940aSRaphael Isemann SM.PrintMessage(PatternLoc, SourceMgr::DK_Error, 902*5ffd940aSRaphael Isemann "found empty check string with prefix '" + Prefix + ":'"); 903*5ffd940aSRaphael Isemann return true; 904*5ffd940aSRaphael Isemann } 905*5ffd940aSRaphael Isemann 906*5ffd940aSRaphael Isemann if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) { 907*5ffd940aSRaphael Isemann SM.PrintMessage( 908*5ffd940aSRaphael Isemann PatternLoc, SourceMgr::DK_Error, 909*5ffd940aSRaphael Isemann "found non-empty check string for empty check with prefix '" + Prefix + 910*5ffd940aSRaphael Isemann ":'"); 911*5ffd940aSRaphael Isemann return true; 912*5ffd940aSRaphael Isemann } 913*5ffd940aSRaphael Isemann 914*5ffd940aSRaphael Isemann if (CheckTy == Check::CheckEmpty) { 915*5ffd940aSRaphael Isemann RegExStr = "(\n$)"; 916*5ffd940aSRaphael Isemann return false; 917*5ffd940aSRaphael Isemann } 918*5ffd940aSRaphael Isemann 919*5ffd940aSRaphael Isemann // Check to see if this is a fixed string, or if it has regex pieces. 920*5ffd940aSRaphael Isemann if (!MatchFullLinesHere && 921*5ffd940aSRaphael Isemann (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos && 922*5ffd940aSRaphael Isemann PatternStr.find("[[") == StringRef::npos))) { 923*5ffd940aSRaphael Isemann FixedStr = PatternStr; 924*5ffd940aSRaphael Isemann return false; 925*5ffd940aSRaphael Isemann } 926*5ffd940aSRaphael Isemann 927*5ffd940aSRaphael Isemann if (MatchFullLinesHere) { 928*5ffd940aSRaphael Isemann RegExStr += '^'; 929*5ffd940aSRaphael Isemann if (!Req.NoCanonicalizeWhiteSpace) 930*5ffd940aSRaphael Isemann RegExStr += " *"; 931*5ffd940aSRaphael Isemann } 932*5ffd940aSRaphael Isemann 933*5ffd940aSRaphael Isemann // Paren value #0 is for the fully matched string. Any new parenthesized 934*5ffd940aSRaphael Isemann // values add from there. 935*5ffd940aSRaphael Isemann unsigned CurParen = 1; 936*5ffd940aSRaphael Isemann 937*5ffd940aSRaphael Isemann // Otherwise, there is at least one regex piece. Build up the regex pattern 938*5ffd940aSRaphael Isemann // by escaping scary characters in fixed strings, building up one big regex. 939*5ffd940aSRaphael Isemann while (!PatternStr.empty()) { 940*5ffd940aSRaphael Isemann // RegEx matches. 941*5ffd940aSRaphael Isemann if (PatternStr.startswith("{{")) { 942*5ffd940aSRaphael Isemann // This is the start of a regex match. Scan for the }}. 943*5ffd940aSRaphael Isemann size_t End = PatternStr.find("}}"); 944*5ffd940aSRaphael Isemann if (End == StringRef::npos) { 945*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), 946*5ffd940aSRaphael Isemann SourceMgr::DK_Error, 947*5ffd940aSRaphael Isemann "found start of regex string with no end '}}'"); 948*5ffd940aSRaphael Isemann return true; 949*5ffd940aSRaphael Isemann } 950*5ffd940aSRaphael Isemann 951*5ffd940aSRaphael Isemann // Enclose {{}} patterns in parens just like [[]] even though we're not 952*5ffd940aSRaphael Isemann // capturing the result for any purpose. This is required in case the 953*5ffd940aSRaphael Isemann // expression contains an alternation like: CHECK: abc{{x|z}}def. We 954*5ffd940aSRaphael Isemann // want this to turn into: "abc(x|z)def" not "abcx|zdef". 955*5ffd940aSRaphael Isemann RegExStr += '('; 956*5ffd940aSRaphael Isemann ++CurParen; 957*5ffd940aSRaphael Isemann 958*5ffd940aSRaphael Isemann if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM)) 959*5ffd940aSRaphael Isemann return true; 960*5ffd940aSRaphael Isemann RegExStr += ')'; 961*5ffd940aSRaphael Isemann 962*5ffd940aSRaphael Isemann PatternStr = PatternStr.substr(End + 2); 963*5ffd940aSRaphael Isemann continue; 964*5ffd940aSRaphael Isemann } 965*5ffd940aSRaphael Isemann 966*5ffd940aSRaphael Isemann // String and numeric substitution blocks. Pattern substitution blocks come 967*5ffd940aSRaphael Isemann // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some 968*5ffd940aSRaphael Isemann // other regex) and assigns it to the string variable 'foo'. The latter 969*5ffd940aSRaphael Isemann // substitutes foo's value. Numeric substitution blocks recognize the same 970*5ffd940aSRaphael Isemann // form as string ones, but start with a '#' sign after the double 971*5ffd940aSRaphael Isemann // brackets. They also accept a combined form which sets a numeric variable 972*5ffd940aSRaphael Isemann // to the evaluation of an expression. Both string and numeric variable 973*5ffd940aSRaphael Isemann // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be 974*5ffd940aSRaphael Isemann // valid, as this helps catch some common errors. 975*5ffd940aSRaphael Isemann if (PatternStr.startswith("[[")) { 976*5ffd940aSRaphael Isemann StringRef UnparsedPatternStr = PatternStr.substr(2); 977*5ffd940aSRaphael Isemann // Find the closing bracket pair ending the match. End is going to be an 978*5ffd940aSRaphael Isemann // offset relative to the beginning of the match string. 979*5ffd940aSRaphael Isemann size_t End = FindRegexVarEnd(UnparsedPatternStr, SM); 980*5ffd940aSRaphael Isemann StringRef MatchStr = UnparsedPatternStr.substr(0, End); 981*5ffd940aSRaphael Isemann bool IsNumBlock = MatchStr.consume_front("#"); 982*5ffd940aSRaphael Isemann 983*5ffd940aSRaphael Isemann if (End == StringRef::npos) { 984*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), 985*5ffd940aSRaphael Isemann SourceMgr::DK_Error, 986*5ffd940aSRaphael Isemann "Invalid substitution block, no ]] found"); 987*5ffd940aSRaphael Isemann return true; 988*5ffd940aSRaphael Isemann } 989*5ffd940aSRaphael Isemann // Strip the substitution block we are parsing. End points to the start 990*5ffd940aSRaphael Isemann // of the "]]" closing the expression so account for it in computing the 991*5ffd940aSRaphael Isemann // index of the first unparsed character. 992*5ffd940aSRaphael Isemann PatternStr = UnparsedPatternStr.substr(End + 2); 993*5ffd940aSRaphael Isemann 994*5ffd940aSRaphael Isemann bool IsDefinition = false; 995*5ffd940aSRaphael Isemann bool SubstNeeded = false; 996*5ffd940aSRaphael Isemann // Whether the substitution block is a legacy use of @LINE with string 997*5ffd940aSRaphael Isemann // substitution block syntax. 998*5ffd940aSRaphael Isemann bool IsLegacyLineExpr = false; 999*5ffd940aSRaphael Isemann StringRef DefName; 1000*5ffd940aSRaphael Isemann StringRef SubstStr; 1001*5ffd940aSRaphael Isemann std::string MatchRegexp; 1002*5ffd940aSRaphael Isemann size_t SubstInsertIdx = RegExStr.size(); 1003*5ffd940aSRaphael Isemann 1004*5ffd940aSRaphael Isemann // Parse string variable or legacy @LINE expression. 1005*5ffd940aSRaphael Isemann if (!IsNumBlock) { 1006*5ffd940aSRaphael Isemann size_t VarEndIdx = MatchStr.find(":"); 1007*5ffd940aSRaphael Isemann size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t"); 1008*5ffd940aSRaphael Isemann if (SpacePos != StringRef::npos) { 1009*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos), 1010*5ffd940aSRaphael Isemann SourceMgr::DK_Error, "unexpected whitespace"); 1011*5ffd940aSRaphael Isemann return true; 1012*5ffd940aSRaphael Isemann } 1013*5ffd940aSRaphael Isemann 1014*5ffd940aSRaphael Isemann // Get the name (e.g. "foo") and verify it is well formed. 1015*5ffd940aSRaphael Isemann StringRef OrigMatchStr = MatchStr; 1016*5ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> ParseVarResult = 1017*5ffd940aSRaphael Isemann parseVariable(MatchStr, SM); 1018*5ffd940aSRaphael Isemann if (!ParseVarResult) { 1019*5ffd940aSRaphael Isemann logAllUnhandledErrors(ParseVarResult.takeError(), errs()); 1020*5ffd940aSRaphael Isemann return true; 1021*5ffd940aSRaphael Isemann } 1022*5ffd940aSRaphael Isemann StringRef Name = ParseVarResult->Name; 1023*5ffd940aSRaphael Isemann bool IsPseudo = ParseVarResult->IsPseudo; 1024*5ffd940aSRaphael Isemann 1025*5ffd940aSRaphael Isemann IsDefinition = (VarEndIdx != StringRef::npos); 1026*5ffd940aSRaphael Isemann SubstNeeded = !IsDefinition; 1027*5ffd940aSRaphael Isemann if (IsDefinition) { 1028*5ffd940aSRaphael Isemann if ((IsPseudo || !MatchStr.consume_front(":"))) { 1029*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Name.data()), 1030*5ffd940aSRaphael Isemann SourceMgr::DK_Error, 1031*5ffd940aSRaphael Isemann "invalid name in string variable definition"); 1032*5ffd940aSRaphael Isemann return true; 1033*5ffd940aSRaphael Isemann } 1034*5ffd940aSRaphael Isemann 1035*5ffd940aSRaphael Isemann // Detect collisions between string and numeric variables when the 1036*5ffd940aSRaphael Isemann // former is created later than the latter. 1037*5ffd940aSRaphael Isemann if (Context->GlobalNumericVariableTable.find(Name) != 1038*5ffd940aSRaphael Isemann Context->GlobalNumericVariableTable.end()) { 1039*5ffd940aSRaphael Isemann SM.PrintMessage( 1040*5ffd940aSRaphael Isemann SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, 1041*5ffd940aSRaphael Isemann "numeric variable with name '" + Name + "' already exists"); 1042*5ffd940aSRaphael Isemann return true; 1043*5ffd940aSRaphael Isemann } 1044*5ffd940aSRaphael Isemann DefName = Name; 1045*5ffd940aSRaphael Isemann MatchRegexp = MatchStr.str(); 1046*5ffd940aSRaphael Isemann } else { 1047*5ffd940aSRaphael Isemann if (IsPseudo) { 1048*5ffd940aSRaphael Isemann MatchStr = OrigMatchStr; 1049*5ffd940aSRaphael Isemann IsLegacyLineExpr = IsNumBlock = true; 1050*5ffd940aSRaphael Isemann } else 1051*5ffd940aSRaphael Isemann SubstStr = Name; 1052*5ffd940aSRaphael Isemann } 1053*5ffd940aSRaphael Isemann } 1054*5ffd940aSRaphael Isemann 1055*5ffd940aSRaphael Isemann // Parse numeric substitution block. 1056*5ffd940aSRaphael Isemann std::unique_ptr<Expression> ExpressionPointer; 1057*5ffd940aSRaphael Isemann Optional<NumericVariable *> DefinedNumericVariable; 1058*5ffd940aSRaphael Isemann if (IsNumBlock) { 1059*5ffd940aSRaphael Isemann Expected<std::unique_ptr<Expression>> ParseResult = 1060*5ffd940aSRaphael Isemann parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, 1061*5ffd940aSRaphael Isemann IsLegacyLineExpr, LineNumber, Context, 1062*5ffd940aSRaphael Isemann SM); 1063*5ffd940aSRaphael Isemann if (!ParseResult) { 1064*5ffd940aSRaphael Isemann logAllUnhandledErrors(ParseResult.takeError(), errs()); 1065*5ffd940aSRaphael Isemann return true; 1066*5ffd940aSRaphael Isemann } 1067*5ffd940aSRaphael Isemann ExpressionPointer = std::move(*ParseResult); 1068*5ffd940aSRaphael Isemann SubstNeeded = ExpressionPointer->getAST() != nullptr; 1069*5ffd940aSRaphael Isemann if (DefinedNumericVariable) { 1070*5ffd940aSRaphael Isemann IsDefinition = true; 1071*5ffd940aSRaphael Isemann DefName = (*DefinedNumericVariable)->getName(); 1072*5ffd940aSRaphael Isemann } 1073*5ffd940aSRaphael Isemann if (SubstNeeded) 1074*5ffd940aSRaphael Isemann SubstStr = MatchStr; 1075*5ffd940aSRaphael Isemann else { 1076*5ffd940aSRaphael Isemann ExpressionFormat Format = ExpressionPointer->getFormat(); 1077*5ffd940aSRaphael Isemann MatchRegexp = cantFail(Format.getWildcardRegex()); 1078*5ffd940aSRaphael Isemann } 1079*5ffd940aSRaphael Isemann } 1080*5ffd940aSRaphael Isemann 1081*5ffd940aSRaphael Isemann // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]]. 1082*5ffd940aSRaphael Isemann if (IsDefinition) { 1083*5ffd940aSRaphael Isemann RegExStr += '('; 1084*5ffd940aSRaphael Isemann ++SubstInsertIdx; 1085*5ffd940aSRaphael Isemann 1086*5ffd940aSRaphael Isemann if (IsNumBlock) { 1087*5ffd940aSRaphael Isemann NumericVariableMatch NumericVariableDefinition = { 1088*5ffd940aSRaphael Isemann *DefinedNumericVariable, CurParen}; 1089*5ffd940aSRaphael Isemann NumericVariableDefs[DefName] = NumericVariableDefinition; 1090*5ffd940aSRaphael Isemann // This store is done here rather than in match() to allow 1091*5ffd940aSRaphael Isemann // parseNumericVariableUse() to get the pointer to the class instance 1092*5ffd940aSRaphael Isemann // of the right variable definition corresponding to a given numeric 1093*5ffd940aSRaphael Isemann // variable use. 1094*5ffd940aSRaphael Isemann Context->GlobalNumericVariableTable[DefName] = 1095*5ffd940aSRaphael Isemann *DefinedNumericVariable; 1096*5ffd940aSRaphael Isemann } else { 1097*5ffd940aSRaphael Isemann VariableDefs[DefName] = CurParen; 1098*5ffd940aSRaphael Isemann // Mark string variable as defined to detect collisions between 1099*5ffd940aSRaphael Isemann // string and numeric variables in parseNumericVariableUse() and 1100*5ffd940aSRaphael Isemann // defineCmdlineVariables() when the latter is created later than the 1101*5ffd940aSRaphael Isemann // former. We cannot reuse GlobalVariableTable for this by populating 1102*5ffd940aSRaphael Isemann // it with an empty string since we would then lose the ability to 1103*5ffd940aSRaphael Isemann // detect the use of an undefined variable in match(). 1104*5ffd940aSRaphael Isemann Context->DefinedVariableTable[DefName] = true; 1105*5ffd940aSRaphael Isemann } 1106*5ffd940aSRaphael Isemann 1107*5ffd940aSRaphael Isemann ++CurParen; 1108*5ffd940aSRaphael Isemann } 1109*5ffd940aSRaphael Isemann 1110*5ffd940aSRaphael Isemann if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM)) 1111*5ffd940aSRaphael Isemann return true; 1112*5ffd940aSRaphael Isemann 1113*5ffd940aSRaphael Isemann if (IsDefinition) 1114*5ffd940aSRaphael Isemann RegExStr += ')'; 1115*5ffd940aSRaphael Isemann 1116*5ffd940aSRaphael Isemann // Handle substitutions: [[foo]] and [[#<foo expr>]]. 1117*5ffd940aSRaphael Isemann if (SubstNeeded) { 1118*5ffd940aSRaphael Isemann // Handle substitution of string variables that were defined earlier on 1119*5ffd940aSRaphael Isemann // the same line by emitting a backreference. Expressions do not 1120*5ffd940aSRaphael Isemann // support substituting a numeric variable defined on the same line. 1121*5ffd940aSRaphael Isemann if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) { 1122*5ffd940aSRaphael Isemann unsigned CaptureParenGroup = VariableDefs[SubstStr]; 1123*5ffd940aSRaphael Isemann if (CaptureParenGroup < 1 || CaptureParenGroup > 9) { 1124*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()), 1125*5ffd940aSRaphael Isemann SourceMgr::DK_Error, 1126*5ffd940aSRaphael Isemann "Can't back-reference more than 9 variables"); 1127*5ffd940aSRaphael Isemann return true; 1128*5ffd940aSRaphael Isemann } 1129*5ffd940aSRaphael Isemann AddBackrefToRegEx(CaptureParenGroup); 1130*5ffd940aSRaphael Isemann } else { 1131*5ffd940aSRaphael Isemann // Handle substitution of string variables ([[<var>]]) defined in 1132*5ffd940aSRaphael Isemann // previous CHECK patterns, and substitution of expressions. 1133*5ffd940aSRaphael Isemann Substitution *Substitution = 1134*5ffd940aSRaphael Isemann IsNumBlock 1135*5ffd940aSRaphael Isemann ? Context->makeNumericSubstitution( 1136*5ffd940aSRaphael Isemann SubstStr, std::move(ExpressionPointer), SubstInsertIdx) 1137*5ffd940aSRaphael Isemann : Context->makeStringSubstitution(SubstStr, SubstInsertIdx); 1138*5ffd940aSRaphael Isemann Substitutions.push_back(Substitution); 1139*5ffd940aSRaphael Isemann } 1140*5ffd940aSRaphael Isemann } 1141*5ffd940aSRaphael Isemann } 1142*5ffd940aSRaphael Isemann 1143*5ffd940aSRaphael Isemann // Handle fixed string matches. 1144*5ffd940aSRaphael Isemann // Find the end, which is the start of the next regex. 1145*5ffd940aSRaphael Isemann size_t FixedMatchEnd = PatternStr.find("{{"); 1146*5ffd940aSRaphael Isemann FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[[")); 1147*5ffd940aSRaphael Isemann RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd)); 1148*5ffd940aSRaphael Isemann PatternStr = PatternStr.substr(FixedMatchEnd); 1149*5ffd940aSRaphael Isemann } 1150*5ffd940aSRaphael Isemann 1151*5ffd940aSRaphael Isemann if (MatchFullLinesHere) { 1152*5ffd940aSRaphael Isemann if (!Req.NoCanonicalizeWhiteSpace) 1153*5ffd940aSRaphael Isemann RegExStr += " *"; 1154*5ffd940aSRaphael Isemann RegExStr += '$'; 1155*5ffd940aSRaphael Isemann } 1156*5ffd940aSRaphael Isemann 1157*5ffd940aSRaphael Isemann return false; 1158*5ffd940aSRaphael Isemann } 1159*5ffd940aSRaphael Isemann 1160*5ffd940aSRaphael Isemann bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { 1161*5ffd940aSRaphael Isemann Regex R(RS); 1162*5ffd940aSRaphael Isemann std::string Error; 1163*5ffd940aSRaphael Isemann if (!R.isValid(Error)) { 1164*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error, 1165*5ffd940aSRaphael Isemann "invalid regex: " + Error); 1166*5ffd940aSRaphael Isemann return true; 1167*5ffd940aSRaphael Isemann } 1168*5ffd940aSRaphael Isemann 1169*5ffd940aSRaphael Isemann RegExStr += RS.str(); 1170*5ffd940aSRaphael Isemann CurParen += R.getNumMatches(); 1171*5ffd940aSRaphael Isemann return false; 1172*5ffd940aSRaphael Isemann } 1173*5ffd940aSRaphael Isemann 1174*5ffd940aSRaphael Isemann void Pattern::AddBackrefToRegEx(unsigned BackrefNum) { 1175*5ffd940aSRaphael Isemann assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number"); 1176*5ffd940aSRaphael Isemann std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum); 1177*5ffd940aSRaphael Isemann RegExStr += Backref; 1178*5ffd940aSRaphael Isemann } 1179*5ffd940aSRaphael Isemann 1180*5ffd940aSRaphael Isemann Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, 1181*5ffd940aSRaphael Isemann const SourceMgr &SM) const { 1182*5ffd940aSRaphael Isemann // If this is the EOF pattern, match it immediately. 1183*5ffd940aSRaphael Isemann if (CheckTy == Check::CheckEOF) { 1184*5ffd940aSRaphael Isemann MatchLen = 0; 1185*5ffd940aSRaphael Isemann return Buffer.size(); 1186*5ffd940aSRaphael Isemann } 1187*5ffd940aSRaphael Isemann 1188*5ffd940aSRaphael Isemann // If this is a fixed string pattern, just match it now. 1189*5ffd940aSRaphael Isemann if (!FixedStr.empty()) { 1190*5ffd940aSRaphael Isemann MatchLen = FixedStr.size(); 1191*5ffd940aSRaphael Isemann size_t Pos = 1192*5ffd940aSRaphael Isemann IgnoreCase ? Buffer.find_lower(FixedStr) : Buffer.find(FixedStr); 1193*5ffd940aSRaphael Isemann if (Pos == StringRef::npos) 1194*5ffd940aSRaphael Isemann return make_error<NotFoundError>(); 1195*5ffd940aSRaphael Isemann return Pos; 1196*5ffd940aSRaphael Isemann } 1197*5ffd940aSRaphael Isemann 1198*5ffd940aSRaphael Isemann // Regex match. 1199*5ffd940aSRaphael Isemann 1200*5ffd940aSRaphael Isemann // If there are substitutions, we need to create a temporary string with the 1201*5ffd940aSRaphael Isemann // actual value. 1202*5ffd940aSRaphael Isemann StringRef RegExToMatch = RegExStr; 1203*5ffd940aSRaphael Isemann std::string TmpStr; 1204*5ffd940aSRaphael Isemann if (!Substitutions.empty()) { 1205*5ffd940aSRaphael Isemann TmpStr = RegExStr; 1206*5ffd940aSRaphael Isemann if (LineNumber) 1207*5ffd940aSRaphael Isemann Context->LineVariable->setValue(ExpressionValue(*LineNumber)); 1208*5ffd940aSRaphael Isemann 1209*5ffd940aSRaphael Isemann size_t InsertOffset = 0; 1210*5ffd940aSRaphael Isemann // Substitute all string variables and expressions whose values are only 1211*5ffd940aSRaphael Isemann // now known. Use of string variables defined on the same line are handled 1212*5ffd940aSRaphael Isemann // by back-references. 1213*5ffd940aSRaphael Isemann for (const auto &Substitution : Substitutions) { 1214*5ffd940aSRaphael Isemann // Substitute and check for failure (e.g. use of undefined variable). 1215*5ffd940aSRaphael Isemann Expected<std::string> Value = Substitution->getResult(); 1216*5ffd940aSRaphael Isemann if (!Value) { 1217*5ffd940aSRaphael Isemann // Convert to an ErrorDiagnostic to get location information. This is 1218*5ffd940aSRaphael Isemann // done here rather than PrintNoMatch since now we know which 1219*5ffd940aSRaphael Isemann // substitution block caused the overflow. 1220*5ffd940aSRaphael Isemann Error Err = 1221*5ffd940aSRaphael Isemann handleErrors(Value.takeError(), [&](const OverflowError &E) { 1222*5ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Substitution->getFromString(), 1223*5ffd940aSRaphael Isemann "unable to substitute variable or " 1224*5ffd940aSRaphael Isemann "numeric expression: overflow error"); 1225*5ffd940aSRaphael Isemann }); 1226*5ffd940aSRaphael Isemann return std::move(Err); 1227*5ffd940aSRaphael Isemann } 1228*5ffd940aSRaphael Isemann 1229*5ffd940aSRaphael Isemann // Plop it into the regex at the adjusted offset. 1230*5ffd940aSRaphael Isemann TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, 1231*5ffd940aSRaphael Isemann Value->begin(), Value->end()); 1232*5ffd940aSRaphael Isemann InsertOffset += Value->size(); 1233*5ffd940aSRaphael Isemann } 1234*5ffd940aSRaphael Isemann 1235*5ffd940aSRaphael Isemann // Match the newly constructed regex. 1236*5ffd940aSRaphael Isemann RegExToMatch = TmpStr; 1237*5ffd940aSRaphael Isemann } 1238*5ffd940aSRaphael Isemann 1239*5ffd940aSRaphael Isemann SmallVector<StringRef, 4> MatchInfo; 1240*5ffd940aSRaphael Isemann unsigned int Flags = Regex::Newline; 1241*5ffd940aSRaphael Isemann if (IgnoreCase) 1242*5ffd940aSRaphael Isemann Flags |= Regex::IgnoreCase; 1243*5ffd940aSRaphael Isemann if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo)) 1244*5ffd940aSRaphael Isemann return make_error<NotFoundError>(); 1245*5ffd940aSRaphael Isemann 1246*5ffd940aSRaphael Isemann // Successful regex match. 1247*5ffd940aSRaphael Isemann assert(!MatchInfo.empty() && "Didn't get any match"); 1248*5ffd940aSRaphael Isemann StringRef FullMatch = MatchInfo[0]; 1249*5ffd940aSRaphael Isemann 1250*5ffd940aSRaphael Isemann // If this defines any string variables, remember their values. 1251*5ffd940aSRaphael Isemann for (const auto &VariableDef : VariableDefs) { 1252*5ffd940aSRaphael Isemann assert(VariableDef.second < MatchInfo.size() && "Internal paren error"); 1253*5ffd940aSRaphael Isemann Context->GlobalVariableTable[VariableDef.first] = 1254*5ffd940aSRaphael Isemann MatchInfo[VariableDef.second]; 1255*5ffd940aSRaphael Isemann } 1256*5ffd940aSRaphael Isemann 1257*5ffd940aSRaphael Isemann // If this defines any numeric variables, remember their values. 1258*5ffd940aSRaphael Isemann for (const auto &NumericVariableDef : NumericVariableDefs) { 1259*5ffd940aSRaphael Isemann const NumericVariableMatch &NumericVariableMatch = 1260*5ffd940aSRaphael Isemann NumericVariableDef.getValue(); 1261*5ffd940aSRaphael Isemann unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup; 1262*5ffd940aSRaphael Isemann assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); 1263*5ffd940aSRaphael Isemann NumericVariable *DefinedNumericVariable = 1264*5ffd940aSRaphael Isemann NumericVariableMatch.DefinedNumericVariable; 1265*5ffd940aSRaphael Isemann 1266*5ffd940aSRaphael Isemann StringRef MatchedValue = MatchInfo[CaptureParenGroup]; 1267*5ffd940aSRaphael Isemann ExpressionFormat Format = DefinedNumericVariable->getImplicitFormat(); 1268*5ffd940aSRaphael Isemann Expected<ExpressionValue> Value = 1269*5ffd940aSRaphael Isemann Format.valueFromStringRepr(MatchedValue, SM); 1270*5ffd940aSRaphael Isemann if (!Value) 1271*5ffd940aSRaphael Isemann return Value.takeError(); 1272*5ffd940aSRaphael Isemann DefinedNumericVariable->setValue(*Value, MatchedValue); 1273*5ffd940aSRaphael Isemann } 1274*5ffd940aSRaphael Isemann 1275*5ffd940aSRaphael Isemann // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after 1276*5ffd940aSRaphael Isemann // the required preceding newline, which is consumed by the pattern in the 1277*5ffd940aSRaphael Isemann // case of CHECK-EMPTY but not CHECK-NEXT. 1278*5ffd940aSRaphael Isemann size_t MatchStartSkip = CheckTy == Check::CheckEmpty; 1279*5ffd940aSRaphael Isemann MatchLen = FullMatch.size() - MatchStartSkip; 1280*5ffd940aSRaphael Isemann return FullMatch.data() - Buffer.data() + MatchStartSkip; 1281*5ffd940aSRaphael Isemann } 1282*5ffd940aSRaphael Isemann 1283*5ffd940aSRaphael Isemann unsigned Pattern::computeMatchDistance(StringRef Buffer) const { 1284*5ffd940aSRaphael Isemann // Just compute the number of matching characters. For regular expressions, we 1285*5ffd940aSRaphael Isemann // just compare against the regex itself and hope for the best. 1286*5ffd940aSRaphael Isemann // 1287*5ffd940aSRaphael Isemann // FIXME: One easy improvement here is have the regex lib generate a single 1288*5ffd940aSRaphael Isemann // example regular expression which matches, and use that as the example 1289*5ffd940aSRaphael Isemann // string. 1290*5ffd940aSRaphael Isemann StringRef ExampleString(FixedStr); 1291*5ffd940aSRaphael Isemann if (ExampleString.empty()) 1292*5ffd940aSRaphael Isemann ExampleString = RegExStr; 1293*5ffd940aSRaphael Isemann 1294*5ffd940aSRaphael Isemann // Only compare up to the first line in the buffer, or the string size. 1295*5ffd940aSRaphael Isemann StringRef BufferPrefix = Buffer.substr(0, ExampleString.size()); 1296*5ffd940aSRaphael Isemann BufferPrefix = BufferPrefix.split('\n').first; 1297*5ffd940aSRaphael Isemann return BufferPrefix.edit_distance(ExampleString); 1298*5ffd940aSRaphael Isemann } 1299*5ffd940aSRaphael Isemann 1300*5ffd940aSRaphael Isemann void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, 1301*5ffd940aSRaphael Isemann SMRange Range, 1302*5ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy, 1303*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 1304*5ffd940aSRaphael Isemann // Print what we know about substitutions. 1305*5ffd940aSRaphael Isemann if (!Substitutions.empty()) { 1306*5ffd940aSRaphael Isemann for (const auto &Substitution : Substitutions) { 1307*5ffd940aSRaphael Isemann SmallString<256> Msg; 1308*5ffd940aSRaphael Isemann raw_svector_ostream OS(Msg); 1309*5ffd940aSRaphael Isemann Expected<std::string> MatchedValue = Substitution->getResult(); 1310*5ffd940aSRaphael Isemann 1311*5ffd940aSRaphael Isemann // Substitution failed or is not known at match time, print the undefined 1312*5ffd940aSRaphael Isemann // variables it uses. 1313*5ffd940aSRaphael Isemann if (!MatchedValue) { 1314*5ffd940aSRaphael Isemann bool UndefSeen = false; 1315*5ffd940aSRaphael Isemann handleAllErrors( 1316*5ffd940aSRaphael Isemann MatchedValue.takeError(), [](const NotFoundError &E) {}, 1317*5ffd940aSRaphael Isemann // Handled in PrintNoMatch(). 1318*5ffd940aSRaphael Isemann [](const ErrorDiagnostic &E) {}, 1319*5ffd940aSRaphael Isemann // Handled in match(). 1320*5ffd940aSRaphael Isemann [](const OverflowError &E) {}, 1321*5ffd940aSRaphael Isemann [&](const UndefVarError &E) { 1322*5ffd940aSRaphael Isemann if (!UndefSeen) { 1323*5ffd940aSRaphael Isemann OS << "uses undefined variable(s):"; 1324*5ffd940aSRaphael Isemann UndefSeen = true; 1325*5ffd940aSRaphael Isemann } 1326*5ffd940aSRaphael Isemann OS << " "; 1327*5ffd940aSRaphael Isemann E.log(OS); 1328*5ffd940aSRaphael Isemann }); 1329*5ffd940aSRaphael Isemann } else { 1330*5ffd940aSRaphael Isemann // Substitution succeeded. Print substituted value. 1331*5ffd940aSRaphael Isemann OS << "with \""; 1332*5ffd940aSRaphael Isemann OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; 1333*5ffd940aSRaphael Isemann OS.write_escaped(*MatchedValue) << "\""; 1334*5ffd940aSRaphael Isemann } 1335*5ffd940aSRaphael Isemann 1336*5ffd940aSRaphael Isemann // We report only the start of the match/search range to suggest we are 1337*5ffd940aSRaphael Isemann // reporting the substitutions as set at the start of the match/search. 1338*5ffd940aSRaphael Isemann // Indicating a non-zero-length range might instead seem to imply that the 1339*5ffd940aSRaphael Isemann // substitution matches or was captured from exactly that range. 1340*5ffd940aSRaphael Isemann if (Diags) 1341*5ffd940aSRaphael Isemann Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, 1342*5ffd940aSRaphael Isemann SMRange(Range.Start, Range.Start), OS.str()); 1343*5ffd940aSRaphael Isemann else 1344*5ffd940aSRaphael Isemann SM.PrintMessage(Range.Start, SourceMgr::DK_Note, OS.str()); 1345*5ffd940aSRaphael Isemann } 1346*5ffd940aSRaphael Isemann } 1347*5ffd940aSRaphael Isemann } 1348*5ffd940aSRaphael Isemann 1349*5ffd940aSRaphael Isemann void Pattern::printVariableDefs(const SourceMgr &SM, 1350*5ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy, 1351*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 1352*5ffd940aSRaphael Isemann if (VariableDefs.empty() && NumericVariableDefs.empty()) 1353*5ffd940aSRaphael Isemann return; 1354*5ffd940aSRaphael Isemann // Build list of variable captures. 1355*5ffd940aSRaphael Isemann struct VarCapture { 1356*5ffd940aSRaphael Isemann StringRef Name; 1357*5ffd940aSRaphael Isemann SMRange Range; 1358*5ffd940aSRaphael Isemann }; 1359*5ffd940aSRaphael Isemann SmallVector<VarCapture, 2> VarCaptures; 1360*5ffd940aSRaphael Isemann for (const auto &VariableDef : VariableDefs) { 1361*5ffd940aSRaphael Isemann VarCapture VC; 1362*5ffd940aSRaphael Isemann VC.Name = VariableDef.first; 1363*5ffd940aSRaphael Isemann StringRef Value = Context->GlobalVariableTable[VC.Name]; 1364*5ffd940aSRaphael Isemann SMLoc Start = SMLoc::getFromPointer(Value.data()); 1365*5ffd940aSRaphael Isemann SMLoc End = SMLoc::getFromPointer(Value.data() + Value.size()); 1366*5ffd940aSRaphael Isemann VC.Range = SMRange(Start, End); 1367*5ffd940aSRaphael Isemann VarCaptures.push_back(VC); 1368*5ffd940aSRaphael Isemann } 1369*5ffd940aSRaphael Isemann for (const auto &VariableDef : NumericVariableDefs) { 1370*5ffd940aSRaphael Isemann VarCapture VC; 1371*5ffd940aSRaphael Isemann VC.Name = VariableDef.getKey(); 1372*5ffd940aSRaphael Isemann StringRef StrValue = VariableDef.getValue() 1373*5ffd940aSRaphael Isemann .DefinedNumericVariable->getStringValue() 1374*5ffd940aSRaphael Isemann .getValue(); 1375*5ffd940aSRaphael Isemann SMLoc Start = SMLoc::getFromPointer(StrValue.data()); 1376*5ffd940aSRaphael Isemann SMLoc End = SMLoc::getFromPointer(StrValue.data() + StrValue.size()); 1377*5ffd940aSRaphael Isemann VC.Range = SMRange(Start, End); 1378*5ffd940aSRaphael Isemann VarCaptures.push_back(VC); 1379*5ffd940aSRaphael Isemann } 1380*5ffd940aSRaphael Isemann // Sort variable captures by the order in which they matched the input. 1381*5ffd940aSRaphael Isemann // Ranges shouldn't be overlapping, so we can just compare the start. 1382*5ffd940aSRaphael Isemann std::sort(VarCaptures.begin(), VarCaptures.end(), 1383*5ffd940aSRaphael Isemann [](const VarCapture &A, const VarCapture &B) { 1384*5ffd940aSRaphael Isemann assert(A.Range.Start != B.Range.Start && 1385*5ffd940aSRaphael Isemann "unexpected overlapping variable captures"); 1386*5ffd940aSRaphael Isemann return A.Range.Start.getPointer() < B.Range.Start.getPointer(); 1387*5ffd940aSRaphael Isemann }); 1388*5ffd940aSRaphael Isemann // Create notes for the sorted captures. 1389*5ffd940aSRaphael Isemann for (const VarCapture &VC : VarCaptures) { 1390*5ffd940aSRaphael Isemann SmallString<256> Msg; 1391*5ffd940aSRaphael Isemann raw_svector_ostream OS(Msg); 1392*5ffd940aSRaphael Isemann OS << "captured var \"" << VC.Name << "\""; 1393*5ffd940aSRaphael Isemann if (Diags) 1394*5ffd940aSRaphael Isemann Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, VC.Range, OS.str()); 1395*5ffd940aSRaphael Isemann else 1396*5ffd940aSRaphael Isemann SM.PrintMessage(VC.Range.Start, SourceMgr::DK_Note, OS.str(), VC.Range); 1397*5ffd940aSRaphael Isemann } 1398*5ffd940aSRaphael Isemann } 1399*5ffd940aSRaphael Isemann 1400*5ffd940aSRaphael Isemann static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy, 1401*5ffd940aSRaphael Isemann const SourceMgr &SM, SMLoc Loc, 1402*5ffd940aSRaphael Isemann Check::FileCheckType CheckTy, 1403*5ffd940aSRaphael Isemann StringRef Buffer, size_t Pos, size_t Len, 1404*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags, 1405*5ffd940aSRaphael Isemann bool AdjustPrevDiags = false) { 1406*5ffd940aSRaphael Isemann SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos); 1407*5ffd940aSRaphael Isemann SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len); 1408*5ffd940aSRaphael Isemann SMRange Range(Start, End); 1409*5ffd940aSRaphael Isemann if (Diags) { 1410*5ffd940aSRaphael Isemann if (AdjustPrevDiags) { 1411*5ffd940aSRaphael Isemann SMLoc CheckLoc = Diags->rbegin()->CheckLoc; 1412*5ffd940aSRaphael Isemann for (auto I = Diags->rbegin(), E = Diags->rend(); 1413*5ffd940aSRaphael Isemann I != E && I->CheckLoc == CheckLoc; ++I) 1414*5ffd940aSRaphael Isemann I->MatchTy = MatchTy; 1415*5ffd940aSRaphael Isemann } else 1416*5ffd940aSRaphael Isemann Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range); 1417*5ffd940aSRaphael Isemann } 1418*5ffd940aSRaphael Isemann return Range; 1419*5ffd940aSRaphael Isemann } 1420*5ffd940aSRaphael Isemann 1421*5ffd940aSRaphael Isemann void Pattern::printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, 1422*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 1423*5ffd940aSRaphael Isemann // Attempt to find the closest/best fuzzy match. Usually an error happens 1424*5ffd940aSRaphael Isemann // because some string in the output didn't exactly match. In these cases, we 1425*5ffd940aSRaphael Isemann // would like to show the user a best guess at what "should have" matched, to 1426*5ffd940aSRaphael Isemann // save them having to actually check the input manually. 1427*5ffd940aSRaphael Isemann size_t NumLinesForward = 0; 1428*5ffd940aSRaphael Isemann size_t Best = StringRef::npos; 1429*5ffd940aSRaphael Isemann double BestQuality = 0; 1430*5ffd940aSRaphael Isemann 1431*5ffd940aSRaphael Isemann // Use an arbitrary 4k limit on how far we will search. 1432*5ffd940aSRaphael Isemann for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) { 1433*5ffd940aSRaphael Isemann if (Buffer[i] == '\n') 1434*5ffd940aSRaphael Isemann ++NumLinesForward; 1435*5ffd940aSRaphael Isemann 1436*5ffd940aSRaphael Isemann // Patterns have leading whitespace stripped, so skip whitespace when 1437*5ffd940aSRaphael Isemann // looking for something which looks like a pattern. 1438*5ffd940aSRaphael Isemann if (Buffer[i] == ' ' || Buffer[i] == '\t') 1439*5ffd940aSRaphael Isemann continue; 1440*5ffd940aSRaphael Isemann 1441*5ffd940aSRaphael Isemann // Compute the "quality" of this match as an arbitrary combination of the 1442*5ffd940aSRaphael Isemann // match distance and the number of lines skipped to get to this match. 1443*5ffd940aSRaphael Isemann unsigned Distance = computeMatchDistance(Buffer.substr(i)); 1444*5ffd940aSRaphael Isemann double Quality = Distance + (NumLinesForward / 100.); 1445*5ffd940aSRaphael Isemann 1446*5ffd940aSRaphael Isemann if (Quality < BestQuality || Best == StringRef::npos) { 1447*5ffd940aSRaphael Isemann Best = i; 1448*5ffd940aSRaphael Isemann BestQuality = Quality; 1449*5ffd940aSRaphael Isemann } 1450*5ffd940aSRaphael Isemann } 1451*5ffd940aSRaphael Isemann 1452*5ffd940aSRaphael Isemann // Print the "possible intended match here" line if we found something 1453*5ffd940aSRaphael Isemann // reasonable and not equal to what we showed in the "scanning from here" 1454*5ffd940aSRaphael Isemann // line. 1455*5ffd940aSRaphael Isemann if (Best && Best != StringRef::npos && BestQuality < 50) { 1456*5ffd940aSRaphael Isemann SMRange MatchRange = 1457*5ffd940aSRaphael Isemann ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(), 1458*5ffd940aSRaphael Isemann getCheckTy(), Buffer, Best, 0, Diags); 1459*5ffd940aSRaphael Isemann SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, 1460*5ffd940aSRaphael Isemann "possible intended match here"); 1461*5ffd940aSRaphael Isemann 1462*5ffd940aSRaphael Isemann // FIXME: If we wanted to be really friendly we would show why the match 1463*5ffd940aSRaphael Isemann // failed, as it can be hard to spot simple one character differences. 1464*5ffd940aSRaphael Isemann } 1465*5ffd940aSRaphael Isemann } 1466*5ffd940aSRaphael Isemann 1467*5ffd940aSRaphael Isemann Expected<StringRef> 1468*5ffd940aSRaphael Isemann FileCheckPatternContext::getPatternVarValue(StringRef VarName) { 1469*5ffd940aSRaphael Isemann auto VarIter = GlobalVariableTable.find(VarName); 1470*5ffd940aSRaphael Isemann if (VarIter == GlobalVariableTable.end()) 1471*5ffd940aSRaphael Isemann return make_error<UndefVarError>(VarName); 1472*5ffd940aSRaphael Isemann 1473*5ffd940aSRaphael Isemann return VarIter->second; 1474*5ffd940aSRaphael Isemann } 1475*5ffd940aSRaphael Isemann 1476*5ffd940aSRaphael Isemann template <class... Types> 1477*5ffd940aSRaphael Isemann NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) { 1478*5ffd940aSRaphael Isemann NumericVariables.push_back(std::make_unique<NumericVariable>(args...)); 1479*5ffd940aSRaphael Isemann return NumericVariables.back().get(); 1480*5ffd940aSRaphael Isemann } 1481*5ffd940aSRaphael Isemann 1482*5ffd940aSRaphael Isemann Substitution * 1483*5ffd940aSRaphael Isemann FileCheckPatternContext::makeStringSubstitution(StringRef VarName, 1484*5ffd940aSRaphael Isemann size_t InsertIdx) { 1485*5ffd940aSRaphael Isemann Substitutions.push_back( 1486*5ffd940aSRaphael Isemann std::make_unique<StringSubstitution>(this, VarName, InsertIdx)); 1487*5ffd940aSRaphael Isemann return Substitutions.back().get(); 1488*5ffd940aSRaphael Isemann } 1489*5ffd940aSRaphael Isemann 1490*5ffd940aSRaphael Isemann Substitution *FileCheckPatternContext::makeNumericSubstitution( 1491*5ffd940aSRaphael Isemann StringRef ExpressionStr, std::unique_ptr<Expression> Expression, 1492*5ffd940aSRaphael Isemann size_t InsertIdx) { 1493*5ffd940aSRaphael Isemann Substitutions.push_back(std::make_unique<NumericSubstitution>( 1494*5ffd940aSRaphael Isemann this, ExpressionStr, std::move(Expression), InsertIdx)); 1495*5ffd940aSRaphael Isemann return Substitutions.back().get(); 1496*5ffd940aSRaphael Isemann } 1497*5ffd940aSRaphael Isemann 1498*5ffd940aSRaphael Isemann size_t Pattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { 1499*5ffd940aSRaphael Isemann // Offset keeps track of the current offset within the input Str 1500*5ffd940aSRaphael Isemann size_t Offset = 0; 1501*5ffd940aSRaphael Isemann // [...] Nesting depth 1502*5ffd940aSRaphael Isemann size_t BracketDepth = 0; 1503*5ffd940aSRaphael Isemann 1504*5ffd940aSRaphael Isemann while (!Str.empty()) { 1505*5ffd940aSRaphael Isemann if (Str.startswith("]]") && BracketDepth == 0) 1506*5ffd940aSRaphael Isemann return Offset; 1507*5ffd940aSRaphael Isemann if (Str[0] == '\\') { 1508*5ffd940aSRaphael Isemann // Backslash escapes the next char within regexes, so skip them both. 1509*5ffd940aSRaphael Isemann Str = Str.substr(2); 1510*5ffd940aSRaphael Isemann Offset += 2; 1511*5ffd940aSRaphael Isemann } else { 1512*5ffd940aSRaphael Isemann switch (Str[0]) { 1513*5ffd940aSRaphael Isemann default: 1514*5ffd940aSRaphael Isemann break; 1515*5ffd940aSRaphael Isemann case '[': 1516*5ffd940aSRaphael Isemann BracketDepth++; 1517*5ffd940aSRaphael Isemann break; 1518*5ffd940aSRaphael Isemann case ']': 1519*5ffd940aSRaphael Isemann if (BracketDepth == 0) { 1520*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Str.data()), 1521*5ffd940aSRaphael Isemann SourceMgr::DK_Error, 1522*5ffd940aSRaphael Isemann "missing closing \"]\" for regex variable"); 1523*5ffd940aSRaphael Isemann exit(1); 1524*5ffd940aSRaphael Isemann } 1525*5ffd940aSRaphael Isemann BracketDepth--; 1526*5ffd940aSRaphael Isemann break; 1527*5ffd940aSRaphael Isemann } 1528*5ffd940aSRaphael Isemann Str = Str.substr(1); 1529*5ffd940aSRaphael Isemann Offset++; 1530*5ffd940aSRaphael Isemann } 1531*5ffd940aSRaphael Isemann } 1532*5ffd940aSRaphael Isemann 1533*5ffd940aSRaphael Isemann return StringRef::npos; 1534*5ffd940aSRaphael Isemann } 1535*5ffd940aSRaphael Isemann 1536*5ffd940aSRaphael Isemann StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB, 1537*5ffd940aSRaphael Isemann SmallVectorImpl<char> &OutputBuffer) { 1538*5ffd940aSRaphael Isemann OutputBuffer.reserve(MB.getBufferSize()); 1539*5ffd940aSRaphael Isemann 1540*5ffd940aSRaphael Isemann for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd(); 1541*5ffd940aSRaphael Isemann Ptr != End; ++Ptr) { 1542*5ffd940aSRaphael Isemann // Eliminate trailing dosish \r. 1543*5ffd940aSRaphael Isemann if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') { 1544*5ffd940aSRaphael Isemann continue; 1545*5ffd940aSRaphael Isemann } 1546*5ffd940aSRaphael Isemann 1547*5ffd940aSRaphael Isemann // If current char is not a horizontal whitespace or if horizontal 1548*5ffd940aSRaphael Isemann // whitespace canonicalization is disabled, dump it to output as is. 1549*5ffd940aSRaphael Isemann if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) { 1550*5ffd940aSRaphael Isemann OutputBuffer.push_back(*Ptr); 1551*5ffd940aSRaphael Isemann continue; 1552*5ffd940aSRaphael Isemann } 1553*5ffd940aSRaphael Isemann 1554*5ffd940aSRaphael Isemann // Otherwise, add one space and advance over neighboring space. 1555*5ffd940aSRaphael Isemann OutputBuffer.push_back(' '); 1556*5ffd940aSRaphael Isemann while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t')) 1557*5ffd940aSRaphael Isemann ++Ptr; 1558*5ffd940aSRaphael Isemann } 1559*5ffd940aSRaphael Isemann 1560*5ffd940aSRaphael Isemann // Add a null byte and then return all but that byte. 1561*5ffd940aSRaphael Isemann OutputBuffer.push_back('\0'); 1562*5ffd940aSRaphael Isemann return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1); 1563*5ffd940aSRaphael Isemann } 1564*5ffd940aSRaphael Isemann 1565*5ffd940aSRaphael Isemann FileCheckDiag::FileCheckDiag(const SourceMgr &SM, 1566*5ffd940aSRaphael Isemann const Check::FileCheckType &CheckTy, 1567*5ffd940aSRaphael Isemann SMLoc CheckLoc, MatchType MatchTy, 1568*5ffd940aSRaphael Isemann SMRange InputRange, StringRef Note) 1569*5ffd940aSRaphael Isemann : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy), Note(Note) { 1570*5ffd940aSRaphael Isemann auto Start = SM.getLineAndColumn(InputRange.Start); 1571*5ffd940aSRaphael Isemann auto End = SM.getLineAndColumn(InputRange.End); 1572*5ffd940aSRaphael Isemann InputStartLine = Start.first; 1573*5ffd940aSRaphael Isemann InputStartCol = Start.second; 1574*5ffd940aSRaphael Isemann InputEndLine = End.first; 1575*5ffd940aSRaphael Isemann InputEndCol = End.second; 1576*5ffd940aSRaphael Isemann } 1577*5ffd940aSRaphael Isemann 1578*5ffd940aSRaphael Isemann static bool IsPartOfWord(char c) { 1579*5ffd940aSRaphael Isemann return (isAlnum(c) || c == '-' || c == '_'); 1580*5ffd940aSRaphael Isemann } 1581*5ffd940aSRaphael Isemann 1582*5ffd940aSRaphael Isemann Check::FileCheckType &Check::FileCheckType::setCount(int C) { 1583*5ffd940aSRaphael Isemann assert(Count > 0 && "zero and negative counts are not supported"); 1584*5ffd940aSRaphael Isemann assert((C == 1 || Kind == CheckPlain) && 1585*5ffd940aSRaphael Isemann "count supported only for plain CHECK directives"); 1586*5ffd940aSRaphael Isemann Count = C; 1587*5ffd940aSRaphael Isemann return *this; 1588*5ffd940aSRaphael Isemann } 1589*5ffd940aSRaphael Isemann 1590*5ffd940aSRaphael Isemann std::string Check::FileCheckType::getDescription(StringRef Prefix) const { 1591*5ffd940aSRaphael Isemann switch (Kind) { 1592*5ffd940aSRaphael Isemann case Check::CheckNone: 1593*5ffd940aSRaphael Isemann return "invalid"; 1594*5ffd940aSRaphael Isemann case Check::CheckPlain: 1595*5ffd940aSRaphael Isemann if (Count > 1) 1596*5ffd940aSRaphael Isemann return Prefix.str() + "-COUNT"; 1597*5ffd940aSRaphael Isemann return std::string(Prefix); 1598*5ffd940aSRaphael Isemann case Check::CheckNext: 1599*5ffd940aSRaphael Isemann return Prefix.str() + "-NEXT"; 1600*5ffd940aSRaphael Isemann case Check::CheckSame: 1601*5ffd940aSRaphael Isemann return Prefix.str() + "-SAME"; 1602*5ffd940aSRaphael Isemann case Check::CheckNot: 1603*5ffd940aSRaphael Isemann return Prefix.str() + "-NOT"; 1604*5ffd940aSRaphael Isemann case Check::CheckDAG: 1605*5ffd940aSRaphael Isemann return Prefix.str() + "-DAG"; 1606*5ffd940aSRaphael Isemann case Check::CheckLabel: 1607*5ffd940aSRaphael Isemann return Prefix.str() + "-LABEL"; 1608*5ffd940aSRaphael Isemann case Check::CheckEmpty: 1609*5ffd940aSRaphael Isemann return Prefix.str() + "-EMPTY"; 1610*5ffd940aSRaphael Isemann case Check::CheckComment: 1611*5ffd940aSRaphael Isemann return std::string(Prefix); 1612*5ffd940aSRaphael Isemann case Check::CheckEOF: 1613*5ffd940aSRaphael Isemann return "implicit EOF"; 1614*5ffd940aSRaphael Isemann case Check::CheckBadNot: 1615*5ffd940aSRaphael Isemann return "bad NOT"; 1616*5ffd940aSRaphael Isemann case Check::CheckBadCount: 1617*5ffd940aSRaphael Isemann return "bad COUNT"; 1618*5ffd940aSRaphael Isemann } 1619*5ffd940aSRaphael Isemann llvm_unreachable("unknown FileCheckType"); 1620*5ffd940aSRaphael Isemann } 1621*5ffd940aSRaphael Isemann 1622*5ffd940aSRaphael Isemann static std::pair<Check::FileCheckType, StringRef> 1623*5ffd940aSRaphael Isemann FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix) { 1624*5ffd940aSRaphael Isemann if (Buffer.size() <= Prefix.size()) 1625*5ffd940aSRaphael Isemann return {Check::CheckNone, StringRef()}; 1626*5ffd940aSRaphael Isemann 1627*5ffd940aSRaphael Isemann char NextChar = Buffer[Prefix.size()]; 1628*5ffd940aSRaphael Isemann 1629*5ffd940aSRaphael Isemann StringRef Rest = Buffer.drop_front(Prefix.size() + 1); 1630*5ffd940aSRaphael Isemann 1631*5ffd940aSRaphael Isemann // Check for comment. 1632*5ffd940aSRaphael Isemann if (llvm::is_contained(Req.CommentPrefixes, Prefix)) { 1633*5ffd940aSRaphael Isemann if (NextChar == ':') 1634*5ffd940aSRaphael Isemann return {Check::CheckComment, Rest}; 1635*5ffd940aSRaphael Isemann // Ignore a comment prefix if it has a suffix like "-NOT". 1636*5ffd940aSRaphael Isemann return {Check::CheckNone, StringRef()}; 1637*5ffd940aSRaphael Isemann } 1638*5ffd940aSRaphael Isemann 1639*5ffd940aSRaphael Isemann // Verify that the : is present after the prefix. 1640*5ffd940aSRaphael Isemann if (NextChar == ':') 1641*5ffd940aSRaphael Isemann return {Check::CheckPlain, Rest}; 1642*5ffd940aSRaphael Isemann 1643*5ffd940aSRaphael Isemann if (NextChar != '-') 1644*5ffd940aSRaphael Isemann return {Check::CheckNone, StringRef()}; 1645*5ffd940aSRaphael Isemann 1646*5ffd940aSRaphael Isemann if (Rest.consume_front("COUNT-")) { 1647*5ffd940aSRaphael Isemann int64_t Count; 1648*5ffd940aSRaphael Isemann if (Rest.consumeInteger(10, Count)) 1649*5ffd940aSRaphael Isemann // Error happened in parsing integer. 1650*5ffd940aSRaphael Isemann return {Check::CheckBadCount, Rest}; 1651*5ffd940aSRaphael Isemann if (Count <= 0 || Count > INT32_MAX) 1652*5ffd940aSRaphael Isemann return {Check::CheckBadCount, Rest}; 1653*5ffd940aSRaphael Isemann if (!Rest.consume_front(":")) 1654*5ffd940aSRaphael Isemann return {Check::CheckBadCount, Rest}; 1655*5ffd940aSRaphael Isemann return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest}; 1656*5ffd940aSRaphael Isemann } 1657*5ffd940aSRaphael Isemann 1658*5ffd940aSRaphael Isemann if (Rest.consume_front("NEXT:")) 1659*5ffd940aSRaphael Isemann return {Check::CheckNext, Rest}; 1660*5ffd940aSRaphael Isemann 1661*5ffd940aSRaphael Isemann if (Rest.consume_front("SAME:")) 1662*5ffd940aSRaphael Isemann return {Check::CheckSame, Rest}; 1663*5ffd940aSRaphael Isemann 1664*5ffd940aSRaphael Isemann if (Rest.consume_front("NOT:")) 1665*5ffd940aSRaphael Isemann return {Check::CheckNot, Rest}; 1666*5ffd940aSRaphael Isemann 1667*5ffd940aSRaphael Isemann if (Rest.consume_front("DAG:")) 1668*5ffd940aSRaphael Isemann return {Check::CheckDAG, Rest}; 1669*5ffd940aSRaphael Isemann 1670*5ffd940aSRaphael Isemann if (Rest.consume_front("LABEL:")) 1671*5ffd940aSRaphael Isemann return {Check::CheckLabel, Rest}; 1672*5ffd940aSRaphael Isemann 1673*5ffd940aSRaphael Isemann if (Rest.consume_front("EMPTY:")) 1674*5ffd940aSRaphael Isemann return {Check::CheckEmpty, Rest}; 1675*5ffd940aSRaphael Isemann 1676*5ffd940aSRaphael Isemann // You can't combine -NOT with another suffix. 1677*5ffd940aSRaphael Isemann if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || 1678*5ffd940aSRaphael Isemann Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") || 1679*5ffd940aSRaphael Isemann Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") || 1680*5ffd940aSRaphael Isemann Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:")) 1681*5ffd940aSRaphael Isemann return {Check::CheckBadNot, Rest}; 1682*5ffd940aSRaphael Isemann 1683*5ffd940aSRaphael Isemann return {Check::CheckNone, Rest}; 1684*5ffd940aSRaphael Isemann } 1685*5ffd940aSRaphael Isemann 1686*5ffd940aSRaphael Isemann // From the given position, find the next character after the word. 1687*5ffd940aSRaphael Isemann static size_t SkipWord(StringRef Str, size_t Loc) { 1688*5ffd940aSRaphael Isemann while (Loc < Str.size() && IsPartOfWord(Str[Loc])) 1689*5ffd940aSRaphael Isemann ++Loc; 1690*5ffd940aSRaphael Isemann return Loc; 1691*5ffd940aSRaphael Isemann } 1692*5ffd940aSRaphael Isemann 1693*5ffd940aSRaphael Isemann /// Searches the buffer for the first prefix in the prefix regular expression. 1694*5ffd940aSRaphael Isemann /// 1695*5ffd940aSRaphael Isemann /// This searches the buffer using the provided regular expression, however it 1696*5ffd940aSRaphael Isemann /// enforces constraints beyond that: 1697*5ffd940aSRaphael Isemann /// 1) The found prefix must not be a suffix of something that looks like 1698*5ffd940aSRaphael Isemann /// a valid prefix. 1699*5ffd940aSRaphael Isemann /// 2) The found prefix must be followed by a valid check type suffix using \c 1700*5ffd940aSRaphael Isemann /// FindCheckType above. 1701*5ffd940aSRaphael Isemann /// 1702*5ffd940aSRaphael Isemann /// \returns a pair of StringRefs into the Buffer, which combines: 1703*5ffd940aSRaphael Isemann /// - the first match of the regular expression to satisfy these two is 1704*5ffd940aSRaphael Isemann /// returned, 1705*5ffd940aSRaphael Isemann /// otherwise an empty StringRef is returned to indicate failure. 1706*5ffd940aSRaphael Isemann /// - buffer rewound to the location right after parsed suffix, for parsing 1707*5ffd940aSRaphael Isemann /// to continue from 1708*5ffd940aSRaphael Isemann /// 1709*5ffd940aSRaphael Isemann /// If this routine returns a valid prefix, it will also shrink \p Buffer to 1710*5ffd940aSRaphael Isemann /// start at the beginning of the returned prefix, increment \p LineNumber for 1711*5ffd940aSRaphael Isemann /// each new line consumed from \p Buffer, and set \p CheckTy to the type of 1712*5ffd940aSRaphael Isemann /// check found by examining the suffix. 1713*5ffd940aSRaphael Isemann /// 1714*5ffd940aSRaphael Isemann /// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy 1715*5ffd940aSRaphael Isemann /// is unspecified. 1716*5ffd940aSRaphael Isemann static std::pair<StringRef, StringRef> 1717*5ffd940aSRaphael Isemann FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE, 1718*5ffd940aSRaphael Isemann StringRef &Buffer, unsigned &LineNumber, 1719*5ffd940aSRaphael Isemann Check::FileCheckType &CheckTy) { 1720*5ffd940aSRaphael Isemann SmallVector<StringRef, 2> Matches; 1721*5ffd940aSRaphael Isemann 1722*5ffd940aSRaphael Isemann while (!Buffer.empty()) { 1723*5ffd940aSRaphael Isemann // Find the first (longest) match using the RE. 1724*5ffd940aSRaphael Isemann if (!PrefixRE.match(Buffer, &Matches)) 1725*5ffd940aSRaphael Isemann // No match at all, bail. 1726*5ffd940aSRaphael Isemann return {StringRef(), StringRef()}; 1727*5ffd940aSRaphael Isemann 1728*5ffd940aSRaphael Isemann StringRef Prefix = Matches[0]; 1729*5ffd940aSRaphael Isemann Matches.clear(); 1730*5ffd940aSRaphael Isemann 1731*5ffd940aSRaphael Isemann assert(Prefix.data() >= Buffer.data() && 1732*5ffd940aSRaphael Isemann Prefix.data() < Buffer.data() + Buffer.size() && 1733*5ffd940aSRaphael Isemann "Prefix doesn't start inside of buffer!"); 1734*5ffd940aSRaphael Isemann size_t Loc = Prefix.data() - Buffer.data(); 1735*5ffd940aSRaphael Isemann StringRef Skipped = Buffer.substr(0, Loc); 1736*5ffd940aSRaphael Isemann Buffer = Buffer.drop_front(Loc); 1737*5ffd940aSRaphael Isemann LineNumber += Skipped.count('\n'); 1738*5ffd940aSRaphael Isemann 1739*5ffd940aSRaphael Isemann // Check that the matched prefix isn't a suffix of some other check-like 1740*5ffd940aSRaphael Isemann // word. 1741*5ffd940aSRaphael Isemann // FIXME: This is a very ad-hoc check. it would be better handled in some 1742*5ffd940aSRaphael Isemann // other way. Among other things it seems hard to distinguish between 1743*5ffd940aSRaphael Isemann // intentional and unintentional uses of this feature. 1744*5ffd940aSRaphael Isemann if (Skipped.empty() || !IsPartOfWord(Skipped.back())) { 1745*5ffd940aSRaphael Isemann // Now extract the type. 1746*5ffd940aSRaphael Isemann StringRef AfterSuffix; 1747*5ffd940aSRaphael Isemann std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix); 1748*5ffd940aSRaphael Isemann 1749*5ffd940aSRaphael Isemann // If we've found a valid check type for this prefix, we're done. 1750*5ffd940aSRaphael Isemann if (CheckTy != Check::CheckNone) 1751*5ffd940aSRaphael Isemann return {Prefix, AfterSuffix}; 1752*5ffd940aSRaphael Isemann } 1753*5ffd940aSRaphael Isemann 1754*5ffd940aSRaphael Isemann // If we didn't successfully find a prefix, we need to skip this invalid 1755*5ffd940aSRaphael Isemann // prefix and continue scanning. We directly skip the prefix that was 1756*5ffd940aSRaphael Isemann // matched and any additional parts of that check-like word. 1757*5ffd940aSRaphael Isemann Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size())); 1758*5ffd940aSRaphael Isemann } 1759*5ffd940aSRaphael Isemann 1760*5ffd940aSRaphael Isemann // We ran out of buffer while skipping partial matches so give up. 1761*5ffd940aSRaphael Isemann return {StringRef(), StringRef()}; 1762*5ffd940aSRaphael Isemann } 1763*5ffd940aSRaphael Isemann 1764*5ffd940aSRaphael Isemann void FileCheckPatternContext::createLineVariable() { 1765*5ffd940aSRaphael Isemann assert(!LineVariable && "@LINE pseudo numeric variable already created"); 1766*5ffd940aSRaphael Isemann StringRef LineName = "@LINE"; 1767*5ffd940aSRaphael Isemann LineVariable = makeNumericVariable( 1768*5ffd940aSRaphael Isemann LineName, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); 1769*5ffd940aSRaphael Isemann GlobalNumericVariableTable[LineName] = LineVariable; 1770*5ffd940aSRaphael Isemann } 1771*5ffd940aSRaphael Isemann 1772*5ffd940aSRaphael Isemann FileCheck::FileCheck(FileCheckRequest Req) 1773*5ffd940aSRaphael Isemann : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()), 1774*5ffd940aSRaphael Isemann CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {} 1775*5ffd940aSRaphael Isemann 1776*5ffd940aSRaphael Isemann FileCheck::~FileCheck() = default; 1777*5ffd940aSRaphael Isemann 1778*5ffd940aSRaphael Isemann bool FileCheck::readCheckFile( 1779*5ffd940aSRaphael Isemann SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, 1780*5ffd940aSRaphael Isemann std::pair<unsigned, unsigned> *ImpPatBufferIDRange) { 1781*5ffd940aSRaphael Isemann if (ImpPatBufferIDRange) 1782*5ffd940aSRaphael Isemann ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0; 1783*5ffd940aSRaphael Isemann 1784*5ffd940aSRaphael Isemann Error DefineError = 1785*5ffd940aSRaphael Isemann PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM); 1786*5ffd940aSRaphael Isemann if (DefineError) { 1787*5ffd940aSRaphael Isemann logAllUnhandledErrors(std::move(DefineError), errs()); 1788*5ffd940aSRaphael Isemann return true; 1789*5ffd940aSRaphael Isemann } 1790*5ffd940aSRaphael Isemann 1791*5ffd940aSRaphael Isemann PatternContext->createLineVariable(); 1792*5ffd940aSRaphael Isemann 1793*5ffd940aSRaphael Isemann std::vector<Pattern> ImplicitNegativeChecks; 1794*5ffd940aSRaphael Isemann for (StringRef PatternString : Req.ImplicitCheckNot) { 1795*5ffd940aSRaphael Isemann // Create a buffer with fake command line content in order to display the 1796*5ffd940aSRaphael Isemann // command line option responsible for the specific implicit CHECK-NOT. 1797*5ffd940aSRaphael Isemann std::string Prefix = "-implicit-check-not='"; 1798*5ffd940aSRaphael Isemann std::string Suffix = "'"; 1799*5ffd940aSRaphael Isemann std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy( 1800*5ffd940aSRaphael Isemann (Prefix + PatternString + Suffix).str(), "command line"); 1801*5ffd940aSRaphael Isemann 1802*5ffd940aSRaphael Isemann StringRef PatternInBuffer = 1803*5ffd940aSRaphael Isemann CmdLine->getBuffer().substr(Prefix.size(), PatternString.size()); 1804*5ffd940aSRaphael Isemann unsigned BufferID = SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); 1805*5ffd940aSRaphael Isemann if (ImpPatBufferIDRange) { 1806*5ffd940aSRaphael Isemann if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) { 1807*5ffd940aSRaphael Isemann ImpPatBufferIDRange->first = BufferID; 1808*5ffd940aSRaphael Isemann ImpPatBufferIDRange->second = BufferID + 1; 1809*5ffd940aSRaphael Isemann } else { 1810*5ffd940aSRaphael Isemann assert(BufferID == ImpPatBufferIDRange->second && 1811*5ffd940aSRaphael Isemann "expected consecutive source buffer IDs"); 1812*5ffd940aSRaphael Isemann ++ImpPatBufferIDRange->second; 1813*5ffd940aSRaphael Isemann } 1814*5ffd940aSRaphael Isemann } 1815*5ffd940aSRaphael Isemann 1816*5ffd940aSRaphael Isemann ImplicitNegativeChecks.push_back( 1817*5ffd940aSRaphael Isemann Pattern(Check::CheckNot, PatternContext.get())); 1818*5ffd940aSRaphael Isemann ImplicitNegativeChecks.back().parsePattern(PatternInBuffer, 1819*5ffd940aSRaphael Isemann "IMPLICIT-CHECK", SM, Req); 1820*5ffd940aSRaphael Isemann } 1821*5ffd940aSRaphael Isemann 1822*5ffd940aSRaphael Isemann std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks; 1823*5ffd940aSRaphael Isemann 1824*5ffd940aSRaphael Isemann // LineNumber keeps track of the line on which CheckPrefix instances are 1825*5ffd940aSRaphael Isemann // found. 1826*5ffd940aSRaphael Isemann unsigned LineNumber = 1; 1827*5ffd940aSRaphael Isemann 1828*5ffd940aSRaphael Isemann bool FoundUsedCheckPrefix = false; 1829*5ffd940aSRaphael Isemann while (1) { 1830*5ffd940aSRaphael Isemann Check::FileCheckType CheckTy; 1831*5ffd940aSRaphael Isemann 1832*5ffd940aSRaphael Isemann // See if a prefix occurs in the memory buffer. 1833*5ffd940aSRaphael Isemann StringRef UsedPrefix; 1834*5ffd940aSRaphael Isemann StringRef AfterSuffix; 1835*5ffd940aSRaphael Isemann std::tie(UsedPrefix, AfterSuffix) = 1836*5ffd940aSRaphael Isemann FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy); 1837*5ffd940aSRaphael Isemann if (UsedPrefix.empty()) 1838*5ffd940aSRaphael Isemann break; 1839*5ffd940aSRaphael Isemann if (CheckTy != Check::CheckComment) 1840*5ffd940aSRaphael Isemann FoundUsedCheckPrefix = true; 1841*5ffd940aSRaphael Isemann 1842*5ffd940aSRaphael Isemann assert(UsedPrefix.data() == Buffer.data() && 1843*5ffd940aSRaphael Isemann "Failed to move Buffer's start forward, or pointed prefix outside " 1844*5ffd940aSRaphael Isemann "of the buffer!"); 1845*5ffd940aSRaphael Isemann assert(AfterSuffix.data() >= Buffer.data() && 1846*5ffd940aSRaphael Isemann AfterSuffix.data() < Buffer.data() + Buffer.size() && 1847*5ffd940aSRaphael Isemann "Parsing after suffix doesn't start inside of buffer!"); 1848*5ffd940aSRaphael Isemann 1849*5ffd940aSRaphael Isemann // Location to use for error messages. 1850*5ffd940aSRaphael Isemann const char *UsedPrefixStart = UsedPrefix.data(); 1851*5ffd940aSRaphael Isemann 1852*5ffd940aSRaphael Isemann // Skip the buffer to the end of parsed suffix (or just prefix, if no good 1853*5ffd940aSRaphael Isemann // suffix was processed). 1854*5ffd940aSRaphael Isemann Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size()) 1855*5ffd940aSRaphael Isemann : AfterSuffix; 1856*5ffd940aSRaphael Isemann 1857*5ffd940aSRaphael Isemann // Complain about useful-looking but unsupported suffixes. 1858*5ffd940aSRaphael Isemann if (CheckTy == Check::CheckBadNot) { 1859*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, 1860*5ffd940aSRaphael Isemann "unsupported -NOT combo on prefix '" + UsedPrefix + "'"); 1861*5ffd940aSRaphael Isemann return true; 1862*5ffd940aSRaphael Isemann } 1863*5ffd940aSRaphael Isemann 1864*5ffd940aSRaphael Isemann // Complain about invalid count specification. 1865*5ffd940aSRaphael Isemann if (CheckTy == Check::CheckBadCount) { 1866*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, 1867*5ffd940aSRaphael Isemann "invalid count in -COUNT specification on prefix '" + 1868*5ffd940aSRaphael Isemann UsedPrefix + "'"); 1869*5ffd940aSRaphael Isemann return true; 1870*5ffd940aSRaphael Isemann } 1871*5ffd940aSRaphael Isemann 1872*5ffd940aSRaphael Isemann // Okay, we found the prefix, yay. Remember the rest of the line, but ignore 1873*5ffd940aSRaphael Isemann // leading whitespace. 1874*5ffd940aSRaphael Isemann if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) 1875*5ffd940aSRaphael Isemann Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); 1876*5ffd940aSRaphael Isemann 1877*5ffd940aSRaphael Isemann // Scan ahead to the end of line. 1878*5ffd940aSRaphael Isemann size_t EOL = Buffer.find_first_of("\n\r"); 1879*5ffd940aSRaphael Isemann 1880*5ffd940aSRaphael Isemann // Remember the location of the start of the pattern, for diagnostics. 1881*5ffd940aSRaphael Isemann SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); 1882*5ffd940aSRaphael Isemann 1883*5ffd940aSRaphael Isemann // Extract the pattern from the buffer. 1884*5ffd940aSRaphael Isemann StringRef PatternBuffer = Buffer.substr(0, EOL); 1885*5ffd940aSRaphael Isemann Buffer = Buffer.substr(EOL); 1886*5ffd940aSRaphael Isemann 1887*5ffd940aSRaphael Isemann // If this is a comment, we're done. 1888*5ffd940aSRaphael Isemann if (CheckTy == Check::CheckComment) 1889*5ffd940aSRaphael Isemann continue; 1890*5ffd940aSRaphael Isemann 1891*5ffd940aSRaphael Isemann // Parse the pattern. 1892*5ffd940aSRaphael Isemann Pattern P(CheckTy, PatternContext.get(), LineNumber); 1893*5ffd940aSRaphael Isemann if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req)) 1894*5ffd940aSRaphael Isemann return true; 1895*5ffd940aSRaphael Isemann 1896*5ffd940aSRaphael Isemann // Verify that CHECK-LABEL lines do not define or use variables 1897*5ffd940aSRaphael Isemann if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { 1898*5ffd940aSRaphael Isemann SM.PrintMessage( 1899*5ffd940aSRaphael Isemann SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, 1900*5ffd940aSRaphael Isemann "found '" + UsedPrefix + "-LABEL:'" 1901*5ffd940aSRaphael Isemann " with variable definition or use"); 1902*5ffd940aSRaphael Isemann return true; 1903*5ffd940aSRaphael Isemann } 1904*5ffd940aSRaphael Isemann 1905*5ffd940aSRaphael Isemann // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them. 1906*5ffd940aSRaphael Isemann if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame || 1907*5ffd940aSRaphael Isemann CheckTy == Check::CheckEmpty) && 1908*5ffd940aSRaphael Isemann CheckStrings->empty()) { 1909*5ffd940aSRaphael Isemann StringRef Type = CheckTy == Check::CheckNext 1910*5ffd940aSRaphael Isemann ? "NEXT" 1911*5ffd940aSRaphael Isemann : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME"; 1912*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), 1913*5ffd940aSRaphael Isemann SourceMgr::DK_Error, 1914*5ffd940aSRaphael Isemann "found '" + UsedPrefix + "-" + Type + 1915*5ffd940aSRaphael Isemann "' without previous '" + UsedPrefix + ": line"); 1916*5ffd940aSRaphael Isemann return true; 1917*5ffd940aSRaphael Isemann } 1918*5ffd940aSRaphael Isemann 1919*5ffd940aSRaphael Isemann // Handle CHECK-DAG/-NOT. 1920*5ffd940aSRaphael Isemann if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { 1921*5ffd940aSRaphael Isemann DagNotMatches.push_back(P); 1922*5ffd940aSRaphael Isemann continue; 1923*5ffd940aSRaphael Isemann } 1924*5ffd940aSRaphael Isemann 1925*5ffd940aSRaphael Isemann // Okay, add the string we captured to the output vector and move on. 1926*5ffd940aSRaphael Isemann CheckStrings->emplace_back(P, UsedPrefix, PatternLoc); 1927*5ffd940aSRaphael Isemann std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); 1928*5ffd940aSRaphael Isemann DagNotMatches = ImplicitNegativeChecks; 1929*5ffd940aSRaphael Isemann } 1930*5ffd940aSRaphael Isemann 1931*5ffd940aSRaphael Isemann // When there are no used prefixes we report an error except in the case that 1932*5ffd940aSRaphael Isemann // no prefix is specified explicitly but -implicit-check-not is specified. 1933*5ffd940aSRaphael Isemann if (!FoundUsedCheckPrefix && 1934*5ffd940aSRaphael Isemann (ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) { 1935*5ffd940aSRaphael Isemann errs() << "error: no check strings found with prefix" 1936*5ffd940aSRaphael Isemann << (Req.CheckPrefixes.size() > 1 ? "es " : " "); 1937*5ffd940aSRaphael Isemann for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { 1938*5ffd940aSRaphael Isemann if (I != 0) 1939*5ffd940aSRaphael Isemann errs() << ", "; 1940*5ffd940aSRaphael Isemann errs() << "\'" << Req.CheckPrefixes[I] << ":'"; 1941*5ffd940aSRaphael Isemann } 1942*5ffd940aSRaphael Isemann errs() << '\n'; 1943*5ffd940aSRaphael Isemann return true; 1944*5ffd940aSRaphael Isemann } 1945*5ffd940aSRaphael Isemann 1946*5ffd940aSRaphael Isemann // Add an EOF pattern for any trailing --implicit-check-not/CHECK-DAG/-NOTs, 1947*5ffd940aSRaphael Isemann // and use the first prefix as a filler for the error message. 1948*5ffd940aSRaphael Isemann if (!DagNotMatches.empty()) { 1949*5ffd940aSRaphael Isemann CheckStrings->emplace_back( 1950*5ffd940aSRaphael Isemann Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1), 1951*5ffd940aSRaphael Isemann *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data())); 1952*5ffd940aSRaphael Isemann std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); 1953*5ffd940aSRaphael Isemann } 1954*5ffd940aSRaphael Isemann 1955*5ffd940aSRaphael Isemann return false; 1956*5ffd940aSRaphael Isemann } 1957*5ffd940aSRaphael Isemann 1958*5ffd940aSRaphael Isemann static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, 1959*5ffd940aSRaphael Isemann StringRef Prefix, SMLoc Loc, const Pattern &Pat, 1960*5ffd940aSRaphael Isemann int MatchedCount, StringRef Buffer, size_t MatchPos, 1961*5ffd940aSRaphael Isemann size_t MatchLen, const FileCheckRequest &Req, 1962*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) { 1963*5ffd940aSRaphael Isemann bool PrintDiag = true; 1964*5ffd940aSRaphael Isemann if (ExpectedMatch) { 1965*5ffd940aSRaphael Isemann if (!Req.Verbose) 1966*5ffd940aSRaphael Isemann return; 1967*5ffd940aSRaphael Isemann if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF) 1968*5ffd940aSRaphael Isemann return; 1969*5ffd940aSRaphael Isemann // Due to their verbosity, we don't print verbose diagnostics here if we're 1970*5ffd940aSRaphael Isemann // gathering them for a different rendering, but we always print other 1971*5ffd940aSRaphael Isemann // diagnostics. 1972*5ffd940aSRaphael Isemann PrintDiag = !Diags; 1973*5ffd940aSRaphael Isemann } 1974*5ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy = ExpectedMatch 1975*5ffd940aSRaphael Isemann ? FileCheckDiag::MatchFoundAndExpected 1976*5ffd940aSRaphael Isemann : FileCheckDiag::MatchFoundButExcluded; 1977*5ffd940aSRaphael Isemann SMRange MatchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), 1978*5ffd940aSRaphael Isemann Buffer, MatchPos, MatchLen, Diags); 1979*5ffd940aSRaphael Isemann if (Diags) { 1980*5ffd940aSRaphael Isemann Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, Diags); 1981*5ffd940aSRaphael Isemann Pat.printVariableDefs(SM, MatchTy, Diags); 1982*5ffd940aSRaphael Isemann } 1983*5ffd940aSRaphael Isemann if (!PrintDiag) 1984*5ffd940aSRaphael Isemann return; 1985*5ffd940aSRaphael Isemann 1986*5ffd940aSRaphael Isemann std::string Message = formatv("{0}: {1} string found in input", 1987*5ffd940aSRaphael Isemann Pat.getCheckTy().getDescription(Prefix), 1988*5ffd940aSRaphael Isemann (ExpectedMatch ? "expected" : "excluded")) 1989*5ffd940aSRaphael Isemann .str(); 1990*5ffd940aSRaphael Isemann if (Pat.getCount() > 1) 1991*5ffd940aSRaphael Isemann Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); 1992*5ffd940aSRaphael Isemann 1993*5ffd940aSRaphael Isemann SM.PrintMessage( 1994*5ffd940aSRaphael Isemann Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message); 1995*5ffd940aSRaphael Isemann SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here", 1996*5ffd940aSRaphael Isemann {MatchRange}); 1997*5ffd940aSRaphael Isemann Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, nullptr); 1998*5ffd940aSRaphael Isemann Pat.printVariableDefs(SM, MatchTy, nullptr); 1999*5ffd940aSRaphael Isemann } 2000*5ffd940aSRaphael Isemann 2001*5ffd940aSRaphael Isemann static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, 2002*5ffd940aSRaphael Isemann const FileCheckString &CheckStr, int MatchedCount, 2003*5ffd940aSRaphael Isemann StringRef Buffer, size_t MatchPos, size_t MatchLen, 2004*5ffd940aSRaphael Isemann FileCheckRequest &Req, 2005*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) { 2006*5ffd940aSRaphael Isemann PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, 2007*5ffd940aSRaphael Isemann MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags); 2008*5ffd940aSRaphael Isemann } 2009*5ffd940aSRaphael Isemann 2010*5ffd940aSRaphael Isemann static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, 2011*5ffd940aSRaphael Isemann StringRef Prefix, SMLoc Loc, const Pattern &Pat, 2012*5ffd940aSRaphael Isemann int MatchedCount, StringRef Buffer, 2013*5ffd940aSRaphael Isemann bool VerboseVerbose, std::vector<FileCheckDiag> *Diags, 2014*5ffd940aSRaphael Isemann Error MatchErrors) { 2015*5ffd940aSRaphael Isemann assert(MatchErrors && "Called on successful match"); 2016*5ffd940aSRaphael Isemann bool PrintDiag = true; 2017*5ffd940aSRaphael Isemann if (!ExpectedMatch) { 2018*5ffd940aSRaphael Isemann if (!VerboseVerbose) { 2019*5ffd940aSRaphael Isemann consumeError(std::move(MatchErrors)); 2020*5ffd940aSRaphael Isemann return; 2021*5ffd940aSRaphael Isemann } 2022*5ffd940aSRaphael Isemann // Due to their verbosity, we don't print verbose diagnostics here if we're 2023*5ffd940aSRaphael Isemann // gathering them for a different rendering, but we always print other 2024*5ffd940aSRaphael Isemann // diagnostics. 2025*5ffd940aSRaphael Isemann PrintDiag = !Diags; 2026*5ffd940aSRaphael Isemann } 2027*5ffd940aSRaphael Isemann 2028*5ffd940aSRaphael Isemann // If the current position is at the end of a line, advance to the start of 2029*5ffd940aSRaphael Isemann // the next line. 2030*5ffd940aSRaphael Isemann Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r")); 2031*5ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy = ExpectedMatch 2032*5ffd940aSRaphael Isemann ? FileCheckDiag::MatchNoneButExpected 2033*5ffd940aSRaphael Isemann : FileCheckDiag::MatchNoneAndExcluded; 2034*5ffd940aSRaphael Isemann SMRange SearchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), 2035*5ffd940aSRaphael Isemann Buffer, 0, Buffer.size(), Diags); 2036*5ffd940aSRaphael Isemann if (Diags) 2037*5ffd940aSRaphael Isemann Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, Diags); 2038*5ffd940aSRaphael Isemann if (!PrintDiag) { 2039*5ffd940aSRaphael Isemann consumeError(std::move(MatchErrors)); 2040*5ffd940aSRaphael Isemann return; 2041*5ffd940aSRaphael Isemann } 2042*5ffd940aSRaphael Isemann 2043*5ffd940aSRaphael Isemann MatchErrors = handleErrors(std::move(MatchErrors), 2044*5ffd940aSRaphael Isemann [](const ErrorDiagnostic &E) { E.log(errs()); }); 2045*5ffd940aSRaphael Isemann 2046*5ffd940aSRaphael Isemann // No problem matching the string per se. 2047*5ffd940aSRaphael Isemann if (!MatchErrors) 2048*5ffd940aSRaphael Isemann return; 2049*5ffd940aSRaphael Isemann consumeError(std::move(MatchErrors)); 2050*5ffd940aSRaphael Isemann 2051*5ffd940aSRaphael Isemann // Print "not found" diagnostic. 2052*5ffd940aSRaphael Isemann std::string Message = formatv("{0}: {1} string not found in input", 2053*5ffd940aSRaphael Isemann Pat.getCheckTy().getDescription(Prefix), 2054*5ffd940aSRaphael Isemann (ExpectedMatch ? "expected" : "excluded")) 2055*5ffd940aSRaphael Isemann .str(); 2056*5ffd940aSRaphael Isemann if (Pat.getCount() > 1) 2057*5ffd940aSRaphael Isemann Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); 2058*5ffd940aSRaphael Isemann SM.PrintMessage( 2059*5ffd940aSRaphael Isemann Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message); 2060*5ffd940aSRaphael Isemann 2061*5ffd940aSRaphael Isemann // Print the "scanning from here" line. 2062*5ffd940aSRaphael Isemann SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here"); 2063*5ffd940aSRaphael Isemann 2064*5ffd940aSRaphael Isemann // Allow the pattern to print additional information if desired. 2065*5ffd940aSRaphael Isemann Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, nullptr); 2066*5ffd940aSRaphael Isemann 2067*5ffd940aSRaphael Isemann if (ExpectedMatch) 2068*5ffd940aSRaphael Isemann Pat.printFuzzyMatch(SM, Buffer, Diags); 2069*5ffd940aSRaphael Isemann } 2070*5ffd940aSRaphael Isemann 2071*5ffd940aSRaphael Isemann static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, 2072*5ffd940aSRaphael Isemann const FileCheckString &CheckStr, int MatchedCount, 2073*5ffd940aSRaphael Isemann StringRef Buffer, bool VerboseVerbose, 2074*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags, Error MatchErrors) { 2075*5ffd940aSRaphael Isemann PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, 2076*5ffd940aSRaphael Isemann MatchedCount, Buffer, VerboseVerbose, Diags, 2077*5ffd940aSRaphael Isemann std::move(MatchErrors)); 2078*5ffd940aSRaphael Isemann } 2079*5ffd940aSRaphael Isemann 2080*5ffd940aSRaphael Isemann /// Counts the number of newlines in the specified range. 2081*5ffd940aSRaphael Isemann static unsigned CountNumNewlinesBetween(StringRef Range, 2082*5ffd940aSRaphael Isemann const char *&FirstNewLine) { 2083*5ffd940aSRaphael Isemann unsigned NumNewLines = 0; 2084*5ffd940aSRaphael Isemann while (1) { 2085*5ffd940aSRaphael Isemann // Scan for newline. 2086*5ffd940aSRaphael Isemann Range = Range.substr(Range.find_first_of("\n\r")); 2087*5ffd940aSRaphael Isemann if (Range.empty()) 2088*5ffd940aSRaphael Isemann return NumNewLines; 2089*5ffd940aSRaphael Isemann 2090*5ffd940aSRaphael Isemann ++NumNewLines; 2091*5ffd940aSRaphael Isemann 2092*5ffd940aSRaphael Isemann // Handle \n\r and \r\n as a single newline. 2093*5ffd940aSRaphael Isemann if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') && 2094*5ffd940aSRaphael Isemann (Range[0] != Range[1])) 2095*5ffd940aSRaphael Isemann Range = Range.substr(1); 2096*5ffd940aSRaphael Isemann Range = Range.substr(1); 2097*5ffd940aSRaphael Isemann 2098*5ffd940aSRaphael Isemann if (NumNewLines == 1) 2099*5ffd940aSRaphael Isemann FirstNewLine = Range.begin(); 2100*5ffd940aSRaphael Isemann } 2101*5ffd940aSRaphael Isemann } 2102*5ffd940aSRaphael Isemann 2103*5ffd940aSRaphael Isemann size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, 2104*5ffd940aSRaphael Isemann bool IsLabelScanMode, size_t &MatchLen, 2105*5ffd940aSRaphael Isemann FileCheckRequest &Req, 2106*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 2107*5ffd940aSRaphael Isemann size_t LastPos = 0; 2108*5ffd940aSRaphael Isemann std::vector<const Pattern *> NotStrings; 2109*5ffd940aSRaphael Isemann 2110*5ffd940aSRaphael Isemann // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL 2111*5ffd940aSRaphael Isemann // bounds; we have not processed variable definitions within the bounded block 2112*5ffd940aSRaphael Isemann // yet so cannot handle any final CHECK-DAG yet; this is handled when going 2113*5ffd940aSRaphael Isemann // over the block again (including the last CHECK-LABEL) in normal mode. 2114*5ffd940aSRaphael Isemann if (!IsLabelScanMode) { 2115*5ffd940aSRaphael Isemann // Match "dag strings" (with mixed "not strings" if any). 2116*5ffd940aSRaphael Isemann LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags); 2117*5ffd940aSRaphael Isemann if (LastPos == StringRef::npos) 2118*5ffd940aSRaphael Isemann return StringRef::npos; 2119*5ffd940aSRaphael Isemann } 2120*5ffd940aSRaphael Isemann 2121*5ffd940aSRaphael Isemann // Match itself from the last position after matching CHECK-DAG. 2122*5ffd940aSRaphael Isemann size_t LastMatchEnd = LastPos; 2123*5ffd940aSRaphael Isemann size_t FirstMatchPos = 0; 2124*5ffd940aSRaphael Isemann // Go match the pattern Count times. Majority of patterns only match with 2125*5ffd940aSRaphael Isemann // count 1 though. 2126*5ffd940aSRaphael Isemann assert(Pat.getCount() != 0 && "pattern count can not be zero"); 2127*5ffd940aSRaphael Isemann for (int i = 1; i <= Pat.getCount(); i++) { 2128*5ffd940aSRaphael Isemann StringRef MatchBuffer = Buffer.substr(LastMatchEnd); 2129*5ffd940aSRaphael Isemann size_t CurrentMatchLen; 2130*5ffd940aSRaphael Isemann // get a match at current start point 2131*5ffd940aSRaphael Isemann Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM); 2132*5ffd940aSRaphael Isemann 2133*5ffd940aSRaphael Isemann // report 2134*5ffd940aSRaphael Isemann if (!MatchResult) { 2135*5ffd940aSRaphael Isemann PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags, 2136*5ffd940aSRaphael Isemann MatchResult.takeError()); 2137*5ffd940aSRaphael Isemann return StringRef::npos; 2138*5ffd940aSRaphael Isemann } 2139*5ffd940aSRaphael Isemann size_t MatchPos = *MatchResult; 2140*5ffd940aSRaphael Isemann PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req, 2141*5ffd940aSRaphael Isemann Diags); 2142*5ffd940aSRaphael Isemann if (i == 1) 2143*5ffd940aSRaphael Isemann FirstMatchPos = LastPos + MatchPos; 2144*5ffd940aSRaphael Isemann 2145*5ffd940aSRaphael Isemann // move start point after the match 2146*5ffd940aSRaphael Isemann LastMatchEnd += MatchPos + CurrentMatchLen; 2147*5ffd940aSRaphael Isemann } 2148*5ffd940aSRaphael Isemann // Full match len counts from first match pos. 2149*5ffd940aSRaphael Isemann MatchLen = LastMatchEnd - FirstMatchPos; 2150*5ffd940aSRaphael Isemann 2151*5ffd940aSRaphael Isemann // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT 2152*5ffd940aSRaphael Isemann // or CHECK-NOT 2153*5ffd940aSRaphael Isemann if (!IsLabelScanMode) { 2154*5ffd940aSRaphael Isemann size_t MatchPos = FirstMatchPos - LastPos; 2155*5ffd940aSRaphael Isemann StringRef MatchBuffer = Buffer.substr(LastPos); 2156*5ffd940aSRaphael Isemann StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); 2157*5ffd940aSRaphael Isemann 2158*5ffd940aSRaphael Isemann // If this check is a "CHECK-NEXT", verify that the previous match was on 2159*5ffd940aSRaphael Isemann // the previous line (i.e. that there is one newline between them). 2160*5ffd940aSRaphael Isemann if (CheckNext(SM, SkippedRegion)) { 2161*5ffd940aSRaphael Isemann ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, 2162*5ffd940aSRaphael Isemann Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, 2163*5ffd940aSRaphael Isemann Diags, Req.Verbose); 2164*5ffd940aSRaphael Isemann return StringRef::npos; 2165*5ffd940aSRaphael Isemann } 2166*5ffd940aSRaphael Isemann 2167*5ffd940aSRaphael Isemann // If this check is a "CHECK-SAME", verify that the previous match was on 2168*5ffd940aSRaphael Isemann // the same line (i.e. that there is no newline between them). 2169*5ffd940aSRaphael Isemann if (CheckSame(SM, SkippedRegion)) { 2170*5ffd940aSRaphael Isemann ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, 2171*5ffd940aSRaphael Isemann Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, 2172*5ffd940aSRaphael Isemann Diags, Req.Verbose); 2173*5ffd940aSRaphael Isemann return StringRef::npos; 2174*5ffd940aSRaphael Isemann } 2175*5ffd940aSRaphael Isemann 2176*5ffd940aSRaphael Isemann // If this match had "not strings", verify that they don't exist in the 2177*5ffd940aSRaphael Isemann // skipped region. 2178*5ffd940aSRaphael Isemann if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) 2179*5ffd940aSRaphael Isemann return StringRef::npos; 2180*5ffd940aSRaphael Isemann } 2181*5ffd940aSRaphael Isemann 2182*5ffd940aSRaphael Isemann return FirstMatchPos; 2183*5ffd940aSRaphael Isemann } 2184*5ffd940aSRaphael Isemann 2185*5ffd940aSRaphael Isemann bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { 2186*5ffd940aSRaphael Isemann if (Pat.getCheckTy() != Check::CheckNext && 2187*5ffd940aSRaphael Isemann Pat.getCheckTy() != Check::CheckEmpty) 2188*5ffd940aSRaphael Isemann return false; 2189*5ffd940aSRaphael Isemann 2190*5ffd940aSRaphael Isemann Twine CheckName = 2191*5ffd940aSRaphael Isemann Prefix + 2192*5ffd940aSRaphael Isemann Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT"); 2193*5ffd940aSRaphael Isemann 2194*5ffd940aSRaphael Isemann // Count the number of newlines between the previous match and this one. 2195*5ffd940aSRaphael Isemann const char *FirstNewLine = nullptr; 2196*5ffd940aSRaphael Isemann unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); 2197*5ffd940aSRaphael Isemann 2198*5ffd940aSRaphael Isemann if (NumNewLines == 0) { 2199*5ffd940aSRaphael Isemann SM.PrintMessage(Loc, SourceMgr::DK_Error, 2200*5ffd940aSRaphael Isemann CheckName + ": is on the same line as previous match"); 2201*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 2202*5ffd940aSRaphael Isemann "'next' match was here"); 2203*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 2204*5ffd940aSRaphael Isemann "previous match ended here"); 2205*5ffd940aSRaphael Isemann return true; 2206*5ffd940aSRaphael Isemann } 2207*5ffd940aSRaphael Isemann 2208*5ffd940aSRaphael Isemann if (NumNewLines != 1) { 2209*5ffd940aSRaphael Isemann SM.PrintMessage(Loc, SourceMgr::DK_Error, 2210*5ffd940aSRaphael Isemann CheckName + 2211*5ffd940aSRaphael Isemann ": is not on the line after the previous match"); 2212*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 2213*5ffd940aSRaphael Isemann "'next' match was here"); 2214*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 2215*5ffd940aSRaphael Isemann "previous match ended here"); 2216*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note, 2217*5ffd940aSRaphael Isemann "non-matching line after previous match is here"); 2218*5ffd940aSRaphael Isemann return true; 2219*5ffd940aSRaphael Isemann } 2220*5ffd940aSRaphael Isemann 2221*5ffd940aSRaphael Isemann return false; 2222*5ffd940aSRaphael Isemann } 2223*5ffd940aSRaphael Isemann 2224*5ffd940aSRaphael Isemann bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { 2225*5ffd940aSRaphael Isemann if (Pat.getCheckTy() != Check::CheckSame) 2226*5ffd940aSRaphael Isemann return false; 2227*5ffd940aSRaphael Isemann 2228*5ffd940aSRaphael Isemann // Count the number of newlines between the previous match and this one. 2229*5ffd940aSRaphael Isemann const char *FirstNewLine = nullptr; 2230*5ffd940aSRaphael Isemann unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); 2231*5ffd940aSRaphael Isemann 2232*5ffd940aSRaphael Isemann if (NumNewLines != 0) { 2233*5ffd940aSRaphael Isemann SM.PrintMessage(Loc, SourceMgr::DK_Error, 2234*5ffd940aSRaphael Isemann Prefix + 2235*5ffd940aSRaphael Isemann "-SAME: is not on the same line as the previous match"); 2236*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 2237*5ffd940aSRaphael Isemann "'next' match was here"); 2238*5ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 2239*5ffd940aSRaphael Isemann "previous match ended here"); 2240*5ffd940aSRaphael Isemann return true; 2241*5ffd940aSRaphael Isemann } 2242*5ffd940aSRaphael Isemann 2243*5ffd940aSRaphael Isemann return false; 2244*5ffd940aSRaphael Isemann } 2245*5ffd940aSRaphael Isemann 2246*5ffd940aSRaphael Isemann bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, 2247*5ffd940aSRaphael Isemann const std::vector<const Pattern *> &NotStrings, 2248*5ffd940aSRaphael Isemann const FileCheckRequest &Req, 2249*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 2250*5ffd940aSRaphael Isemann bool DirectiveFail = false; 2251*5ffd940aSRaphael Isemann for (const Pattern *Pat : NotStrings) { 2252*5ffd940aSRaphael Isemann assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); 2253*5ffd940aSRaphael Isemann 2254*5ffd940aSRaphael Isemann size_t MatchLen = 0; 2255*5ffd940aSRaphael Isemann Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM); 2256*5ffd940aSRaphael Isemann 2257*5ffd940aSRaphael Isemann if (!MatchResult) { 2258*5ffd940aSRaphael Isemann PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, 2259*5ffd940aSRaphael Isemann Req.VerboseVerbose, Diags, MatchResult.takeError()); 2260*5ffd940aSRaphael Isemann continue; 2261*5ffd940aSRaphael Isemann } 2262*5ffd940aSRaphael Isemann size_t Pos = *MatchResult; 2263*5ffd940aSRaphael Isemann 2264*5ffd940aSRaphael Isemann PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen, 2265*5ffd940aSRaphael Isemann Req, Diags); 2266*5ffd940aSRaphael Isemann DirectiveFail = true; 2267*5ffd940aSRaphael Isemann continue; 2268*5ffd940aSRaphael Isemann } 2269*5ffd940aSRaphael Isemann 2270*5ffd940aSRaphael Isemann return DirectiveFail; 2271*5ffd940aSRaphael Isemann } 2272*5ffd940aSRaphael Isemann 2273*5ffd940aSRaphael Isemann size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, 2274*5ffd940aSRaphael Isemann std::vector<const Pattern *> &NotStrings, 2275*5ffd940aSRaphael Isemann const FileCheckRequest &Req, 2276*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 2277*5ffd940aSRaphael Isemann if (DagNotStrings.empty()) 2278*5ffd940aSRaphael Isemann return 0; 2279*5ffd940aSRaphael Isemann 2280*5ffd940aSRaphael Isemann // The start of the search range. 2281*5ffd940aSRaphael Isemann size_t StartPos = 0; 2282*5ffd940aSRaphael Isemann 2283*5ffd940aSRaphael Isemann struct MatchRange { 2284*5ffd940aSRaphael Isemann size_t Pos; 2285*5ffd940aSRaphael Isemann size_t End; 2286*5ffd940aSRaphael Isemann }; 2287*5ffd940aSRaphael Isemann // A sorted list of ranges for non-overlapping CHECK-DAG matches. Match 2288*5ffd940aSRaphael Isemann // ranges are erased from this list once they are no longer in the search 2289*5ffd940aSRaphael Isemann // range. 2290*5ffd940aSRaphael Isemann std::list<MatchRange> MatchRanges; 2291*5ffd940aSRaphael Isemann 2292*5ffd940aSRaphael Isemann // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG 2293*5ffd940aSRaphael Isemann // group, so we don't use a range-based for loop here. 2294*5ffd940aSRaphael Isemann for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end(); 2295*5ffd940aSRaphael Isemann PatItr != PatEnd; ++PatItr) { 2296*5ffd940aSRaphael Isemann const Pattern &Pat = *PatItr; 2297*5ffd940aSRaphael Isemann assert((Pat.getCheckTy() == Check::CheckDAG || 2298*5ffd940aSRaphael Isemann Pat.getCheckTy() == Check::CheckNot) && 2299*5ffd940aSRaphael Isemann "Invalid CHECK-DAG or CHECK-NOT!"); 2300*5ffd940aSRaphael Isemann 2301*5ffd940aSRaphael Isemann if (Pat.getCheckTy() == Check::CheckNot) { 2302*5ffd940aSRaphael Isemann NotStrings.push_back(&Pat); 2303*5ffd940aSRaphael Isemann continue; 2304*5ffd940aSRaphael Isemann } 2305*5ffd940aSRaphael Isemann 2306*5ffd940aSRaphael Isemann assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); 2307*5ffd940aSRaphael Isemann 2308*5ffd940aSRaphael Isemann // CHECK-DAG always matches from the start. 2309*5ffd940aSRaphael Isemann size_t MatchLen = 0, MatchPos = StartPos; 2310*5ffd940aSRaphael Isemann 2311*5ffd940aSRaphael Isemann // Search for a match that doesn't overlap a previous match in this 2312*5ffd940aSRaphael Isemann // CHECK-DAG group. 2313*5ffd940aSRaphael Isemann for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) { 2314*5ffd940aSRaphael Isemann StringRef MatchBuffer = Buffer.substr(MatchPos); 2315*5ffd940aSRaphael Isemann Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM); 2316*5ffd940aSRaphael Isemann // With a group of CHECK-DAGs, a single mismatching means the match on 2317*5ffd940aSRaphael Isemann // that group of CHECK-DAGs fails immediately. 2318*5ffd940aSRaphael Isemann if (!MatchResult) { 2319*5ffd940aSRaphael Isemann PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer, 2320*5ffd940aSRaphael Isemann Req.VerboseVerbose, Diags, MatchResult.takeError()); 2321*5ffd940aSRaphael Isemann return StringRef::npos; 2322*5ffd940aSRaphael Isemann } 2323*5ffd940aSRaphael Isemann size_t MatchPosBuf = *MatchResult; 2324*5ffd940aSRaphael Isemann // Re-calc it as the offset relative to the start of the original string. 2325*5ffd940aSRaphael Isemann MatchPos += MatchPosBuf; 2326*5ffd940aSRaphael Isemann if (Req.VerboseVerbose) 2327*5ffd940aSRaphael Isemann PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos, 2328*5ffd940aSRaphael Isemann MatchLen, Req, Diags); 2329*5ffd940aSRaphael Isemann MatchRange M{MatchPos, MatchPos + MatchLen}; 2330*5ffd940aSRaphael Isemann if (Req.AllowDeprecatedDagOverlap) { 2331*5ffd940aSRaphael Isemann // We don't need to track all matches in this mode, so we just maintain 2332*5ffd940aSRaphael Isemann // one match range that encompasses the current CHECK-DAG group's 2333*5ffd940aSRaphael Isemann // matches. 2334*5ffd940aSRaphael Isemann if (MatchRanges.empty()) 2335*5ffd940aSRaphael Isemann MatchRanges.insert(MatchRanges.end(), M); 2336*5ffd940aSRaphael Isemann else { 2337*5ffd940aSRaphael Isemann auto Block = MatchRanges.begin(); 2338*5ffd940aSRaphael Isemann Block->Pos = std::min(Block->Pos, M.Pos); 2339*5ffd940aSRaphael Isemann Block->End = std::max(Block->End, M.End); 2340*5ffd940aSRaphael Isemann } 2341*5ffd940aSRaphael Isemann break; 2342*5ffd940aSRaphael Isemann } 2343*5ffd940aSRaphael Isemann // Iterate previous matches until overlapping match or insertion point. 2344*5ffd940aSRaphael Isemann bool Overlap = false; 2345*5ffd940aSRaphael Isemann for (; MI != ME; ++MI) { 2346*5ffd940aSRaphael Isemann if (M.Pos < MI->End) { 2347*5ffd940aSRaphael Isemann // !Overlap => New match has no overlap and is before this old match. 2348*5ffd940aSRaphael Isemann // Overlap => New match overlaps this old match. 2349*5ffd940aSRaphael Isemann Overlap = MI->Pos < M.End; 2350*5ffd940aSRaphael Isemann break; 2351*5ffd940aSRaphael Isemann } 2352*5ffd940aSRaphael Isemann } 2353*5ffd940aSRaphael Isemann if (!Overlap) { 2354*5ffd940aSRaphael Isemann // Insert non-overlapping match into list. 2355*5ffd940aSRaphael Isemann MatchRanges.insert(MI, M); 2356*5ffd940aSRaphael Isemann break; 2357*5ffd940aSRaphael Isemann } 2358*5ffd940aSRaphael Isemann if (Req.VerboseVerbose) { 2359*5ffd940aSRaphael Isemann // Due to their verbosity, we don't print verbose diagnostics here if 2360*5ffd940aSRaphael Isemann // we're gathering them for a different rendering, but we always print 2361*5ffd940aSRaphael Isemann // other diagnostics. 2362*5ffd940aSRaphael Isemann if (!Diags) { 2363*5ffd940aSRaphael Isemann SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos); 2364*5ffd940aSRaphael Isemann SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End); 2365*5ffd940aSRaphael Isemann SMRange OldRange(OldStart, OldEnd); 2366*5ffd940aSRaphael Isemann SM.PrintMessage(OldStart, SourceMgr::DK_Note, 2367*5ffd940aSRaphael Isemann "match discarded, overlaps earlier DAG match here", 2368*5ffd940aSRaphael Isemann {OldRange}); 2369*5ffd940aSRaphael Isemann } else { 2370*5ffd940aSRaphael Isemann SMLoc CheckLoc = Diags->rbegin()->CheckLoc; 2371*5ffd940aSRaphael Isemann for (auto I = Diags->rbegin(), E = Diags->rend(); 2372*5ffd940aSRaphael Isemann I != E && I->CheckLoc == CheckLoc; ++I) 2373*5ffd940aSRaphael Isemann I->MatchTy = FileCheckDiag::MatchFoundButDiscarded; 2374*5ffd940aSRaphael Isemann } 2375*5ffd940aSRaphael Isemann } 2376*5ffd940aSRaphael Isemann MatchPos = MI->End; 2377*5ffd940aSRaphael Isemann } 2378*5ffd940aSRaphael Isemann if (!Req.VerboseVerbose) 2379*5ffd940aSRaphael Isemann PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos, 2380*5ffd940aSRaphael Isemann MatchLen, Req, Diags); 2381*5ffd940aSRaphael Isemann 2382*5ffd940aSRaphael Isemann // Handle the end of a CHECK-DAG group. 2383*5ffd940aSRaphael Isemann if (std::next(PatItr) == PatEnd || 2384*5ffd940aSRaphael Isemann std::next(PatItr)->getCheckTy() == Check::CheckNot) { 2385*5ffd940aSRaphael Isemann if (!NotStrings.empty()) { 2386*5ffd940aSRaphael Isemann // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to 2387*5ffd940aSRaphael Isemann // CHECK-DAG, verify that there are no 'not' strings occurred in that 2388*5ffd940aSRaphael Isemann // region. 2389*5ffd940aSRaphael Isemann StringRef SkippedRegion = 2390*5ffd940aSRaphael Isemann Buffer.slice(StartPos, MatchRanges.begin()->Pos); 2391*5ffd940aSRaphael Isemann if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) 2392*5ffd940aSRaphael Isemann return StringRef::npos; 2393*5ffd940aSRaphael Isemann // Clear "not strings". 2394*5ffd940aSRaphael Isemann NotStrings.clear(); 2395*5ffd940aSRaphael Isemann } 2396*5ffd940aSRaphael Isemann // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the 2397*5ffd940aSRaphael Isemann // end of this CHECK-DAG group's match range. 2398*5ffd940aSRaphael Isemann StartPos = MatchRanges.rbegin()->End; 2399*5ffd940aSRaphael Isemann // Don't waste time checking for (impossible) overlaps before that. 2400*5ffd940aSRaphael Isemann MatchRanges.clear(); 2401*5ffd940aSRaphael Isemann } 2402*5ffd940aSRaphael Isemann } 2403*5ffd940aSRaphael Isemann 2404*5ffd940aSRaphael Isemann return StartPos; 2405*5ffd940aSRaphael Isemann } 2406*5ffd940aSRaphael Isemann 2407*5ffd940aSRaphael Isemann static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, 2408*5ffd940aSRaphael Isemann ArrayRef<StringRef> SuppliedPrefixes) { 2409*5ffd940aSRaphael Isemann for (StringRef Prefix : SuppliedPrefixes) { 2410*5ffd940aSRaphael Isemann if (Prefix.empty()) { 2411*5ffd940aSRaphael Isemann errs() << "error: supplied " << Kind << " prefix must not be the empty " 2412*5ffd940aSRaphael Isemann << "string\n"; 2413*5ffd940aSRaphael Isemann return false; 2414*5ffd940aSRaphael Isemann } 2415*5ffd940aSRaphael Isemann static const Regex Validator("^[a-zA-Z0-9_-]*$"); 2416*5ffd940aSRaphael Isemann if (!Validator.match(Prefix)) { 2417*5ffd940aSRaphael Isemann errs() << "error: supplied " << Kind << " prefix must start with a " 2418*5ffd940aSRaphael Isemann << "letter and contain only alphanumeric characters, hyphens, and " 2419*5ffd940aSRaphael Isemann << "underscores: '" << Prefix << "'\n"; 2420*5ffd940aSRaphael Isemann return false; 2421*5ffd940aSRaphael Isemann } 2422*5ffd940aSRaphael Isemann if (!UniquePrefixes.insert(Prefix).second) { 2423*5ffd940aSRaphael Isemann errs() << "error: supplied " << Kind << " prefix must be unique among " 2424*5ffd940aSRaphael Isemann << "check and comment prefixes: '" << Prefix << "'\n"; 2425*5ffd940aSRaphael Isemann return false; 2426*5ffd940aSRaphael Isemann } 2427*5ffd940aSRaphael Isemann } 2428*5ffd940aSRaphael Isemann return true; 2429*5ffd940aSRaphael Isemann } 2430*5ffd940aSRaphael Isemann 2431*5ffd940aSRaphael Isemann static const char *DefaultCheckPrefixes[] = {"CHECK"}; 2432*5ffd940aSRaphael Isemann static const char *DefaultCommentPrefixes[] = {"COM", "RUN"}; 2433*5ffd940aSRaphael Isemann 2434*5ffd940aSRaphael Isemann bool FileCheck::ValidateCheckPrefixes() { 2435*5ffd940aSRaphael Isemann StringSet<> UniquePrefixes; 2436*5ffd940aSRaphael Isemann // Add default prefixes to catch user-supplied duplicates of them below. 2437*5ffd940aSRaphael Isemann if (Req.CheckPrefixes.empty()) { 2438*5ffd940aSRaphael Isemann for (const char *Prefix : DefaultCheckPrefixes) 2439*5ffd940aSRaphael Isemann UniquePrefixes.insert(Prefix); 2440*5ffd940aSRaphael Isemann } 2441*5ffd940aSRaphael Isemann if (Req.CommentPrefixes.empty()) { 2442*5ffd940aSRaphael Isemann for (const char *Prefix : DefaultCommentPrefixes) 2443*5ffd940aSRaphael Isemann UniquePrefixes.insert(Prefix); 2444*5ffd940aSRaphael Isemann } 2445*5ffd940aSRaphael Isemann // Do not validate the default prefixes, or diagnostics about duplicates might 2446*5ffd940aSRaphael Isemann // incorrectly indicate that they were supplied by the user. 2447*5ffd940aSRaphael Isemann if (!ValidatePrefixes("check", UniquePrefixes, Req.CheckPrefixes)) 2448*5ffd940aSRaphael Isemann return false; 2449*5ffd940aSRaphael Isemann if (!ValidatePrefixes("comment", UniquePrefixes, Req.CommentPrefixes)) 2450*5ffd940aSRaphael Isemann return false; 2451*5ffd940aSRaphael Isemann return true; 2452*5ffd940aSRaphael Isemann } 2453*5ffd940aSRaphael Isemann 2454*5ffd940aSRaphael Isemann Regex FileCheck::buildCheckPrefixRegex() { 2455*5ffd940aSRaphael Isemann if (Req.CheckPrefixes.empty()) { 2456*5ffd940aSRaphael Isemann for (const char *Prefix : DefaultCheckPrefixes) 2457*5ffd940aSRaphael Isemann Req.CheckPrefixes.push_back(Prefix); 2458*5ffd940aSRaphael Isemann Req.IsDefaultCheckPrefix = true; 2459*5ffd940aSRaphael Isemann } 2460*5ffd940aSRaphael Isemann if (Req.CommentPrefixes.empty()) { 2461*5ffd940aSRaphael Isemann for (const char *Prefix : DefaultCommentPrefixes) 2462*5ffd940aSRaphael Isemann Req.CommentPrefixes.push_back(Prefix); 2463*5ffd940aSRaphael Isemann } 2464*5ffd940aSRaphael Isemann 2465*5ffd940aSRaphael Isemann // We already validated the contents of CheckPrefixes and CommentPrefixes so 2466*5ffd940aSRaphael Isemann // just concatenate them as alternatives. 2467*5ffd940aSRaphael Isemann SmallString<32> PrefixRegexStr; 2468*5ffd940aSRaphael Isemann for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { 2469*5ffd940aSRaphael Isemann if (I != 0) 2470*5ffd940aSRaphael Isemann PrefixRegexStr.push_back('|'); 2471*5ffd940aSRaphael Isemann PrefixRegexStr.append(Req.CheckPrefixes[I]); 2472*5ffd940aSRaphael Isemann } 2473*5ffd940aSRaphael Isemann for (StringRef Prefix : Req.CommentPrefixes) { 2474*5ffd940aSRaphael Isemann PrefixRegexStr.push_back('|'); 2475*5ffd940aSRaphael Isemann PrefixRegexStr.append(Prefix); 2476*5ffd940aSRaphael Isemann } 2477*5ffd940aSRaphael Isemann 2478*5ffd940aSRaphael Isemann return Regex(PrefixRegexStr); 2479*5ffd940aSRaphael Isemann } 2480*5ffd940aSRaphael Isemann 2481*5ffd940aSRaphael Isemann Error FileCheckPatternContext::defineCmdlineVariables( 2482*5ffd940aSRaphael Isemann ArrayRef<StringRef> CmdlineDefines, SourceMgr &SM) { 2483*5ffd940aSRaphael Isemann assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() && 2484*5ffd940aSRaphael Isemann "Overriding defined variable with command-line variable definitions"); 2485*5ffd940aSRaphael Isemann 2486*5ffd940aSRaphael Isemann if (CmdlineDefines.empty()) 2487*5ffd940aSRaphael Isemann return Error::success(); 2488*5ffd940aSRaphael Isemann 2489*5ffd940aSRaphael Isemann // Create a string representing the vector of command-line definitions. Each 2490*5ffd940aSRaphael Isemann // definition is on its own line and prefixed with a definition number to 2491*5ffd940aSRaphael Isemann // clarify which definition a given diagnostic corresponds to. 2492*5ffd940aSRaphael Isemann unsigned I = 0; 2493*5ffd940aSRaphael Isemann Error Errs = Error::success(); 2494*5ffd940aSRaphael Isemann std::string CmdlineDefsDiag; 2495*5ffd940aSRaphael Isemann SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices; 2496*5ffd940aSRaphael Isemann for (StringRef CmdlineDef : CmdlineDefines) { 2497*5ffd940aSRaphael Isemann std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str(); 2498*5ffd940aSRaphael Isemann size_t EqIdx = CmdlineDef.find('='); 2499*5ffd940aSRaphael Isemann if (EqIdx == StringRef::npos) { 2500*5ffd940aSRaphael Isemann CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0)); 2501*5ffd940aSRaphael Isemann continue; 2502*5ffd940aSRaphael Isemann } 2503*5ffd940aSRaphael Isemann // Numeric variable definition. 2504*5ffd940aSRaphael Isemann if (CmdlineDef[0] == '#') { 2505*5ffd940aSRaphael Isemann // Append a copy of the command-line definition adapted to use the same 2506*5ffd940aSRaphael Isemann // format as in the input file to be able to reuse 2507*5ffd940aSRaphael Isemann // parseNumericSubstitutionBlock. 2508*5ffd940aSRaphael Isemann CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str(); 2509*5ffd940aSRaphael Isemann std::string SubstitutionStr = std::string(CmdlineDef); 2510*5ffd940aSRaphael Isemann SubstitutionStr[EqIdx] = ':'; 2511*5ffd940aSRaphael Isemann CmdlineDefsIndices.push_back( 2512*5ffd940aSRaphael Isemann std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size())); 2513*5ffd940aSRaphael Isemann CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str(); 2514*5ffd940aSRaphael Isemann } else { 2515*5ffd940aSRaphael Isemann CmdlineDefsDiag += DefPrefix; 2516*5ffd940aSRaphael Isemann CmdlineDefsIndices.push_back( 2517*5ffd940aSRaphael Isemann std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size())); 2518*5ffd940aSRaphael Isemann CmdlineDefsDiag += (CmdlineDef + "\n").str(); 2519*5ffd940aSRaphael Isemann } 2520*5ffd940aSRaphael Isemann } 2521*5ffd940aSRaphael Isemann 2522*5ffd940aSRaphael Isemann // Create a buffer with fake command line content in order to display 2523*5ffd940aSRaphael Isemann // parsing diagnostic with location information and point to the 2524*5ffd940aSRaphael Isemann // global definition with invalid syntax. 2525*5ffd940aSRaphael Isemann std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer = 2526*5ffd940aSRaphael Isemann MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines"); 2527*5ffd940aSRaphael Isemann StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer(); 2528*5ffd940aSRaphael Isemann SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc()); 2529*5ffd940aSRaphael Isemann 2530*5ffd940aSRaphael Isemann for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) { 2531*5ffd940aSRaphael Isemann StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first, 2532*5ffd940aSRaphael Isemann CmdlineDefIndices.second); 2533*5ffd940aSRaphael Isemann if (CmdlineDef.empty()) { 2534*5ffd940aSRaphael Isemann Errs = joinErrors( 2535*5ffd940aSRaphael Isemann std::move(Errs), 2536*5ffd940aSRaphael Isemann ErrorDiagnostic::get(SM, CmdlineDef, 2537*5ffd940aSRaphael Isemann "missing equal sign in global definition")); 2538*5ffd940aSRaphael Isemann continue; 2539*5ffd940aSRaphael Isemann } 2540*5ffd940aSRaphael Isemann 2541*5ffd940aSRaphael Isemann // Numeric variable definition. 2542*5ffd940aSRaphael Isemann if (CmdlineDef[0] == '#') { 2543*5ffd940aSRaphael Isemann // Now parse the definition both to check that the syntax is correct and 2544*5ffd940aSRaphael Isemann // to create the necessary class instance. 2545*5ffd940aSRaphael Isemann StringRef CmdlineDefExpr = CmdlineDef.substr(1); 2546*5ffd940aSRaphael Isemann Optional<NumericVariable *> DefinedNumericVariable; 2547*5ffd940aSRaphael Isemann Expected<std::unique_ptr<Expression>> ExpressionResult = 2548*5ffd940aSRaphael Isemann Pattern::parseNumericSubstitutionBlock( 2549*5ffd940aSRaphael Isemann CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM); 2550*5ffd940aSRaphael Isemann if (!ExpressionResult) { 2551*5ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), ExpressionResult.takeError()); 2552*5ffd940aSRaphael Isemann continue; 2553*5ffd940aSRaphael Isemann } 2554*5ffd940aSRaphael Isemann std::unique_ptr<Expression> Expression = std::move(*ExpressionResult); 2555*5ffd940aSRaphael Isemann // Now evaluate the expression whose value this variable should be set 2556*5ffd940aSRaphael Isemann // to, since the expression of a command-line variable definition should 2557*5ffd940aSRaphael Isemann // only use variables defined earlier on the command-line. If not, this 2558*5ffd940aSRaphael Isemann // is an error and we report it. 2559*5ffd940aSRaphael Isemann Expected<ExpressionValue> Value = Expression->getAST()->eval(); 2560*5ffd940aSRaphael Isemann if (!Value) { 2561*5ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), Value.takeError()); 2562*5ffd940aSRaphael Isemann continue; 2563*5ffd940aSRaphael Isemann } 2564*5ffd940aSRaphael Isemann 2565*5ffd940aSRaphael Isemann assert(DefinedNumericVariable && "No variable defined"); 2566*5ffd940aSRaphael Isemann (*DefinedNumericVariable)->setValue(*Value); 2567*5ffd940aSRaphael Isemann 2568*5ffd940aSRaphael Isemann // Record this variable definition. 2569*5ffd940aSRaphael Isemann GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] = 2570*5ffd940aSRaphael Isemann *DefinedNumericVariable; 2571*5ffd940aSRaphael Isemann } else { 2572*5ffd940aSRaphael Isemann // String variable definition. 2573*5ffd940aSRaphael Isemann std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('='); 2574*5ffd940aSRaphael Isemann StringRef CmdlineName = CmdlineNameVal.first; 2575*5ffd940aSRaphael Isemann StringRef OrigCmdlineName = CmdlineName; 2576*5ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> ParseVarResult = 2577*5ffd940aSRaphael Isemann Pattern::parseVariable(CmdlineName, SM); 2578*5ffd940aSRaphael Isemann if (!ParseVarResult) { 2579*5ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), ParseVarResult.takeError()); 2580*5ffd940aSRaphael Isemann continue; 2581*5ffd940aSRaphael Isemann } 2582*5ffd940aSRaphael Isemann // Check that CmdlineName does not denote a pseudo variable is only 2583*5ffd940aSRaphael Isemann // composed of the parsed numeric variable. This catches cases like 2584*5ffd940aSRaphael Isemann // "FOO+2" in a "FOO+2=10" definition. 2585*5ffd940aSRaphael Isemann if (ParseVarResult->IsPseudo || !CmdlineName.empty()) { 2586*5ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), 2587*5ffd940aSRaphael Isemann ErrorDiagnostic::get( 2588*5ffd940aSRaphael Isemann SM, OrigCmdlineName, 2589*5ffd940aSRaphael Isemann "invalid name in string variable definition '" + 2590*5ffd940aSRaphael Isemann OrigCmdlineName + "'")); 2591*5ffd940aSRaphael Isemann continue; 2592*5ffd940aSRaphael Isemann } 2593*5ffd940aSRaphael Isemann StringRef Name = ParseVarResult->Name; 2594*5ffd940aSRaphael Isemann 2595*5ffd940aSRaphael Isemann // Detect collisions between string and numeric variables when the former 2596*5ffd940aSRaphael Isemann // is created later than the latter. 2597*5ffd940aSRaphael Isemann if (GlobalNumericVariableTable.find(Name) != 2598*5ffd940aSRaphael Isemann GlobalNumericVariableTable.end()) { 2599*5ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), 2600*5ffd940aSRaphael Isemann ErrorDiagnostic::get(SM, Name, 2601*5ffd940aSRaphael Isemann "numeric variable with name '" + 2602*5ffd940aSRaphael Isemann Name + "' already exists")); 2603*5ffd940aSRaphael Isemann continue; 2604*5ffd940aSRaphael Isemann } 2605*5ffd940aSRaphael Isemann GlobalVariableTable.insert(CmdlineNameVal); 2606*5ffd940aSRaphael Isemann // Mark the string variable as defined to detect collisions between 2607*5ffd940aSRaphael Isemann // string and numeric variables in defineCmdlineVariables when the latter 2608*5ffd940aSRaphael Isemann // is created later than the former. We cannot reuse GlobalVariableTable 2609*5ffd940aSRaphael Isemann // for this by populating it with an empty string since we would then 2610*5ffd940aSRaphael Isemann // lose the ability to detect the use of an undefined variable in 2611*5ffd940aSRaphael Isemann // match(). 2612*5ffd940aSRaphael Isemann DefinedVariableTable[Name] = true; 2613*5ffd940aSRaphael Isemann } 2614*5ffd940aSRaphael Isemann } 2615*5ffd940aSRaphael Isemann 2616*5ffd940aSRaphael Isemann return Errs; 2617*5ffd940aSRaphael Isemann } 2618*5ffd940aSRaphael Isemann 2619*5ffd940aSRaphael Isemann void FileCheckPatternContext::clearLocalVars() { 2620*5ffd940aSRaphael Isemann SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars; 2621*5ffd940aSRaphael Isemann for (const StringMapEntry<StringRef> &Var : GlobalVariableTable) 2622*5ffd940aSRaphael Isemann if (Var.first()[0] != '$') 2623*5ffd940aSRaphael Isemann LocalPatternVars.push_back(Var.first()); 2624*5ffd940aSRaphael Isemann 2625*5ffd940aSRaphael Isemann // Numeric substitution reads the value of a variable directly, not via 2626*5ffd940aSRaphael Isemann // GlobalNumericVariableTable. Therefore, we clear local variables by 2627*5ffd940aSRaphael Isemann // clearing their value which will lead to a numeric substitution failure. We 2628*5ffd940aSRaphael Isemann // also mark the variable for removal from GlobalNumericVariableTable since 2629*5ffd940aSRaphael Isemann // this is what defineCmdlineVariables checks to decide that no global 2630*5ffd940aSRaphael Isemann // variable has been defined. 2631*5ffd940aSRaphael Isemann for (const auto &Var : GlobalNumericVariableTable) 2632*5ffd940aSRaphael Isemann if (Var.first()[0] != '$') { 2633*5ffd940aSRaphael Isemann Var.getValue()->clearValue(); 2634*5ffd940aSRaphael Isemann LocalNumericVars.push_back(Var.first()); 2635*5ffd940aSRaphael Isemann } 2636*5ffd940aSRaphael Isemann 2637*5ffd940aSRaphael Isemann for (const auto &Var : LocalPatternVars) 2638*5ffd940aSRaphael Isemann GlobalVariableTable.erase(Var); 2639*5ffd940aSRaphael Isemann for (const auto &Var : LocalNumericVars) 2640*5ffd940aSRaphael Isemann GlobalNumericVariableTable.erase(Var); 2641*5ffd940aSRaphael Isemann } 2642*5ffd940aSRaphael Isemann 2643*5ffd940aSRaphael Isemann bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer, 2644*5ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) { 2645*5ffd940aSRaphael Isemann bool ChecksFailed = false; 2646*5ffd940aSRaphael Isemann 2647*5ffd940aSRaphael Isemann unsigned i = 0, j = 0, e = CheckStrings->size(); 2648*5ffd940aSRaphael Isemann while (true) { 2649*5ffd940aSRaphael Isemann StringRef CheckRegion; 2650*5ffd940aSRaphael Isemann if (j == e) { 2651*5ffd940aSRaphael Isemann CheckRegion = Buffer; 2652*5ffd940aSRaphael Isemann } else { 2653*5ffd940aSRaphael Isemann const FileCheckString &CheckLabelStr = (*CheckStrings)[j]; 2654*5ffd940aSRaphael Isemann if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) { 2655*5ffd940aSRaphael Isemann ++j; 2656*5ffd940aSRaphael Isemann continue; 2657*5ffd940aSRaphael Isemann } 2658*5ffd940aSRaphael Isemann 2659*5ffd940aSRaphael Isemann // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG 2660*5ffd940aSRaphael Isemann size_t MatchLabelLen = 0; 2661*5ffd940aSRaphael Isemann size_t MatchLabelPos = 2662*5ffd940aSRaphael Isemann CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags); 2663*5ffd940aSRaphael Isemann if (MatchLabelPos == StringRef::npos) 2664*5ffd940aSRaphael Isemann // Immediately bail if CHECK-LABEL fails, nothing else we can do. 2665*5ffd940aSRaphael Isemann return false; 2666*5ffd940aSRaphael Isemann 2667*5ffd940aSRaphael Isemann CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen); 2668*5ffd940aSRaphael Isemann Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); 2669*5ffd940aSRaphael Isemann ++j; 2670*5ffd940aSRaphael Isemann } 2671*5ffd940aSRaphael Isemann 2672*5ffd940aSRaphael Isemann // Do not clear the first region as it's the one before the first 2673*5ffd940aSRaphael Isemann // CHECK-LABEL and it would clear variables defined on the command-line 2674*5ffd940aSRaphael Isemann // before they get used. 2675*5ffd940aSRaphael Isemann if (i != 0 && Req.EnableVarScope) 2676*5ffd940aSRaphael Isemann PatternContext->clearLocalVars(); 2677*5ffd940aSRaphael Isemann 2678*5ffd940aSRaphael Isemann for (; i != j; ++i) { 2679*5ffd940aSRaphael Isemann const FileCheckString &CheckStr = (*CheckStrings)[i]; 2680*5ffd940aSRaphael Isemann 2681*5ffd940aSRaphael Isemann // Check each string within the scanned region, including a second check 2682*5ffd940aSRaphael Isemann // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) 2683*5ffd940aSRaphael Isemann size_t MatchLen = 0; 2684*5ffd940aSRaphael Isemann size_t MatchPos = 2685*5ffd940aSRaphael Isemann CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags); 2686*5ffd940aSRaphael Isemann 2687*5ffd940aSRaphael Isemann if (MatchPos == StringRef::npos) { 2688*5ffd940aSRaphael Isemann ChecksFailed = true; 2689*5ffd940aSRaphael Isemann i = j; 2690*5ffd940aSRaphael Isemann break; 2691*5ffd940aSRaphael Isemann } 2692*5ffd940aSRaphael Isemann 2693*5ffd940aSRaphael Isemann CheckRegion = CheckRegion.substr(MatchPos + MatchLen); 2694*5ffd940aSRaphael Isemann } 2695*5ffd940aSRaphael Isemann 2696*5ffd940aSRaphael Isemann if (j == e) 2697*5ffd940aSRaphael Isemann break; 2698*5ffd940aSRaphael Isemann } 2699*5ffd940aSRaphael Isemann 2700*5ffd940aSRaphael Isemann // Success if no checks failed. 2701*5ffd940aSRaphael Isemann return !ChecksFailed; 2702*5ffd940aSRaphael Isemann } 2703