15ffd940aSRaphael Isemann //===- FileCheck.cpp - Check that File's Contents match what is expected --===// 25ffd940aSRaphael Isemann // 35ffd940aSRaphael Isemann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd940aSRaphael Isemann // See https://llvm.org/LICENSE.txt for license information. 55ffd940aSRaphael Isemann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd940aSRaphael Isemann // 75ffd940aSRaphael Isemann //===----------------------------------------------------------------------===// 85ffd940aSRaphael Isemann // 95ffd940aSRaphael Isemann // FileCheck does a line-by line check of a file that validates whether it 105ffd940aSRaphael Isemann // contains the expected content. This is useful for regression tests etc. 115ffd940aSRaphael Isemann // 125ffd940aSRaphael Isemann // This file implements most of the API that will be used by the FileCheck utility 135ffd940aSRaphael Isemann // as well as various unittests. 145ffd940aSRaphael Isemann //===----------------------------------------------------------------------===// 155ffd940aSRaphael Isemann 165ffd940aSRaphael Isemann #include "llvm/FileCheck/FileCheck.h" 175ffd940aSRaphael Isemann #include "FileCheckImpl.h" 185ffd940aSRaphael Isemann #include "llvm/ADT/STLExtras.h" 195ffd940aSRaphael Isemann #include "llvm/ADT/StringSet.h" 205ffd940aSRaphael Isemann #include "llvm/ADT/Twine.h" 215ffd940aSRaphael Isemann #include "llvm/Support/CheckedArithmetic.h" 225ffd940aSRaphael Isemann #include "llvm/Support/FormatVariadic.h" 235ffd940aSRaphael Isemann #include <cstdint> 245ffd940aSRaphael Isemann #include <list> 25871d658cSMircea Trofin #include <set> 265ffd940aSRaphael Isemann #include <tuple> 275ffd940aSRaphael Isemann #include <utility> 285ffd940aSRaphael Isemann 295ffd940aSRaphael Isemann using namespace llvm; 305ffd940aSRaphael Isemann 315ffd940aSRaphael Isemann StringRef ExpressionFormat::toString() const { 325ffd940aSRaphael Isemann switch (Value) { 335ffd940aSRaphael Isemann case Kind::NoFormat: 345ffd940aSRaphael Isemann return StringRef("<none>"); 355ffd940aSRaphael Isemann case Kind::Unsigned: 365ffd940aSRaphael Isemann return StringRef("%u"); 375ffd940aSRaphael Isemann case Kind::Signed: 385ffd940aSRaphael Isemann return StringRef("%d"); 395ffd940aSRaphael Isemann case Kind::HexUpper: 405ffd940aSRaphael Isemann return StringRef("%X"); 415ffd940aSRaphael Isemann case Kind::HexLower: 425ffd940aSRaphael Isemann return StringRef("%x"); 435ffd940aSRaphael Isemann } 445ffd940aSRaphael Isemann llvm_unreachable("unknown expression format"); 455ffd940aSRaphael Isemann } 465ffd940aSRaphael Isemann 475ffd940aSRaphael Isemann Expected<std::string> ExpressionFormat::getWildcardRegex() const { 48f9e2a62cSThomas Preud'homme StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef(); 49f9e2a62cSThomas Preud'homme 50f9e2a62cSThomas Preud'homme auto CreatePrecisionRegex = [&](StringRef S) { 51f9e2a62cSThomas Preud'homme return (Twine(AlternateFormPrefix) + S + Twine('{') + Twine(Precision) + 52f9e2a62cSThomas Preud'homme "}") 53f9e2a62cSThomas Preud'homme .str(); 545ffd940aSRaphael Isemann }; 555ffd940aSRaphael Isemann 565ffd940aSRaphael Isemann switch (Value) { 575ffd940aSRaphael Isemann case Kind::Unsigned: 585ffd940aSRaphael Isemann if (Precision) 595ffd940aSRaphael Isemann return CreatePrecisionRegex("([1-9][0-9]*)?[0-9]"); 605ffd940aSRaphael Isemann return std::string("[0-9]+"); 615ffd940aSRaphael Isemann case Kind::Signed: 625ffd940aSRaphael Isemann if (Precision) 635ffd940aSRaphael Isemann return CreatePrecisionRegex("-?([1-9][0-9]*)?[0-9]"); 645ffd940aSRaphael Isemann return std::string("-?[0-9]+"); 655ffd940aSRaphael Isemann case Kind::HexUpper: 665ffd940aSRaphael Isemann if (Precision) 675ffd940aSRaphael Isemann return CreatePrecisionRegex("([1-9A-F][0-9A-F]*)?[0-9A-F]"); 68f9e2a62cSThomas Preud'homme return (Twine(AlternateFormPrefix) + Twine("[0-9A-F]+")).str(); 695ffd940aSRaphael Isemann case Kind::HexLower: 705ffd940aSRaphael Isemann if (Precision) 715ffd940aSRaphael Isemann return CreatePrecisionRegex("([1-9a-f][0-9a-f]*)?[0-9a-f]"); 72f9e2a62cSThomas Preud'homme return (Twine(AlternateFormPrefix) + Twine("[0-9a-f]+")).str(); 735ffd940aSRaphael Isemann default: 745ffd940aSRaphael Isemann return createStringError(std::errc::invalid_argument, 755ffd940aSRaphael Isemann "trying to match value with invalid format"); 765ffd940aSRaphael Isemann } 775ffd940aSRaphael Isemann } 785ffd940aSRaphael Isemann 795ffd940aSRaphael Isemann Expected<std::string> 805ffd940aSRaphael Isemann ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const { 815ffd940aSRaphael Isemann uint64_t AbsoluteValue; 825ffd940aSRaphael Isemann StringRef SignPrefix = IntegerValue.isNegative() ? "-" : ""; 835ffd940aSRaphael Isemann 845ffd940aSRaphael Isemann if (Value == Kind::Signed) { 855ffd940aSRaphael Isemann Expected<int64_t> SignedValue = IntegerValue.getSignedValue(); 865ffd940aSRaphael Isemann if (!SignedValue) 875ffd940aSRaphael Isemann return SignedValue.takeError(); 885ffd940aSRaphael Isemann if (*SignedValue < 0) 895ffd940aSRaphael Isemann AbsoluteValue = cantFail(IntegerValue.getAbsolute().getUnsignedValue()); 905ffd940aSRaphael Isemann else 915ffd940aSRaphael Isemann AbsoluteValue = *SignedValue; 925ffd940aSRaphael Isemann } else { 935ffd940aSRaphael Isemann Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue(); 945ffd940aSRaphael Isemann if (!UnsignedValue) 955ffd940aSRaphael Isemann return UnsignedValue.takeError(); 965ffd940aSRaphael Isemann AbsoluteValue = *UnsignedValue; 975ffd940aSRaphael Isemann } 985ffd940aSRaphael Isemann 995ffd940aSRaphael Isemann std::string AbsoluteValueStr; 1005ffd940aSRaphael Isemann switch (Value) { 1015ffd940aSRaphael Isemann case Kind::Unsigned: 1025ffd940aSRaphael Isemann case Kind::Signed: 1035ffd940aSRaphael Isemann AbsoluteValueStr = utostr(AbsoluteValue); 1045ffd940aSRaphael Isemann break; 1055ffd940aSRaphael Isemann case Kind::HexUpper: 1065ffd940aSRaphael Isemann case Kind::HexLower: 1075ffd940aSRaphael Isemann AbsoluteValueStr = utohexstr(AbsoluteValue, Value == Kind::HexLower); 1085ffd940aSRaphael Isemann break; 1095ffd940aSRaphael Isemann default: 1105ffd940aSRaphael Isemann return createStringError(std::errc::invalid_argument, 1115ffd940aSRaphael Isemann "trying to match value with invalid format"); 1125ffd940aSRaphael Isemann } 1135ffd940aSRaphael Isemann 114f9e2a62cSThomas Preud'homme StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef(); 115f9e2a62cSThomas Preud'homme 1165ffd940aSRaphael Isemann if (Precision > AbsoluteValueStr.size()) { 1175ffd940aSRaphael Isemann unsigned LeadingZeros = Precision - AbsoluteValueStr.size(); 118f9e2a62cSThomas Preud'homme return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + 119f9e2a62cSThomas Preud'homme std::string(LeadingZeros, '0') + AbsoluteValueStr) 1205ffd940aSRaphael Isemann .str(); 1215ffd940aSRaphael Isemann } 1225ffd940aSRaphael Isemann 123f9e2a62cSThomas Preud'homme return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + AbsoluteValueStr) 124f9e2a62cSThomas Preud'homme .str(); 1255ffd940aSRaphael Isemann } 1265ffd940aSRaphael Isemann 1275ffd940aSRaphael Isemann Expected<ExpressionValue> 1285ffd940aSRaphael Isemann ExpressionFormat::valueFromStringRepr(StringRef StrVal, 1295ffd940aSRaphael Isemann const SourceMgr &SM) const { 1305ffd940aSRaphael Isemann bool ValueIsSigned = Value == Kind::Signed; 131c347619bSThomas Preud'homme // Both the FileCheck utility and library only call this method with a valid 132c347619bSThomas Preud'homme // value in StrVal. This is guaranteed by the regex returned by 133c347619bSThomas Preud'homme // getWildcardRegex() above. Only underflow and overflow errors can thus 134c347619bSThomas Preud'homme // occur. However new uses of this method could be added in the future so 135c347619bSThomas Preud'homme // the error message does not make assumptions about StrVal. 136c347619bSThomas Preud'homme StringRef IntegerParseErrorStr = "unable to represent numeric value"; 1375ffd940aSRaphael Isemann if (ValueIsSigned) { 1385ffd940aSRaphael Isemann int64_t SignedValue; 1395ffd940aSRaphael Isemann 1405ffd940aSRaphael Isemann if (StrVal.getAsInteger(10, SignedValue)) 141c347619bSThomas Preud'homme return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); 1425ffd940aSRaphael Isemann 1435ffd940aSRaphael Isemann return ExpressionValue(SignedValue); 1445ffd940aSRaphael Isemann } 1455ffd940aSRaphael Isemann 1465ffd940aSRaphael Isemann bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower; 1475ffd940aSRaphael Isemann uint64_t UnsignedValue; 148f9e2a62cSThomas Preud'homme bool MissingFormPrefix = AlternateForm && !StrVal.consume_front("0x"); 1495ffd940aSRaphael Isemann if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue)) 150c347619bSThomas Preud'homme return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); 1515ffd940aSRaphael Isemann 152f9e2a62cSThomas Preud'homme // Error out for a missing prefix only now that we know we have an otherwise 153f9e2a62cSThomas Preud'homme // valid integer. For example, "-0x18" is reported above instead. 154f9e2a62cSThomas Preud'homme if (MissingFormPrefix) 155f9e2a62cSThomas Preud'homme return ErrorDiagnostic::get(SM, StrVal, "missing alternate form prefix"); 156f9e2a62cSThomas Preud'homme 1575ffd940aSRaphael Isemann return ExpressionValue(UnsignedValue); 1585ffd940aSRaphael Isemann } 1595ffd940aSRaphael Isemann 1605ffd940aSRaphael Isemann static int64_t getAsSigned(uint64_t UnsignedValue) { 1615ffd940aSRaphael Isemann // Use memcpy to reinterpret the bitpattern in Value since casting to 1625ffd940aSRaphael Isemann // signed is implementation-defined if the unsigned value is too big to be 1635ffd940aSRaphael Isemann // represented in the signed type and using an union violates type aliasing 1645ffd940aSRaphael Isemann // rules. 1655ffd940aSRaphael Isemann int64_t SignedValue; 1665ffd940aSRaphael Isemann memcpy(&SignedValue, &UnsignedValue, sizeof(SignedValue)); 1675ffd940aSRaphael Isemann return SignedValue; 1685ffd940aSRaphael Isemann } 1695ffd940aSRaphael Isemann 1705ffd940aSRaphael Isemann Expected<int64_t> ExpressionValue::getSignedValue() const { 1715ffd940aSRaphael Isemann if (Negative) 1725ffd940aSRaphael Isemann return getAsSigned(Value); 1735ffd940aSRaphael Isemann 1745ffd940aSRaphael Isemann if (Value > (uint64_t)std::numeric_limits<int64_t>::max()) 1755ffd940aSRaphael Isemann return make_error<OverflowError>(); 1765ffd940aSRaphael Isemann 1775ffd940aSRaphael Isemann // Value is in the representable range of int64_t so we can use cast. 1785ffd940aSRaphael Isemann return static_cast<int64_t>(Value); 1795ffd940aSRaphael Isemann } 1805ffd940aSRaphael Isemann 1815ffd940aSRaphael Isemann Expected<uint64_t> ExpressionValue::getUnsignedValue() const { 1825ffd940aSRaphael Isemann if (Negative) 1835ffd940aSRaphael Isemann return make_error<OverflowError>(); 1845ffd940aSRaphael Isemann 1855ffd940aSRaphael Isemann return Value; 1865ffd940aSRaphael Isemann } 1875ffd940aSRaphael Isemann 1885ffd940aSRaphael Isemann ExpressionValue ExpressionValue::getAbsolute() const { 1895ffd940aSRaphael Isemann if (!Negative) 1905ffd940aSRaphael Isemann return *this; 1915ffd940aSRaphael Isemann 1925ffd940aSRaphael Isemann int64_t SignedValue = getAsSigned(Value); 1935ffd940aSRaphael Isemann int64_t MaxInt64 = std::numeric_limits<int64_t>::max(); 1945ffd940aSRaphael Isemann // Absolute value can be represented as int64_t. 1955ffd940aSRaphael Isemann if (SignedValue >= -MaxInt64) 1965ffd940aSRaphael Isemann return ExpressionValue(-getAsSigned(Value)); 1975ffd940aSRaphael Isemann 1985ffd940aSRaphael Isemann // -X == -(max int64_t + Rem), negate each component independently. 1995ffd940aSRaphael Isemann SignedValue += MaxInt64; 2005ffd940aSRaphael Isemann uint64_t RemainingValueAbsolute = -SignedValue; 2015ffd940aSRaphael Isemann return ExpressionValue(MaxInt64 + RemainingValueAbsolute); 2025ffd940aSRaphael Isemann } 2035ffd940aSRaphael Isemann 2045ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand, 2055ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 2065ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) { 2075ffd940aSRaphael Isemann int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 2085ffd940aSRaphael Isemann int64_t RightValue = cantFail(RightOperand.getSignedValue()); 2095ffd940aSRaphael Isemann Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue); 2105ffd940aSRaphael Isemann if (!Result) 2115ffd940aSRaphael Isemann return make_error<OverflowError>(); 2125ffd940aSRaphael Isemann 2135ffd940aSRaphael Isemann return ExpressionValue(*Result); 2145ffd940aSRaphael Isemann } 2155ffd940aSRaphael Isemann 2165ffd940aSRaphael Isemann // (-A) + B == B - A. 2175ffd940aSRaphael Isemann if (LeftOperand.isNegative()) 2185ffd940aSRaphael Isemann return RightOperand - LeftOperand.getAbsolute(); 2195ffd940aSRaphael Isemann 2205ffd940aSRaphael Isemann // A + (-B) == A - B. 2215ffd940aSRaphael Isemann if (RightOperand.isNegative()) 2225ffd940aSRaphael Isemann return LeftOperand - RightOperand.getAbsolute(); 2235ffd940aSRaphael Isemann 2245ffd940aSRaphael Isemann // Both values are positive at this point. 2255ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 2265ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 2275ffd940aSRaphael Isemann Optional<uint64_t> Result = 2285ffd940aSRaphael Isemann checkedAddUnsigned<uint64_t>(LeftValue, RightValue); 2295ffd940aSRaphael Isemann if (!Result) 2305ffd940aSRaphael Isemann return make_error<OverflowError>(); 2315ffd940aSRaphael Isemann 2325ffd940aSRaphael Isemann return ExpressionValue(*Result); 2335ffd940aSRaphael Isemann } 2345ffd940aSRaphael Isemann 2355ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand, 2365ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 2375ffd940aSRaphael Isemann // Result will be negative and thus might underflow. 2385ffd940aSRaphael Isemann if (LeftOperand.isNegative() && !RightOperand.isNegative()) { 2395ffd940aSRaphael Isemann int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 2405ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 2415ffd940aSRaphael Isemann // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement. 2425ffd940aSRaphael Isemann if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max()) 2435ffd940aSRaphael Isemann return make_error<OverflowError>(); 2445ffd940aSRaphael Isemann Optional<int64_t> Result = 2455ffd940aSRaphael Isemann checkedSub(LeftValue, static_cast<int64_t>(RightValue)); 2465ffd940aSRaphael Isemann if (!Result) 2475ffd940aSRaphael Isemann return make_error<OverflowError>(); 2485ffd940aSRaphael Isemann 2495ffd940aSRaphael Isemann return ExpressionValue(*Result); 2505ffd940aSRaphael Isemann } 2515ffd940aSRaphael Isemann 2525ffd940aSRaphael Isemann // (-A) - (-B) == B - A. 2535ffd940aSRaphael Isemann if (LeftOperand.isNegative()) 2545ffd940aSRaphael Isemann return RightOperand.getAbsolute() - LeftOperand.getAbsolute(); 2555ffd940aSRaphael Isemann 2565ffd940aSRaphael Isemann // A - (-B) == A + B. 2575ffd940aSRaphael Isemann if (RightOperand.isNegative()) 2585ffd940aSRaphael Isemann return LeftOperand + RightOperand.getAbsolute(); 2595ffd940aSRaphael Isemann 2605ffd940aSRaphael Isemann // Both values are positive at this point. 2615ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 2625ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 2635ffd940aSRaphael Isemann if (LeftValue >= RightValue) 2645ffd940aSRaphael Isemann return ExpressionValue(LeftValue - RightValue); 2655ffd940aSRaphael Isemann else { 2665ffd940aSRaphael Isemann uint64_t AbsoluteDifference = RightValue - LeftValue; 2675ffd940aSRaphael Isemann uint64_t MaxInt64 = std::numeric_limits<int64_t>::max(); 2685ffd940aSRaphael Isemann // Value might underflow. 2695ffd940aSRaphael Isemann if (AbsoluteDifference > MaxInt64) { 2705ffd940aSRaphael Isemann AbsoluteDifference -= MaxInt64; 2715ffd940aSRaphael Isemann int64_t Result = -MaxInt64; 2725ffd940aSRaphael Isemann int64_t MinInt64 = std::numeric_limits<int64_t>::min(); 2735ffd940aSRaphael Isemann // Underflow, tested by: 2745ffd940aSRaphael Isemann // abs(Result + (max int64_t)) > abs((min int64_t) + (max int64_t)) 2755ffd940aSRaphael Isemann if (AbsoluteDifference > static_cast<uint64_t>(-(MinInt64 - Result))) 2765ffd940aSRaphael Isemann return make_error<OverflowError>(); 2775ffd940aSRaphael Isemann Result -= static_cast<int64_t>(AbsoluteDifference); 2785ffd940aSRaphael Isemann return ExpressionValue(Result); 2795ffd940aSRaphael Isemann } 2805ffd940aSRaphael Isemann 2815ffd940aSRaphael Isemann return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference)); 2825ffd940aSRaphael Isemann } 2835ffd940aSRaphael Isemann } 2845ffd940aSRaphael Isemann 2855ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand, 2865ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 2875ffd940aSRaphael Isemann // -A * -B == A * B 2885ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) 2895ffd940aSRaphael Isemann return LeftOperand.getAbsolute() * RightOperand.getAbsolute(); 2905ffd940aSRaphael Isemann 2915ffd940aSRaphael Isemann // A * -B == -B * A 2925ffd940aSRaphael Isemann if (RightOperand.isNegative()) 2935ffd940aSRaphael Isemann return RightOperand * LeftOperand; 2945ffd940aSRaphael Isemann 2955ffd940aSRaphael Isemann assert(!RightOperand.isNegative() && "Unexpected negative operand!"); 2965ffd940aSRaphael Isemann 2975ffd940aSRaphael Isemann // Result will be negative and can underflow. 2985ffd940aSRaphael Isemann if (LeftOperand.isNegative()) { 2995ffd940aSRaphael Isemann auto Result = LeftOperand.getAbsolute() * RightOperand.getAbsolute(); 3005ffd940aSRaphael Isemann if (!Result) 3015ffd940aSRaphael Isemann return Result; 3025ffd940aSRaphael Isemann 3035ffd940aSRaphael Isemann return ExpressionValue(0) - *Result; 3045ffd940aSRaphael Isemann } 3055ffd940aSRaphael Isemann 3065ffd940aSRaphael Isemann // Result will be positive and can overflow. 3075ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 3085ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 3095ffd940aSRaphael Isemann Optional<uint64_t> Result = 3105ffd940aSRaphael Isemann checkedMulUnsigned<uint64_t>(LeftValue, RightValue); 3115ffd940aSRaphael Isemann if (!Result) 3125ffd940aSRaphael Isemann return make_error<OverflowError>(); 3135ffd940aSRaphael Isemann 3145ffd940aSRaphael Isemann return ExpressionValue(*Result); 3155ffd940aSRaphael Isemann } 3165ffd940aSRaphael Isemann 3175ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand, 3185ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 3195ffd940aSRaphael Isemann // -A / -B == A / B 3205ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) 3215ffd940aSRaphael Isemann return LeftOperand.getAbsolute() / RightOperand.getAbsolute(); 3225ffd940aSRaphael Isemann 3235ffd940aSRaphael Isemann // Check for divide by zero. 3245ffd940aSRaphael Isemann if (RightOperand == ExpressionValue(0)) 3255ffd940aSRaphael Isemann return make_error<OverflowError>(); 3265ffd940aSRaphael Isemann 3275ffd940aSRaphael Isemann // Result will be negative and can underflow. 3285ffd940aSRaphael Isemann if (LeftOperand.isNegative() || RightOperand.isNegative()) 3295ffd940aSRaphael Isemann return ExpressionValue(0) - 3305ffd940aSRaphael Isemann cantFail(LeftOperand.getAbsolute() / RightOperand.getAbsolute()); 3315ffd940aSRaphael Isemann 3325ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 3335ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 3345ffd940aSRaphael Isemann return ExpressionValue(LeftValue / RightValue); 3355ffd940aSRaphael Isemann } 3365ffd940aSRaphael Isemann 3375ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand, 3385ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 3395ffd940aSRaphael Isemann if (LeftOperand.isNegative() && RightOperand.isNegative()) { 3405ffd940aSRaphael Isemann int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); 3415ffd940aSRaphael Isemann int64_t RightValue = cantFail(RightOperand.getSignedValue()); 3425ffd940aSRaphael Isemann return ExpressionValue(std::max(LeftValue, RightValue)); 3435ffd940aSRaphael Isemann } 3445ffd940aSRaphael Isemann 3455ffd940aSRaphael Isemann if (!LeftOperand.isNegative() && !RightOperand.isNegative()) { 3465ffd940aSRaphael Isemann uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); 3475ffd940aSRaphael Isemann uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); 3485ffd940aSRaphael Isemann return ExpressionValue(std::max(LeftValue, RightValue)); 3495ffd940aSRaphael Isemann } 3505ffd940aSRaphael Isemann 3515ffd940aSRaphael Isemann if (LeftOperand.isNegative()) 3525ffd940aSRaphael Isemann return RightOperand; 3535ffd940aSRaphael Isemann 3545ffd940aSRaphael Isemann return LeftOperand; 3555ffd940aSRaphael Isemann } 3565ffd940aSRaphael Isemann 3575ffd940aSRaphael Isemann Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand, 3585ffd940aSRaphael Isemann const ExpressionValue &RightOperand) { 3595ffd940aSRaphael Isemann if (cantFail(max(LeftOperand, RightOperand)) == LeftOperand) 3605ffd940aSRaphael Isemann return RightOperand; 3615ffd940aSRaphael Isemann 3625ffd940aSRaphael Isemann return LeftOperand; 3635ffd940aSRaphael Isemann } 3645ffd940aSRaphael Isemann 3655ffd940aSRaphael Isemann Expected<ExpressionValue> NumericVariableUse::eval() const { 3665ffd940aSRaphael Isemann Optional<ExpressionValue> Value = Variable->getValue(); 3675ffd940aSRaphael Isemann if (Value) 3685ffd940aSRaphael Isemann return *Value; 3695ffd940aSRaphael Isemann 3705ffd940aSRaphael Isemann return make_error<UndefVarError>(getExpressionStr()); 3715ffd940aSRaphael Isemann } 3725ffd940aSRaphael Isemann 3735ffd940aSRaphael Isemann Expected<ExpressionValue> BinaryOperation::eval() const { 3745ffd940aSRaphael Isemann Expected<ExpressionValue> LeftOp = LeftOperand->eval(); 3755ffd940aSRaphael Isemann Expected<ExpressionValue> RightOp = RightOperand->eval(); 3765ffd940aSRaphael Isemann 3775ffd940aSRaphael Isemann // Bubble up any error (e.g. undefined variables) in the recursive 3785ffd940aSRaphael Isemann // evaluation. 3795ffd940aSRaphael Isemann if (!LeftOp || !RightOp) { 3805ffd940aSRaphael Isemann Error Err = Error::success(); 3815ffd940aSRaphael Isemann if (!LeftOp) 3825ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), LeftOp.takeError()); 3835ffd940aSRaphael Isemann if (!RightOp) 3845ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), RightOp.takeError()); 3855ffd940aSRaphael Isemann return std::move(Err); 3865ffd940aSRaphael Isemann } 3875ffd940aSRaphael Isemann 3885ffd940aSRaphael Isemann return EvalBinop(*LeftOp, *RightOp); 3895ffd940aSRaphael Isemann } 3905ffd940aSRaphael Isemann 3915ffd940aSRaphael Isemann Expected<ExpressionFormat> 3925ffd940aSRaphael Isemann BinaryOperation::getImplicitFormat(const SourceMgr &SM) const { 3935ffd940aSRaphael Isemann Expected<ExpressionFormat> LeftFormat = LeftOperand->getImplicitFormat(SM); 3945ffd940aSRaphael Isemann Expected<ExpressionFormat> RightFormat = RightOperand->getImplicitFormat(SM); 3955ffd940aSRaphael Isemann if (!LeftFormat || !RightFormat) { 3965ffd940aSRaphael Isemann Error Err = Error::success(); 3975ffd940aSRaphael Isemann if (!LeftFormat) 3985ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), LeftFormat.takeError()); 3995ffd940aSRaphael Isemann if (!RightFormat) 4005ffd940aSRaphael Isemann Err = joinErrors(std::move(Err), RightFormat.takeError()); 4015ffd940aSRaphael Isemann return std::move(Err); 4025ffd940aSRaphael Isemann } 4035ffd940aSRaphael Isemann 4045ffd940aSRaphael Isemann if (*LeftFormat != ExpressionFormat::Kind::NoFormat && 4055ffd940aSRaphael Isemann *RightFormat != ExpressionFormat::Kind::NoFormat && 4065ffd940aSRaphael Isemann *LeftFormat != *RightFormat) 4075ffd940aSRaphael Isemann return ErrorDiagnostic::get( 4085ffd940aSRaphael Isemann SM, getExpressionStr(), 4095ffd940aSRaphael Isemann "implicit format conflict between '" + LeftOperand->getExpressionStr() + 4105ffd940aSRaphael Isemann "' (" + LeftFormat->toString() + ") and '" + 4115ffd940aSRaphael Isemann RightOperand->getExpressionStr() + "' (" + RightFormat->toString() + 4125ffd940aSRaphael Isemann "), need an explicit format specifier"); 4135ffd940aSRaphael Isemann 4145ffd940aSRaphael Isemann return *LeftFormat != ExpressionFormat::Kind::NoFormat ? *LeftFormat 4155ffd940aSRaphael Isemann : *RightFormat; 4165ffd940aSRaphael Isemann } 4175ffd940aSRaphael Isemann 4185ffd940aSRaphael Isemann Expected<std::string> NumericSubstitution::getResult() const { 4195ffd940aSRaphael Isemann assert(ExpressionPointer->getAST() != nullptr && 4205ffd940aSRaphael Isemann "Substituting empty expression"); 4215ffd940aSRaphael Isemann Expected<ExpressionValue> EvaluatedValue = 4225ffd940aSRaphael Isemann ExpressionPointer->getAST()->eval(); 4235ffd940aSRaphael Isemann if (!EvaluatedValue) 4245ffd940aSRaphael Isemann return EvaluatedValue.takeError(); 4255ffd940aSRaphael Isemann ExpressionFormat Format = ExpressionPointer->getFormat(); 4265ffd940aSRaphael Isemann return Format.getMatchingString(*EvaluatedValue); 4275ffd940aSRaphael Isemann } 4285ffd940aSRaphael Isemann 4295ffd940aSRaphael Isemann Expected<std::string> StringSubstitution::getResult() const { 4305ffd940aSRaphael Isemann // Look up the value and escape it so that we can put it into the regex. 4315ffd940aSRaphael Isemann Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr); 4325ffd940aSRaphael Isemann if (!VarVal) 4335ffd940aSRaphael Isemann return VarVal.takeError(); 4345ffd940aSRaphael Isemann return Regex::escape(*VarVal); 4355ffd940aSRaphael Isemann } 4365ffd940aSRaphael Isemann 4375ffd940aSRaphael Isemann bool Pattern::isValidVarNameStart(char C) { return C == '_' || isAlpha(C); } 4385ffd940aSRaphael Isemann 4395ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> 4405ffd940aSRaphael Isemann Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) { 4415ffd940aSRaphael Isemann if (Str.empty()) 4425ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Str, "empty variable name"); 4435ffd940aSRaphael Isemann 4445ffd940aSRaphael Isemann size_t I = 0; 4455ffd940aSRaphael Isemann bool IsPseudo = Str[0] == '@'; 4465ffd940aSRaphael Isemann 4475ffd940aSRaphael Isemann // Global vars start with '$'. 4485ffd940aSRaphael Isemann if (Str[0] == '$' || IsPseudo) 4495ffd940aSRaphael Isemann ++I; 4505ffd940aSRaphael Isemann 4515ffd940aSRaphael Isemann if (!isValidVarNameStart(Str[I++])) 4525ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Str, "invalid variable name"); 4535ffd940aSRaphael Isemann 4545ffd940aSRaphael Isemann for (size_t E = Str.size(); I != E; ++I) 4555ffd940aSRaphael Isemann // Variable names are composed of alphanumeric characters and underscores. 4565ffd940aSRaphael Isemann if (Str[I] != '_' && !isAlnum(Str[I])) 4575ffd940aSRaphael Isemann break; 4585ffd940aSRaphael Isemann 4595ffd940aSRaphael Isemann StringRef Name = Str.take_front(I); 4605ffd940aSRaphael Isemann Str = Str.substr(I); 4615ffd940aSRaphael Isemann return VariableProperties {Name, IsPseudo}; 4625ffd940aSRaphael Isemann } 4635ffd940aSRaphael Isemann 4645ffd940aSRaphael Isemann // StringRef holding all characters considered as horizontal whitespaces by 4655ffd940aSRaphael Isemann // FileCheck input canonicalization. 4665ffd940aSRaphael Isemann constexpr StringLiteral SpaceChars = " \t"; 4675ffd940aSRaphael Isemann 4685ffd940aSRaphael Isemann // Parsing helper function that strips the first character in S and returns it. 4695ffd940aSRaphael Isemann static char popFront(StringRef &S) { 4705ffd940aSRaphael Isemann char C = S.front(); 4715ffd940aSRaphael Isemann S = S.drop_front(); 4725ffd940aSRaphael Isemann return C; 4735ffd940aSRaphael Isemann } 4745ffd940aSRaphael Isemann 4755ffd940aSRaphael Isemann char OverflowError::ID = 0; 4765ffd940aSRaphael Isemann char UndefVarError::ID = 0; 4775ffd940aSRaphael Isemann char ErrorDiagnostic::ID = 0; 4785ffd940aSRaphael Isemann char NotFoundError::ID = 0; 479*dd59c132SJoel E. Denny char ErrorReported::ID = 0; 4805ffd940aSRaphael Isemann 4815ffd940aSRaphael Isemann Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( 4825ffd940aSRaphael Isemann StringRef &Expr, FileCheckPatternContext *Context, 4835ffd940aSRaphael Isemann Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat, 4845ffd940aSRaphael Isemann const SourceMgr &SM) { 4855ffd940aSRaphael Isemann Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM); 4865ffd940aSRaphael Isemann if (!ParseVarResult) 4875ffd940aSRaphael Isemann return ParseVarResult.takeError(); 4885ffd940aSRaphael Isemann StringRef Name = ParseVarResult->Name; 4895ffd940aSRaphael Isemann 4905ffd940aSRaphael Isemann if (ParseVarResult->IsPseudo) 4915ffd940aSRaphael Isemann return ErrorDiagnostic::get( 4925ffd940aSRaphael Isemann SM, Name, "definition of pseudo numeric variable unsupported"); 4935ffd940aSRaphael Isemann 4945ffd940aSRaphael Isemann // Detect collisions between string and numeric variables when the latter 4955ffd940aSRaphael Isemann // is created later than the former. 4965ffd940aSRaphael Isemann if (Context->DefinedVariableTable.find(Name) != 4975ffd940aSRaphael Isemann Context->DefinedVariableTable.end()) 4985ffd940aSRaphael Isemann return ErrorDiagnostic::get( 4995ffd940aSRaphael Isemann SM, Name, "string variable with name '" + Name + "' already exists"); 5005ffd940aSRaphael Isemann 5015ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 5025ffd940aSRaphael Isemann if (!Expr.empty()) 5035ffd940aSRaphael Isemann return ErrorDiagnostic::get( 5045ffd940aSRaphael Isemann SM, Expr, "unexpected characters after numeric variable name"); 5055ffd940aSRaphael Isemann 5065ffd940aSRaphael Isemann NumericVariable *DefinedNumericVariable; 5075ffd940aSRaphael Isemann auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); 5085ffd940aSRaphael Isemann if (VarTableIter != Context->GlobalNumericVariableTable.end()) { 5095ffd940aSRaphael Isemann DefinedNumericVariable = VarTableIter->second; 5105ffd940aSRaphael Isemann if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat) 5115ffd940aSRaphael Isemann return ErrorDiagnostic::get( 5125ffd940aSRaphael Isemann SM, Expr, "format different from previous variable definition"); 5135ffd940aSRaphael Isemann } else 5145ffd940aSRaphael Isemann DefinedNumericVariable = 5155ffd940aSRaphael Isemann Context->makeNumericVariable(Name, ImplicitFormat, LineNumber); 5165ffd940aSRaphael Isemann 5175ffd940aSRaphael Isemann return DefinedNumericVariable; 5185ffd940aSRaphael Isemann } 5195ffd940aSRaphael Isemann 5205ffd940aSRaphael Isemann Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( 5215ffd940aSRaphael Isemann StringRef Name, bool IsPseudo, Optional<size_t> LineNumber, 5225ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 5235ffd940aSRaphael Isemann if (IsPseudo && !Name.equals("@LINE")) 5245ffd940aSRaphael Isemann return ErrorDiagnostic::get( 5255ffd940aSRaphael Isemann SM, Name, "invalid pseudo numeric variable '" + Name + "'"); 5265ffd940aSRaphael Isemann 5275ffd940aSRaphael Isemann // Numeric variable definitions and uses are parsed in the order in which 5285ffd940aSRaphael Isemann // they appear in the CHECK patterns. For each definition, the pointer to the 5295ffd940aSRaphael Isemann // class instance of the corresponding numeric variable definition is stored 5305ffd940aSRaphael Isemann // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer 5315ffd940aSRaphael Isemann // we get below is null, it means no such variable was defined before. When 5325ffd940aSRaphael Isemann // that happens, we create a dummy variable so that parsing can continue. All 5335ffd940aSRaphael Isemann // uses of undefined variables, whether string or numeric, are then diagnosed 5345ffd940aSRaphael Isemann // in printSubstitutions() after failing to match. 5355ffd940aSRaphael Isemann auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); 5365ffd940aSRaphael Isemann NumericVariable *NumericVariable; 5375ffd940aSRaphael Isemann if (VarTableIter != Context->GlobalNumericVariableTable.end()) 5385ffd940aSRaphael Isemann NumericVariable = VarTableIter->second; 5395ffd940aSRaphael Isemann else { 5405ffd940aSRaphael Isemann NumericVariable = Context->makeNumericVariable( 5415ffd940aSRaphael Isemann Name, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); 5425ffd940aSRaphael Isemann Context->GlobalNumericVariableTable[Name] = NumericVariable; 5435ffd940aSRaphael Isemann } 5445ffd940aSRaphael Isemann 5455ffd940aSRaphael Isemann Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber(); 5465ffd940aSRaphael Isemann if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber) 5475ffd940aSRaphael Isemann return ErrorDiagnostic::get( 5485ffd940aSRaphael Isemann SM, Name, 5495ffd940aSRaphael Isemann "numeric variable '" + Name + 5505ffd940aSRaphael Isemann "' defined earlier in the same CHECK directive"); 5515ffd940aSRaphael Isemann 5525ffd940aSRaphael Isemann return std::make_unique<NumericVariableUse>(Name, NumericVariable); 5535ffd940aSRaphael Isemann } 5545ffd940aSRaphael Isemann 5555ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand( 5565ffd940aSRaphael Isemann StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint, 5575ffd940aSRaphael Isemann Optional<size_t> LineNumber, FileCheckPatternContext *Context, 5585ffd940aSRaphael Isemann const SourceMgr &SM) { 5595ffd940aSRaphael Isemann if (Expr.startswith("(")) { 5605ffd940aSRaphael Isemann if (AO != AllowedOperand::Any) 5615ffd940aSRaphael Isemann return ErrorDiagnostic::get( 5625ffd940aSRaphael Isemann SM, Expr, "parenthesized expression not permitted here"); 5635ffd940aSRaphael Isemann return parseParenExpr(Expr, LineNumber, Context, SM); 5645ffd940aSRaphael Isemann } 5655ffd940aSRaphael Isemann 5665ffd940aSRaphael Isemann if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { 5675ffd940aSRaphael Isemann // Try to parse as a numeric variable use. 5685ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> ParseVarResult = 5695ffd940aSRaphael Isemann parseVariable(Expr, SM); 5705ffd940aSRaphael Isemann if (ParseVarResult) { 5715ffd940aSRaphael Isemann // Try to parse a function call. 5725ffd940aSRaphael Isemann if (Expr.ltrim(SpaceChars).startswith("(")) { 5735ffd940aSRaphael Isemann if (AO != AllowedOperand::Any) 5745ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, ParseVarResult->Name, 5755ffd940aSRaphael Isemann "unexpected function call"); 5765ffd940aSRaphael Isemann 5775ffd940aSRaphael Isemann return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context, 5785ffd940aSRaphael Isemann SM); 5795ffd940aSRaphael Isemann } 5805ffd940aSRaphael Isemann 5815ffd940aSRaphael Isemann return parseNumericVariableUse(ParseVarResult->Name, 5825ffd940aSRaphael Isemann ParseVarResult->IsPseudo, LineNumber, 5835ffd940aSRaphael Isemann Context, SM); 5845ffd940aSRaphael Isemann } 5855ffd940aSRaphael Isemann 5865ffd940aSRaphael Isemann if (AO == AllowedOperand::LineVar) 5875ffd940aSRaphael Isemann return ParseVarResult.takeError(); 5885ffd940aSRaphael Isemann // Ignore the error and retry parsing as a literal. 5895ffd940aSRaphael Isemann consumeError(ParseVarResult.takeError()); 5905ffd940aSRaphael Isemann } 5915ffd940aSRaphael Isemann 5925ffd940aSRaphael Isemann // Otherwise, parse it as a literal. 5935ffd940aSRaphael Isemann int64_t SignedLiteralValue; 5945ffd940aSRaphael Isemann uint64_t UnsignedLiteralValue; 5955ffd940aSRaphael Isemann StringRef SaveExpr = Expr; 5965ffd940aSRaphael Isemann // Accept both signed and unsigned literal, default to signed literal. 5975ffd940aSRaphael Isemann if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0, 5985ffd940aSRaphael Isemann UnsignedLiteralValue)) 5995ffd940aSRaphael Isemann return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), 6005ffd940aSRaphael Isemann UnsignedLiteralValue); 6015ffd940aSRaphael Isemann Expr = SaveExpr; 6025ffd940aSRaphael Isemann if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue)) 6035ffd940aSRaphael Isemann return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()), 6045ffd940aSRaphael Isemann SignedLiteralValue); 6055ffd940aSRaphael Isemann 6065ffd940aSRaphael Isemann return ErrorDiagnostic::get( 6075ffd940aSRaphael Isemann SM, Expr, 6085ffd940aSRaphael Isemann Twine("invalid ") + 6095ffd940aSRaphael Isemann (MaybeInvalidConstraint ? "matching constraint or " : "") + 6105ffd940aSRaphael Isemann "operand format"); 6115ffd940aSRaphael Isemann } 6125ffd940aSRaphael Isemann 6135ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> 6145ffd940aSRaphael Isemann Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber, 6155ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 6165ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 6175ffd940aSRaphael Isemann assert(Expr.startswith("(")); 6185ffd940aSRaphael Isemann 6195ffd940aSRaphael Isemann // Parse right operand. 6205ffd940aSRaphael Isemann Expr.consume_front("("); 6215ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 6225ffd940aSRaphael Isemann if (Expr.empty()) 6235ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, "missing operand in expression"); 6245ffd940aSRaphael Isemann 6255ffd940aSRaphael Isemann // Note: parseNumericOperand handles nested opening parentheses. 6265ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> SubExprResult = parseNumericOperand( 6275ffd940aSRaphael Isemann Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, 6285ffd940aSRaphael Isemann Context, SM); 6295ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 6305ffd940aSRaphael Isemann while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) { 6315ffd940aSRaphael Isemann StringRef OrigExpr = Expr; 6325ffd940aSRaphael Isemann SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false, 6335ffd940aSRaphael Isemann LineNumber, Context, SM); 6345ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 6355ffd940aSRaphael Isemann } 6365ffd940aSRaphael Isemann if (!SubExprResult) 6375ffd940aSRaphael Isemann return SubExprResult; 6385ffd940aSRaphael Isemann 6395ffd940aSRaphael Isemann if (!Expr.consume_front(")")) { 6405ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, 6415ffd940aSRaphael Isemann "missing ')' at end of nested expression"); 6425ffd940aSRaphael Isemann } 6435ffd940aSRaphael Isemann return SubExprResult; 6445ffd940aSRaphael Isemann } 6455ffd940aSRaphael Isemann 6465ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> 6475ffd940aSRaphael Isemann Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr, 6485ffd940aSRaphael Isemann std::unique_ptr<ExpressionAST> LeftOp, 6495ffd940aSRaphael Isemann bool IsLegacyLineExpr, Optional<size_t> LineNumber, 6505ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 6515ffd940aSRaphael Isemann RemainingExpr = RemainingExpr.ltrim(SpaceChars); 6525ffd940aSRaphael Isemann if (RemainingExpr.empty()) 6535ffd940aSRaphael Isemann return std::move(LeftOp); 6545ffd940aSRaphael Isemann 6555ffd940aSRaphael Isemann // Check if this is a supported operation and select a function to perform 6565ffd940aSRaphael Isemann // it. 6575ffd940aSRaphael Isemann SMLoc OpLoc = SMLoc::getFromPointer(RemainingExpr.data()); 6585ffd940aSRaphael Isemann char Operator = popFront(RemainingExpr); 6595ffd940aSRaphael Isemann binop_eval_t EvalBinop; 6605ffd940aSRaphael Isemann switch (Operator) { 6615ffd940aSRaphael Isemann case '+': 6625ffd940aSRaphael Isemann EvalBinop = operator+; 6635ffd940aSRaphael Isemann break; 6645ffd940aSRaphael Isemann case '-': 6655ffd940aSRaphael Isemann EvalBinop = operator-; 6665ffd940aSRaphael Isemann break; 6675ffd940aSRaphael Isemann default: 6685ffd940aSRaphael Isemann return ErrorDiagnostic::get( 6695ffd940aSRaphael Isemann SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); 6705ffd940aSRaphael Isemann } 6715ffd940aSRaphael Isemann 6725ffd940aSRaphael Isemann // Parse right operand. 6735ffd940aSRaphael Isemann RemainingExpr = RemainingExpr.ltrim(SpaceChars); 6745ffd940aSRaphael Isemann if (RemainingExpr.empty()) 6755ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, RemainingExpr, 6765ffd940aSRaphael Isemann "missing operand in expression"); 6775ffd940aSRaphael Isemann // The second operand in a legacy @LINE expression is always a literal. 6785ffd940aSRaphael Isemann AllowedOperand AO = 6795ffd940aSRaphael Isemann IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any; 6805ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> RightOpResult = 6815ffd940aSRaphael Isemann parseNumericOperand(RemainingExpr, AO, /*MaybeInvalidConstraint=*/false, 6825ffd940aSRaphael Isemann LineNumber, Context, SM); 6835ffd940aSRaphael Isemann if (!RightOpResult) 6845ffd940aSRaphael Isemann return RightOpResult; 6855ffd940aSRaphael Isemann 6865ffd940aSRaphael Isemann Expr = Expr.drop_back(RemainingExpr.size()); 6875ffd940aSRaphael Isemann return std::make_unique<BinaryOperation>(Expr, EvalBinop, std::move(LeftOp), 6885ffd940aSRaphael Isemann std::move(*RightOpResult)); 6895ffd940aSRaphael Isemann } 6905ffd940aSRaphael Isemann 6915ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> 6925ffd940aSRaphael Isemann Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName, 6935ffd940aSRaphael Isemann Optional<size_t> LineNumber, 6945ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 6955ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 6965ffd940aSRaphael Isemann assert(Expr.startswith("(")); 6975ffd940aSRaphael Isemann 6985ffd940aSRaphael Isemann auto OptFunc = StringSwitch<Optional<binop_eval_t>>(FuncName) 6995ffd940aSRaphael Isemann .Case("add", operator+) 7005ffd940aSRaphael Isemann .Case("div", operator/) 7015ffd940aSRaphael Isemann .Case("max", max) 7025ffd940aSRaphael Isemann .Case("min", min) 7035ffd940aSRaphael Isemann .Case("mul", operator*) 7045ffd940aSRaphael Isemann .Case("sub", operator-) 7055ffd940aSRaphael Isemann .Default(None); 7065ffd940aSRaphael Isemann 7075ffd940aSRaphael Isemann if (!OptFunc) 7085ffd940aSRaphael Isemann return ErrorDiagnostic::get( 7095ffd940aSRaphael Isemann SM, FuncName, Twine("call to undefined function '") + FuncName + "'"); 7105ffd940aSRaphael Isemann 7115ffd940aSRaphael Isemann Expr.consume_front("("); 7125ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 7135ffd940aSRaphael Isemann 7145ffd940aSRaphael Isemann // Parse call arguments, which are comma separated. 7155ffd940aSRaphael Isemann SmallVector<std::unique_ptr<ExpressionAST>, 4> Args; 7165ffd940aSRaphael Isemann while (!Expr.empty() && !Expr.startswith(")")) { 7175ffd940aSRaphael Isemann if (Expr.startswith(",")) 7185ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, "missing argument"); 7195ffd940aSRaphael Isemann 7205ffd940aSRaphael Isemann // Parse the argument, which is an arbitary expression. 7215ffd940aSRaphael Isemann StringRef OuterBinOpExpr = Expr; 7225ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> Arg = parseNumericOperand( 7235ffd940aSRaphael Isemann Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber, 7245ffd940aSRaphael Isemann Context, SM); 7255ffd940aSRaphael Isemann while (Arg && !Expr.empty()) { 7265ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 7275ffd940aSRaphael Isemann // Have we reached an argument terminator? 7285ffd940aSRaphael Isemann if (Expr.startswith(",") || Expr.startswith(")")) 7295ffd940aSRaphael Isemann break; 7305ffd940aSRaphael Isemann 7315ffd940aSRaphael Isemann // Arg = Arg <op> <expr> 7325ffd940aSRaphael Isemann Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber, 7335ffd940aSRaphael Isemann Context, SM); 7345ffd940aSRaphael Isemann } 7355ffd940aSRaphael Isemann 7365ffd940aSRaphael Isemann // Prefer an expression error over a generic invalid argument message. 7375ffd940aSRaphael Isemann if (!Arg) 7385ffd940aSRaphael Isemann return Arg.takeError(); 7395ffd940aSRaphael Isemann Args.push_back(std::move(*Arg)); 7405ffd940aSRaphael Isemann 7415ffd940aSRaphael Isemann // Have we parsed all available arguments? 7425ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 7435ffd940aSRaphael Isemann if (!Expr.consume_front(",")) 7445ffd940aSRaphael Isemann break; 7455ffd940aSRaphael Isemann 7465ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 7475ffd940aSRaphael Isemann if (Expr.startswith(")")) 7485ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, "missing argument"); 7495ffd940aSRaphael Isemann } 7505ffd940aSRaphael Isemann 7515ffd940aSRaphael Isemann if (!Expr.consume_front(")")) 7525ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Expr, 7535ffd940aSRaphael Isemann "missing ')' at end of call expression"); 7545ffd940aSRaphael Isemann 7555ffd940aSRaphael Isemann const unsigned NumArgs = Args.size(); 7565ffd940aSRaphael Isemann if (NumArgs == 2) 7575ffd940aSRaphael Isemann return std::make_unique<BinaryOperation>(Expr, *OptFunc, std::move(Args[0]), 7585ffd940aSRaphael Isemann std::move(Args[1])); 7595ffd940aSRaphael Isemann 7605ffd940aSRaphael Isemann // TODO: Support more than binop_eval_t. 7615ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, FuncName, 7625ffd940aSRaphael Isemann Twine("function '") + FuncName + 7635ffd940aSRaphael Isemann Twine("' takes 2 arguments but ") + 7645ffd940aSRaphael Isemann Twine(NumArgs) + " given"); 7655ffd940aSRaphael Isemann } 7665ffd940aSRaphael Isemann 7675ffd940aSRaphael Isemann Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock( 7685ffd940aSRaphael Isemann StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable, 7695ffd940aSRaphael Isemann bool IsLegacyLineExpr, Optional<size_t> LineNumber, 7705ffd940aSRaphael Isemann FileCheckPatternContext *Context, const SourceMgr &SM) { 7715ffd940aSRaphael Isemann std::unique_ptr<ExpressionAST> ExpressionASTPointer = nullptr; 7725ffd940aSRaphael Isemann StringRef DefExpr = StringRef(); 7735ffd940aSRaphael Isemann DefinedNumericVariable = None; 7745ffd940aSRaphael Isemann ExpressionFormat ExplicitFormat = ExpressionFormat(); 7755ffd940aSRaphael Isemann unsigned Precision = 0; 7765ffd940aSRaphael Isemann 7775ffd940aSRaphael Isemann // Parse format specifier (NOTE: ',' is also an argument seperator). 7785ffd940aSRaphael Isemann size_t FormatSpecEnd = Expr.find(','); 7795ffd940aSRaphael Isemann size_t FunctionStart = Expr.find('('); 7805ffd940aSRaphael Isemann if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) { 7815ffd940aSRaphael Isemann StringRef FormatExpr = Expr.take_front(FormatSpecEnd); 7825ffd940aSRaphael Isemann Expr = Expr.drop_front(FormatSpecEnd + 1); 7835ffd940aSRaphael Isemann FormatExpr = FormatExpr.trim(SpaceChars); 7845ffd940aSRaphael Isemann if (!FormatExpr.consume_front("%")) 7855ffd940aSRaphael Isemann return ErrorDiagnostic::get( 7865ffd940aSRaphael Isemann SM, FormatExpr, 7875ffd940aSRaphael Isemann "invalid matching format specification in expression"); 7885ffd940aSRaphael Isemann 789f9e2a62cSThomas Preud'homme // Parse alternate form flag. 790f9e2a62cSThomas Preud'homme SMLoc AlternateFormFlagLoc = SMLoc::getFromPointer(FormatExpr.data()); 791f9e2a62cSThomas Preud'homme bool AlternateForm = FormatExpr.consume_front("#"); 792f9e2a62cSThomas Preud'homme 7935ffd940aSRaphael Isemann // Parse precision. 7945ffd940aSRaphael Isemann if (FormatExpr.consume_front(".")) { 7955ffd940aSRaphael Isemann if (FormatExpr.consumeInteger(10, Precision)) 7965ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, FormatExpr, 7975ffd940aSRaphael Isemann "invalid precision in format specifier"); 7985ffd940aSRaphael Isemann } 7995ffd940aSRaphael Isemann 8005ffd940aSRaphael Isemann if (!FormatExpr.empty()) { 8015ffd940aSRaphael Isemann // Check for unknown matching format specifier and set matching format in 8025ffd940aSRaphael Isemann // class instance representing this expression. 8035ffd940aSRaphael Isemann SMLoc FmtLoc = SMLoc::getFromPointer(FormatExpr.data()); 8045ffd940aSRaphael Isemann switch (popFront(FormatExpr)) { 8055ffd940aSRaphael Isemann case 'u': 8065ffd940aSRaphael Isemann ExplicitFormat = 8075ffd940aSRaphael Isemann ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision); 8085ffd940aSRaphael Isemann break; 8095ffd940aSRaphael Isemann case 'd': 8105ffd940aSRaphael Isemann ExplicitFormat = 8115ffd940aSRaphael Isemann ExpressionFormat(ExpressionFormat::Kind::Signed, Precision); 8125ffd940aSRaphael Isemann break; 8135ffd940aSRaphael Isemann case 'x': 814f9e2a62cSThomas Preud'homme ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexLower, 815f9e2a62cSThomas Preud'homme Precision, AlternateForm); 8165ffd940aSRaphael Isemann break; 8175ffd940aSRaphael Isemann case 'X': 818f9e2a62cSThomas Preud'homme ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexUpper, 819f9e2a62cSThomas Preud'homme Precision, AlternateForm); 8205ffd940aSRaphael Isemann break; 8215ffd940aSRaphael Isemann default: 8225ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, FmtLoc, 8235ffd940aSRaphael Isemann "invalid format specifier in expression"); 8245ffd940aSRaphael Isemann } 8255ffd940aSRaphael Isemann } 8265ffd940aSRaphael Isemann 827f9e2a62cSThomas Preud'homme if (AlternateForm && ExplicitFormat != ExpressionFormat::Kind::HexLower && 828f9e2a62cSThomas Preud'homme ExplicitFormat != ExpressionFormat::Kind::HexUpper) 829f9e2a62cSThomas Preud'homme return ErrorDiagnostic::get( 830f9e2a62cSThomas Preud'homme SM, AlternateFormFlagLoc, 831f9e2a62cSThomas Preud'homme "alternate form only supported for hex values"); 832f9e2a62cSThomas Preud'homme 8335ffd940aSRaphael Isemann FormatExpr = FormatExpr.ltrim(SpaceChars); 8345ffd940aSRaphael Isemann if (!FormatExpr.empty()) 8355ffd940aSRaphael Isemann return ErrorDiagnostic::get( 8365ffd940aSRaphael Isemann SM, FormatExpr, 8375ffd940aSRaphael Isemann "invalid matching format specification in expression"); 8385ffd940aSRaphael Isemann } 8395ffd940aSRaphael Isemann 8405ffd940aSRaphael Isemann // Save variable definition expression if any. 8415ffd940aSRaphael Isemann size_t DefEnd = Expr.find(':'); 8425ffd940aSRaphael Isemann if (DefEnd != StringRef::npos) { 8435ffd940aSRaphael Isemann DefExpr = Expr.substr(0, DefEnd); 8445ffd940aSRaphael Isemann Expr = Expr.substr(DefEnd + 1); 8455ffd940aSRaphael Isemann } 8465ffd940aSRaphael Isemann 8475ffd940aSRaphael Isemann // Parse matching constraint. 8485ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 8495ffd940aSRaphael Isemann bool HasParsedValidConstraint = false; 8505ffd940aSRaphael Isemann if (Expr.consume_front("==")) 8515ffd940aSRaphael Isemann HasParsedValidConstraint = true; 8525ffd940aSRaphael Isemann 8535ffd940aSRaphael Isemann // Parse the expression itself. 8545ffd940aSRaphael Isemann Expr = Expr.ltrim(SpaceChars); 8555ffd940aSRaphael Isemann if (Expr.empty()) { 8565ffd940aSRaphael Isemann if (HasParsedValidConstraint) 8575ffd940aSRaphael Isemann return ErrorDiagnostic::get( 8585ffd940aSRaphael Isemann SM, Expr, "empty numeric expression should not have a constraint"); 8595ffd940aSRaphael Isemann } else { 8605ffd940aSRaphael Isemann Expr = Expr.rtrim(SpaceChars); 8615ffd940aSRaphael Isemann StringRef OuterBinOpExpr = Expr; 8625ffd940aSRaphael Isemann // The first operand in a legacy @LINE expression is always the @LINE 8635ffd940aSRaphael Isemann // pseudo variable. 8645ffd940aSRaphael Isemann AllowedOperand AO = 8655ffd940aSRaphael Isemann IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any; 8665ffd940aSRaphael Isemann Expected<std::unique_ptr<ExpressionAST>> ParseResult = parseNumericOperand( 8675ffd940aSRaphael Isemann Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM); 8685ffd940aSRaphael Isemann while (ParseResult && !Expr.empty()) { 8695ffd940aSRaphael Isemann ParseResult = parseBinop(OuterBinOpExpr, Expr, std::move(*ParseResult), 8705ffd940aSRaphael Isemann IsLegacyLineExpr, LineNumber, Context, SM); 8715ffd940aSRaphael Isemann // Legacy @LINE expressions only allow 2 operands. 8725ffd940aSRaphael Isemann if (ParseResult && IsLegacyLineExpr && !Expr.empty()) 8735ffd940aSRaphael Isemann return ErrorDiagnostic::get( 8745ffd940aSRaphael Isemann SM, Expr, 8755ffd940aSRaphael Isemann "unexpected characters at end of expression '" + Expr + "'"); 8765ffd940aSRaphael Isemann } 8775ffd940aSRaphael Isemann if (!ParseResult) 8785ffd940aSRaphael Isemann return ParseResult.takeError(); 8795ffd940aSRaphael Isemann ExpressionASTPointer = std::move(*ParseResult); 8805ffd940aSRaphael Isemann } 8815ffd940aSRaphael Isemann 8825ffd940aSRaphael Isemann // Select format of the expression, i.e. (i) its explicit format, if any, 8835ffd940aSRaphael Isemann // otherwise (ii) its implicit format, if any, otherwise (iii) the default 8845ffd940aSRaphael Isemann // format (unsigned). Error out in case of conflicting implicit format 8855ffd940aSRaphael Isemann // without explicit format. 8865ffd940aSRaphael Isemann ExpressionFormat Format; 8875ffd940aSRaphael Isemann if (ExplicitFormat) 8885ffd940aSRaphael Isemann Format = ExplicitFormat; 8895ffd940aSRaphael Isemann else if (ExpressionASTPointer) { 8905ffd940aSRaphael Isemann Expected<ExpressionFormat> ImplicitFormat = 8915ffd940aSRaphael Isemann ExpressionASTPointer->getImplicitFormat(SM); 8925ffd940aSRaphael Isemann if (!ImplicitFormat) 8935ffd940aSRaphael Isemann return ImplicitFormat.takeError(); 8945ffd940aSRaphael Isemann Format = *ImplicitFormat; 8955ffd940aSRaphael Isemann } 8965ffd940aSRaphael Isemann if (!Format) 8975ffd940aSRaphael Isemann Format = ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision); 8985ffd940aSRaphael Isemann 8995ffd940aSRaphael Isemann std::unique_ptr<Expression> ExpressionPointer = 9005ffd940aSRaphael Isemann std::make_unique<Expression>(std::move(ExpressionASTPointer), Format); 9015ffd940aSRaphael Isemann 9025ffd940aSRaphael Isemann // Parse the numeric variable definition. 9035ffd940aSRaphael Isemann if (DefEnd != StringRef::npos) { 9045ffd940aSRaphael Isemann DefExpr = DefExpr.ltrim(SpaceChars); 9055ffd940aSRaphael Isemann Expected<NumericVariable *> ParseResult = parseNumericVariableDefinition( 9065ffd940aSRaphael Isemann DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM); 9075ffd940aSRaphael Isemann 9085ffd940aSRaphael Isemann if (!ParseResult) 9095ffd940aSRaphael Isemann return ParseResult.takeError(); 9105ffd940aSRaphael Isemann DefinedNumericVariable = *ParseResult; 9115ffd940aSRaphael Isemann } 9125ffd940aSRaphael Isemann 9135ffd940aSRaphael Isemann return std::move(ExpressionPointer); 9145ffd940aSRaphael Isemann } 9155ffd940aSRaphael Isemann 9165ffd940aSRaphael Isemann bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, 9175ffd940aSRaphael Isemann SourceMgr &SM, const FileCheckRequest &Req) { 9185ffd940aSRaphael Isemann bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; 9195ffd940aSRaphael Isemann IgnoreCase = Req.IgnoreCase; 9205ffd940aSRaphael Isemann 9215ffd940aSRaphael Isemann PatternLoc = SMLoc::getFromPointer(PatternStr.data()); 9225ffd940aSRaphael Isemann 9235ffd940aSRaphael Isemann if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) 9245ffd940aSRaphael Isemann // Ignore trailing whitespace. 9255ffd940aSRaphael Isemann while (!PatternStr.empty() && 9265ffd940aSRaphael Isemann (PatternStr.back() == ' ' || PatternStr.back() == '\t')) 9275ffd940aSRaphael Isemann PatternStr = PatternStr.substr(0, PatternStr.size() - 1); 9285ffd940aSRaphael Isemann 9295ffd940aSRaphael Isemann // Check that there is something on the line. 9305ffd940aSRaphael Isemann if (PatternStr.empty() && CheckTy != Check::CheckEmpty) { 9315ffd940aSRaphael Isemann SM.PrintMessage(PatternLoc, SourceMgr::DK_Error, 9325ffd940aSRaphael Isemann "found empty check string with prefix '" + Prefix + ":'"); 9335ffd940aSRaphael Isemann return true; 9345ffd940aSRaphael Isemann } 9355ffd940aSRaphael Isemann 9365ffd940aSRaphael Isemann if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) { 9375ffd940aSRaphael Isemann SM.PrintMessage( 9385ffd940aSRaphael Isemann PatternLoc, SourceMgr::DK_Error, 9395ffd940aSRaphael Isemann "found non-empty check string for empty check with prefix '" + Prefix + 9405ffd940aSRaphael Isemann ":'"); 9415ffd940aSRaphael Isemann return true; 9425ffd940aSRaphael Isemann } 9435ffd940aSRaphael Isemann 9445ffd940aSRaphael Isemann if (CheckTy == Check::CheckEmpty) { 9455ffd940aSRaphael Isemann RegExStr = "(\n$)"; 9465ffd940aSRaphael Isemann return false; 9475ffd940aSRaphael Isemann } 9485ffd940aSRaphael Isemann 94944f399ccSJacques Pienaar // If literal check, set fixed string. 95044f399ccSJacques Pienaar if (CheckTy.isLiteralMatch()) { 95144f399ccSJacques Pienaar FixedStr = PatternStr; 95244f399ccSJacques Pienaar return false; 95344f399ccSJacques Pienaar } 95444f399ccSJacques Pienaar 9555ffd940aSRaphael Isemann // Check to see if this is a fixed string, or if it has regex pieces. 9565ffd940aSRaphael Isemann if (!MatchFullLinesHere && 9575ffd940aSRaphael Isemann (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos && 9585ffd940aSRaphael Isemann PatternStr.find("[[") == StringRef::npos))) { 9595ffd940aSRaphael Isemann FixedStr = PatternStr; 9605ffd940aSRaphael Isemann return false; 9615ffd940aSRaphael Isemann } 9625ffd940aSRaphael Isemann 9635ffd940aSRaphael Isemann if (MatchFullLinesHere) { 9645ffd940aSRaphael Isemann RegExStr += '^'; 9655ffd940aSRaphael Isemann if (!Req.NoCanonicalizeWhiteSpace) 9665ffd940aSRaphael Isemann RegExStr += " *"; 9675ffd940aSRaphael Isemann } 9685ffd940aSRaphael Isemann 9695ffd940aSRaphael Isemann // Paren value #0 is for the fully matched string. Any new parenthesized 9705ffd940aSRaphael Isemann // values add from there. 9715ffd940aSRaphael Isemann unsigned CurParen = 1; 9725ffd940aSRaphael Isemann 9735ffd940aSRaphael Isemann // Otherwise, there is at least one regex piece. Build up the regex pattern 9745ffd940aSRaphael Isemann // by escaping scary characters in fixed strings, building up one big regex. 9755ffd940aSRaphael Isemann while (!PatternStr.empty()) { 9765ffd940aSRaphael Isemann // RegEx matches. 9775ffd940aSRaphael Isemann if (PatternStr.startswith("{{")) { 9785ffd940aSRaphael Isemann // This is the start of a regex match. Scan for the }}. 9795ffd940aSRaphael Isemann size_t End = PatternStr.find("}}"); 9805ffd940aSRaphael Isemann if (End == StringRef::npos) { 9815ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), 9825ffd940aSRaphael Isemann SourceMgr::DK_Error, 9835ffd940aSRaphael Isemann "found start of regex string with no end '}}'"); 9845ffd940aSRaphael Isemann return true; 9855ffd940aSRaphael Isemann } 9865ffd940aSRaphael Isemann 9875ffd940aSRaphael Isemann // Enclose {{}} patterns in parens just like [[]] even though we're not 9885ffd940aSRaphael Isemann // capturing the result for any purpose. This is required in case the 9895ffd940aSRaphael Isemann // expression contains an alternation like: CHECK: abc{{x|z}}def. We 9905ffd940aSRaphael Isemann // want this to turn into: "abc(x|z)def" not "abcx|zdef". 9915ffd940aSRaphael Isemann RegExStr += '('; 9925ffd940aSRaphael Isemann ++CurParen; 9935ffd940aSRaphael Isemann 9945ffd940aSRaphael Isemann if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM)) 9955ffd940aSRaphael Isemann return true; 9965ffd940aSRaphael Isemann RegExStr += ')'; 9975ffd940aSRaphael Isemann 9985ffd940aSRaphael Isemann PatternStr = PatternStr.substr(End + 2); 9995ffd940aSRaphael Isemann continue; 10005ffd940aSRaphael Isemann } 10015ffd940aSRaphael Isemann 10025ffd940aSRaphael Isemann // String and numeric substitution blocks. Pattern substitution blocks come 10035ffd940aSRaphael Isemann // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some 10045ffd940aSRaphael Isemann // other regex) and assigns it to the string variable 'foo'. The latter 10055ffd940aSRaphael Isemann // substitutes foo's value. Numeric substitution blocks recognize the same 10065ffd940aSRaphael Isemann // form as string ones, but start with a '#' sign after the double 10075ffd940aSRaphael Isemann // brackets. They also accept a combined form which sets a numeric variable 10085ffd940aSRaphael Isemann // to the evaluation of an expression. Both string and numeric variable 10095ffd940aSRaphael Isemann // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be 10105ffd940aSRaphael Isemann // valid, as this helps catch some common errors. 10115ffd940aSRaphael Isemann if (PatternStr.startswith("[[")) { 10125ffd940aSRaphael Isemann StringRef UnparsedPatternStr = PatternStr.substr(2); 10135ffd940aSRaphael Isemann // Find the closing bracket pair ending the match. End is going to be an 10145ffd940aSRaphael Isemann // offset relative to the beginning of the match string. 10155ffd940aSRaphael Isemann size_t End = FindRegexVarEnd(UnparsedPatternStr, SM); 10165ffd940aSRaphael Isemann StringRef MatchStr = UnparsedPatternStr.substr(0, End); 10175ffd940aSRaphael Isemann bool IsNumBlock = MatchStr.consume_front("#"); 10185ffd940aSRaphael Isemann 10195ffd940aSRaphael Isemann if (End == StringRef::npos) { 10205ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), 10215ffd940aSRaphael Isemann SourceMgr::DK_Error, 10225ffd940aSRaphael Isemann "Invalid substitution block, no ]] found"); 10235ffd940aSRaphael Isemann return true; 10245ffd940aSRaphael Isemann } 10255ffd940aSRaphael Isemann // Strip the substitution block we are parsing. End points to the start 10265ffd940aSRaphael Isemann // of the "]]" closing the expression so account for it in computing the 10275ffd940aSRaphael Isemann // index of the first unparsed character. 10285ffd940aSRaphael Isemann PatternStr = UnparsedPatternStr.substr(End + 2); 10295ffd940aSRaphael Isemann 10305ffd940aSRaphael Isemann bool IsDefinition = false; 10315ffd940aSRaphael Isemann bool SubstNeeded = false; 10325ffd940aSRaphael Isemann // Whether the substitution block is a legacy use of @LINE with string 10335ffd940aSRaphael Isemann // substitution block syntax. 10345ffd940aSRaphael Isemann bool IsLegacyLineExpr = false; 10355ffd940aSRaphael Isemann StringRef DefName; 10365ffd940aSRaphael Isemann StringRef SubstStr; 10375ffd940aSRaphael Isemann std::string MatchRegexp; 10385ffd940aSRaphael Isemann size_t SubstInsertIdx = RegExStr.size(); 10395ffd940aSRaphael Isemann 10405ffd940aSRaphael Isemann // Parse string variable or legacy @LINE expression. 10415ffd940aSRaphael Isemann if (!IsNumBlock) { 1042c70f3686SFangrui Song size_t VarEndIdx = MatchStr.find(':'); 10435ffd940aSRaphael Isemann size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t"); 10445ffd940aSRaphael Isemann if (SpacePos != StringRef::npos) { 10455ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos), 10465ffd940aSRaphael Isemann SourceMgr::DK_Error, "unexpected whitespace"); 10475ffd940aSRaphael Isemann return true; 10485ffd940aSRaphael Isemann } 10495ffd940aSRaphael Isemann 10505ffd940aSRaphael Isemann // Get the name (e.g. "foo") and verify it is well formed. 10515ffd940aSRaphael Isemann StringRef OrigMatchStr = MatchStr; 10525ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> ParseVarResult = 10535ffd940aSRaphael Isemann parseVariable(MatchStr, SM); 10545ffd940aSRaphael Isemann if (!ParseVarResult) { 10555ffd940aSRaphael Isemann logAllUnhandledErrors(ParseVarResult.takeError(), errs()); 10565ffd940aSRaphael Isemann return true; 10575ffd940aSRaphael Isemann } 10585ffd940aSRaphael Isemann StringRef Name = ParseVarResult->Name; 10595ffd940aSRaphael Isemann bool IsPseudo = ParseVarResult->IsPseudo; 10605ffd940aSRaphael Isemann 10615ffd940aSRaphael Isemann IsDefinition = (VarEndIdx != StringRef::npos); 10625ffd940aSRaphael Isemann SubstNeeded = !IsDefinition; 10635ffd940aSRaphael Isemann if (IsDefinition) { 10645ffd940aSRaphael Isemann if ((IsPseudo || !MatchStr.consume_front(":"))) { 10655ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Name.data()), 10665ffd940aSRaphael Isemann SourceMgr::DK_Error, 10675ffd940aSRaphael Isemann "invalid name in string variable definition"); 10685ffd940aSRaphael Isemann return true; 10695ffd940aSRaphael Isemann } 10705ffd940aSRaphael Isemann 10715ffd940aSRaphael Isemann // Detect collisions between string and numeric variables when the 10725ffd940aSRaphael Isemann // former is created later than the latter. 10735ffd940aSRaphael Isemann if (Context->GlobalNumericVariableTable.find(Name) != 10745ffd940aSRaphael Isemann Context->GlobalNumericVariableTable.end()) { 10755ffd940aSRaphael Isemann SM.PrintMessage( 10765ffd940aSRaphael Isemann SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, 10775ffd940aSRaphael Isemann "numeric variable with name '" + Name + "' already exists"); 10785ffd940aSRaphael Isemann return true; 10795ffd940aSRaphael Isemann } 10805ffd940aSRaphael Isemann DefName = Name; 10815ffd940aSRaphael Isemann MatchRegexp = MatchStr.str(); 10825ffd940aSRaphael Isemann } else { 10835ffd940aSRaphael Isemann if (IsPseudo) { 10845ffd940aSRaphael Isemann MatchStr = OrigMatchStr; 10855ffd940aSRaphael Isemann IsLegacyLineExpr = IsNumBlock = true; 10865ffd940aSRaphael Isemann } else 10875ffd940aSRaphael Isemann SubstStr = Name; 10885ffd940aSRaphael Isemann } 10895ffd940aSRaphael Isemann } 10905ffd940aSRaphael Isemann 10915ffd940aSRaphael Isemann // Parse numeric substitution block. 10925ffd940aSRaphael Isemann std::unique_ptr<Expression> ExpressionPointer; 10935ffd940aSRaphael Isemann Optional<NumericVariable *> DefinedNumericVariable; 10945ffd940aSRaphael Isemann if (IsNumBlock) { 10955ffd940aSRaphael Isemann Expected<std::unique_ptr<Expression>> ParseResult = 10965ffd940aSRaphael Isemann parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, 10975ffd940aSRaphael Isemann IsLegacyLineExpr, LineNumber, Context, 10985ffd940aSRaphael Isemann SM); 10995ffd940aSRaphael Isemann if (!ParseResult) { 11005ffd940aSRaphael Isemann logAllUnhandledErrors(ParseResult.takeError(), errs()); 11015ffd940aSRaphael Isemann return true; 11025ffd940aSRaphael Isemann } 11035ffd940aSRaphael Isemann ExpressionPointer = std::move(*ParseResult); 11045ffd940aSRaphael Isemann SubstNeeded = ExpressionPointer->getAST() != nullptr; 11055ffd940aSRaphael Isemann if (DefinedNumericVariable) { 11065ffd940aSRaphael Isemann IsDefinition = true; 11075ffd940aSRaphael Isemann DefName = (*DefinedNumericVariable)->getName(); 11085ffd940aSRaphael Isemann } 11095ffd940aSRaphael Isemann if (SubstNeeded) 11105ffd940aSRaphael Isemann SubstStr = MatchStr; 11115ffd940aSRaphael Isemann else { 11125ffd940aSRaphael Isemann ExpressionFormat Format = ExpressionPointer->getFormat(); 11135ffd940aSRaphael Isemann MatchRegexp = cantFail(Format.getWildcardRegex()); 11145ffd940aSRaphael Isemann } 11155ffd940aSRaphael Isemann } 11165ffd940aSRaphael Isemann 11175ffd940aSRaphael Isemann // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]]. 11185ffd940aSRaphael Isemann if (IsDefinition) { 11195ffd940aSRaphael Isemann RegExStr += '('; 11205ffd940aSRaphael Isemann ++SubstInsertIdx; 11215ffd940aSRaphael Isemann 11225ffd940aSRaphael Isemann if (IsNumBlock) { 11235ffd940aSRaphael Isemann NumericVariableMatch NumericVariableDefinition = { 11245ffd940aSRaphael Isemann *DefinedNumericVariable, CurParen}; 11255ffd940aSRaphael Isemann NumericVariableDefs[DefName] = NumericVariableDefinition; 11265ffd940aSRaphael Isemann // This store is done here rather than in match() to allow 11275ffd940aSRaphael Isemann // parseNumericVariableUse() to get the pointer to the class instance 11285ffd940aSRaphael Isemann // of the right variable definition corresponding to a given numeric 11295ffd940aSRaphael Isemann // variable use. 11305ffd940aSRaphael Isemann Context->GlobalNumericVariableTable[DefName] = 11315ffd940aSRaphael Isemann *DefinedNumericVariable; 11325ffd940aSRaphael Isemann } else { 11335ffd940aSRaphael Isemann VariableDefs[DefName] = CurParen; 11345ffd940aSRaphael Isemann // Mark string variable as defined to detect collisions between 11355ffd940aSRaphael Isemann // string and numeric variables in parseNumericVariableUse() and 11365ffd940aSRaphael Isemann // defineCmdlineVariables() when the latter is created later than the 11375ffd940aSRaphael Isemann // former. We cannot reuse GlobalVariableTable for this by populating 11385ffd940aSRaphael Isemann // it with an empty string since we would then lose the ability to 11395ffd940aSRaphael Isemann // detect the use of an undefined variable in match(). 11405ffd940aSRaphael Isemann Context->DefinedVariableTable[DefName] = true; 11415ffd940aSRaphael Isemann } 11425ffd940aSRaphael Isemann 11435ffd940aSRaphael Isemann ++CurParen; 11445ffd940aSRaphael Isemann } 11455ffd940aSRaphael Isemann 11465ffd940aSRaphael Isemann if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM)) 11475ffd940aSRaphael Isemann return true; 11485ffd940aSRaphael Isemann 11495ffd940aSRaphael Isemann if (IsDefinition) 11505ffd940aSRaphael Isemann RegExStr += ')'; 11515ffd940aSRaphael Isemann 11525ffd940aSRaphael Isemann // Handle substitutions: [[foo]] and [[#<foo expr>]]. 11535ffd940aSRaphael Isemann if (SubstNeeded) { 11545ffd940aSRaphael Isemann // Handle substitution of string variables that were defined earlier on 11555ffd940aSRaphael Isemann // the same line by emitting a backreference. Expressions do not 11565ffd940aSRaphael Isemann // support substituting a numeric variable defined on the same line. 11575ffd940aSRaphael Isemann if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) { 11585ffd940aSRaphael Isemann unsigned CaptureParenGroup = VariableDefs[SubstStr]; 11595ffd940aSRaphael Isemann if (CaptureParenGroup < 1 || CaptureParenGroup > 9) { 11605ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()), 11615ffd940aSRaphael Isemann SourceMgr::DK_Error, 11625ffd940aSRaphael Isemann "Can't back-reference more than 9 variables"); 11635ffd940aSRaphael Isemann return true; 11645ffd940aSRaphael Isemann } 11655ffd940aSRaphael Isemann AddBackrefToRegEx(CaptureParenGroup); 11665ffd940aSRaphael Isemann } else { 11675ffd940aSRaphael Isemann // Handle substitution of string variables ([[<var>]]) defined in 11685ffd940aSRaphael Isemann // previous CHECK patterns, and substitution of expressions. 11695ffd940aSRaphael Isemann Substitution *Substitution = 11705ffd940aSRaphael Isemann IsNumBlock 11715ffd940aSRaphael Isemann ? Context->makeNumericSubstitution( 11725ffd940aSRaphael Isemann SubstStr, std::move(ExpressionPointer), SubstInsertIdx) 11735ffd940aSRaphael Isemann : Context->makeStringSubstitution(SubstStr, SubstInsertIdx); 11745ffd940aSRaphael Isemann Substitutions.push_back(Substitution); 11755ffd940aSRaphael Isemann } 11765ffd940aSRaphael Isemann } 11775ffd940aSRaphael Isemann } 11785ffd940aSRaphael Isemann 11795ffd940aSRaphael Isemann // Handle fixed string matches. 11805ffd940aSRaphael Isemann // Find the end, which is the start of the next regex. 11815ffd940aSRaphael Isemann size_t FixedMatchEnd = PatternStr.find("{{"); 11825ffd940aSRaphael Isemann FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[[")); 11835ffd940aSRaphael Isemann RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd)); 11845ffd940aSRaphael Isemann PatternStr = PatternStr.substr(FixedMatchEnd); 11855ffd940aSRaphael Isemann } 11865ffd940aSRaphael Isemann 11875ffd940aSRaphael Isemann if (MatchFullLinesHere) { 11885ffd940aSRaphael Isemann if (!Req.NoCanonicalizeWhiteSpace) 11895ffd940aSRaphael Isemann RegExStr += " *"; 11905ffd940aSRaphael Isemann RegExStr += '$'; 11915ffd940aSRaphael Isemann } 11925ffd940aSRaphael Isemann 11935ffd940aSRaphael Isemann return false; 11945ffd940aSRaphael Isemann } 11955ffd940aSRaphael Isemann 11965ffd940aSRaphael Isemann bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { 11975ffd940aSRaphael Isemann Regex R(RS); 11985ffd940aSRaphael Isemann std::string Error; 11995ffd940aSRaphael Isemann if (!R.isValid(Error)) { 12005ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error, 12015ffd940aSRaphael Isemann "invalid regex: " + Error); 12025ffd940aSRaphael Isemann return true; 12035ffd940aSRaphael Isemann } 12045ffd940aSRaphael Isemann 12055ffd940aSRaphael Isemann RegExStr += RS.str(); 12065ffd940aSRaphael Isemann CurParen += R.getNumMatches(); 12075ffd940aSRaphael Isemann return false; 12085ffd940aSRaphael Isemann } 12095ffd940aSRaphael Isemann 12105ffd940aSRaphael Isemann void Pattern::AddBackrefToRegEx(unsigned BackrefNum) { 12115ffd940aSRaphael Isemann assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number"); 12125ffd940aSRaphael Isemann std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum); 12135ffd940aSRaphael Isemann RegExStr += Backref; 12145ffd940aSRaphael Isemann } 12155ffd940aSRaphael Isemann 1216*dd59c132SJoel E. Denny Pattern::MatchResult Pattern::match(StringRef Buffer, 12175ffd940aSRaphael Isemann const SourceMgr &SM) const { 12185ffd940aSRaphael Isemann // If this is the EOF pattern, match it immediately. 1219*dd59c132SJoel E. Denny if (CheckTy == Check::CheckEOF) 1220*dd59c132SJoel E. Denny return MatchResult(Buffer.size(), 0, Error::success()); 12215ffd940aSRaphael Isemann 12225ffd940aSRaphael Isemann // If this is a fixed string pattern, just match it now. 12235ffd940aSRaphael Isemann if (!FixedStr.empty()) { 12245ffd940aSRaphael Isemann size_t Pos = 12255ffd940aSRaphael Isemann IgnoreCase ? Buffer.find_lower(FixedStr) : Buffer.find(FixedStr); 12265ffd940aSRaphael Isemann if (Pos == StringRef::npos) 12275ffd940aSRaphael Isemann return make_error<NotFoundError>(); 1228*dd59c132SJoel E. Denny return MatchResult(Pos, /*MatchLen=*/FixedStr.size(), Error::success()); 12295ffd940aSRaphael Isemann } 12305ffd940aSRaphael Isemann 12315ffd940aSRaphael Isemann // Regex match. 12325ffd940aSRaphael Isemann 12335ffd940aSRaphael Isemann // If there are substitutions, we need to create a temporary string with the 12345ffd940aSRaphael Isemann // actual value. 12355ffd940aSRaphael Isemann StringRef RegExToMatch = RegExStr; 12365ffd940aSRaphael Isemann std::string TmpStr; 12375ffd940aSRaphael Isemann if (!Substitutions.empty()) { 12385ffd940aSRaphael Isemann TmpStr = RegExStr; 12395ffd940aSRaphael Isemann if (LineNumber) 12405ffd940aSRaphael Isemann Context->LineVariable->setValue(ExpressionValue(*LineNumber)); 12415ffd940aSRaphael Isemann 12425ffd940aSRaphael Isemann size_t InsertOffset = 0; 12435ffd940aSRaphael Isemann // Substitute all string variables and expressions whose values are only 12445ffd940aSRaphael Isemann // now known. Use of string variables defined on the same line are handled 12455ffd940aSRaphael Isemann // by back-references. 12465ffd940aSRaphael Isemann for (const auto &Substitution : Substitutions) { 12475ffd940aSRaphael Isemann // Substitute and check for failure (e.g. use of undefined variable). 12485ffd940aSRaphael Isemann Expected<std::string> Value = Substitution->getResult(); 12495ffd940aSRaphael Isemann if (!Value) { 12505ffd940aSRaphael Isemann // Convert to an ErrorDiagnostic to get location information. This is 1251*dd59c132SJoel E. Denny // done here rather than printMatch/printNoMatch since now we know which 12525ffd940aSRaphael Isemann // substitution block caused the overflow. 12535ffd940aSRaphael Isemann Error Err = 12545ffd940aSRaphael Isemann handleErrors(Value.takeError(), [&](const OverflowError &E) { 12555ffd940aSRaphael Isemann return ErrorDiagnostic::get(SM, Substitution->getFromString(), 12565ffd940aSRaphael Isemann "unable to substitute variable or " 12575ffd940aSRaphael Isemann "numeric expression: overflow error"); 12585ffd940aSRaphael Isemann }); 12595ffd940aSRaphael Isemann return std::move(Err); 12605ffd940aSRaphael Isemann } 12615ffd940aSRaphael Isemann 12625ffd940aSRaphael Isemann // Plop it into the regex at the adjusted offset. 12635ffd940aSRaphael Isemann TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, 12645ffd940aSRaphael Isemann Value->begin(), Value->end()); 12655ffd940aSRaphael Isemann InsertOffset += Value->size(); 12665ffd940aSRaphael Isemann } 12675ffd940aSRaphael Isemann 12685ffd940aSRaphael Isemann // Match the newly constructed regex. 12695ffd940aSRaphael Isemann RegExToMatch = TmpStr; 12705ffd940aSRaphael Isemann } 12715ffd940aSRaphael Isemann 12725ffd940aSRaphael Isemann SmallVector<StringRef, 4> MatchInfo; 12735ffd940aSRaphael Isemann unsigned int Flags = Regex::Newline; 12745ffd940aSRaphael Isemann if (IgnoreCase) 12755ffd940aSRaphael Isemann Flags |= Regex::IgnoreCase; 12765ffd940aSRaphael Isemann if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo)) 12775ffd940aSRaphael Isemann return make_error<NotFoundError>(); 12785ffd940aSRaphael Isemann 12795ffd940aSRaphael Isemann // Successful regex match. 12805ffd940aSRaphael Isemann assert(!MatchInfo.empty() && "Didn't get any match"); 12815ffd940aSRaphael Isemann StringRef FullMatch = MatchInfo[0]; 12825ffd940aSRaphael Isemann 12835ffd940aSRaphael Isemann // If this defines any string variables, remember their values. 12845ffd940aSRaphael Isemann for (const auto &VariableDef : VariableDefs) { 12855ffd940aSRaphael Isemann assert(VariableDef.second < MatchInfo.size() && "Internal paren error"); 12865ffd940aSRaphael Isemann Context->GlobalVariableTable[VariableDef.first] = 12875ffd940aSRaphael Isemann MatchInfo[VariableDef.second]; 12885ffd940aSRaphael Isemann } 12895ffd940aSRaphael Isemann 1290*dd59c132SJoel E. Denny // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after 1291*dd59c132SJoel E. Denny // the required preceding newline, which is consumed by the pattern in the 1292*dd59c132SJoel E. Denny // case of CHECK-EMPTY but not CHECK-NEXT. 1293*dd59c132SJoel E. Denny size_t MatchStartSkip = CheckTy == Check::CheckEmpty; 1294*dd59c132SJoel E. Denny Match TheMatch; 1295*dd59c132SJoel E. Denny TheMatch.Pos = FullMatch.data() - Buffer.data() + MatchStartSkip; 1296*dd59c132SJoel E. Denny TheMatch.Len = FullMatch.size() - MatchStartSkip; 1297*dd59c132SJoel E. Denny 12985ffd940aSRaphael Isemann // If this defines any numeric variables, remember their values. 12995ffd940aSRaphael Isemann for (const auto &NumericVariableDef : NumericVariableDefs) { 13005ffd940aSRaphael Isemann const NumericVariableMatch &NumericVariableMatch = 13015ffd940aSRaphael Isemann NumericVariableDef.getValue(); 13025ffd940aSRaphael Isemann unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup; 13035ffd940aSRaphael Isemann assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); 13045ffd940aSRaphael Isemann NumericVariable *DefinedNumericVariable = 13055ffd940aSRaphael Isemann NumericVariableMatch.DefinedNumericVariable; 13065ffd940aSRaphael Isemann 13075ffd940aSRaphael Isemann StringRef MatchedValue = MatchInfo[CaptureParenGroup]; 13085ffd940aSRaphael Isemann ExpressionFormat Format = DefinedNumericVariable->getImplicitFormat(); 13095ffd940aSRaphael Isemann Expected<ExpressionValue> Value = 13105ffd940aSRaphael Isemann Format.valueFromStringRepr(MatchedValue, SM); 13115ffd940aSRaphael Isemann if (!Value) 1312*dd59c132SJoel E. Denny return MatchResult(TheMatch, Value.takeError()); 13135ffd940aSRaphael Isemann DefinedNumericVariable->setValue(*Value, MatchedValue); 13145ffd940aSRaphael Isemann } 13155ffd940aSRaphael Isemann 1316*dd59c132SJoel E. Denny return MatchResult(TheMatch, Error::success()); 13175ffd940aSRaphael Isemann } 13185ffd940aSRaphael Isemann 13195ffd940aSRaphael Isemann unsigned Pattern::computeMatchDistance(StringRef Buffer) const { 13205ffd940aSRaphael Isemann // Just compute the number of matching characters. For regular expressions, we 13215ffd940aSRaphael Isemann // just compare against the regex itself and hope for the best. 13225ffd940aSRaphael Isemann // 13235ffd940aSRaphael Isemann // FIXME: One easy improvement here is have the regex lib generate a single 13245ffd940aSRaphael Isemann // example regular expression which matches, and use that as the example 13255ffd940aSRaphael Isemann // string. 13265ffd940aSRaphael Isemann StringRef ExampleString(FixedStr); 13275ffd940aSRaphael Isemann if (ExampleString.empty()) 13285ffd940aSRaphael Isemann ExampleString = RegExStr; 13295ffd940aSRaphael Isemann 13305ffd940aSRaphael Isemann // Only compare up to the first line in the buffer, or the string size. 13315ffd940aSRaphael Isemann StringRef BufferPrefix = Buffer.substr(0, ExampleString.size()); 13325ffd940aSRaphael Isemann BufferPrefix = BufferPrefix.split('\n').first; 13335ffd940aSRaphael Isemann return BufferPrefix.edit_distance(ExampleString); 13345ffd940aSRaphael Isemann } 13355ffd940aSRaphael Isemann 13365ffd940aSRaphael Isemann void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, 13375ffd940aSRaphael Isemann SMRange Range, 13385ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy, 13395ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 13405ffd940aSRaphael Isemann // Print what we know about substitutions. 13415ffd940aSRaphael Isemann if (!Substitutions.empty()) { 13425ffd940aSRaphael Isemann for (const auto &Substitution : Substitutions) { 13435ffd940aSRaphael Isemann SmallString<256> Msg; 13445ffd940aSRaphael Isemann raw_svector_ostream OS(Msg); 13455ffd940aSRaphael Isemann Expected<std::string> MatchedValue = Substitution->getResult(); 13465ffd940aSRaphael Isemann 13475ffd940aSRaphael Isemann // Substitution failed or is not known at match time, print the undefined 13485ffd940aSRaphael Isemann // variables it uses. 13495ffd940aSRaphael Isemann if (!MatchedValue) { 13505ffd940aSRaphael Isemann bool UndefSeen = false; 13515ffd940aSRaphael Isemann handleAllErrors( 13525ffd940aSRaphael Isemann MatchedValue.takeError(), [](const NotFoundError &E) {}, 1353*dd59c132SJoel E. Denny // Handled in printMatch and printNoMatch(). 13545ffd940aSRaphael Isemann [](const ErrorDiagnostic &E) {}, 13555ffd940aSRaphael Isemann // Handled in match(). 13565ffd940aSRaphael Isemann [](const OverflowError &E) {}, 13575ffd940aSRaphael Isemann [&](const UndefVarError &E) { 13585ffd940aSRaphael Isemann if (!UndefSeen) { 13595ffd940aSRaphael Isemann OS << "uses undefined variable(s):"; 13605ffd940aSRaphael Isemann UndefSeen = true; 13615ffd940aSRaphael Isemann } 13625ffd940aSRaphael Isemann OS << " "; 13635ffd940aSRaphael Isemann E.log(OS); 13645ffd940aSRaphael Isemann }); 13655ffd940aSRaphael Isemann } else { 13665ffd940aSRaphael Isemann // Substitution succeeded. Print substituted value. 13675ffd940aSRaphael Isemann OS << "with \""; 13685ffd940aSRaphael Isemann OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; 13695ffd940aSRaphael Isemann OS.write_escaped(*MatchedValue) << "\""; 13705ffd940aSRaphael Isemann } 13715ffd940aSRaphael Isemann 13725ffd940aSRaphael Isemann // We report only the start of the match/search range to suggest we are 13735ffd940aSRaphael Isemann // reporting the substitutions as set at the start of the match/search. 13745ffd940aSRaphael Isemann // Indicating a non-zero-length range might instead seem to imply that the 13755ffd940aSRaphael Isemann // substitution matches or was captured from exactly that range. 13765ffd940aSRaphael Isemann if (Diags) 13775ffd940aSRaphael Isemann Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, 13785ffd940aSRaphael Isemann SMRange(Range.Start, Range.Start), OS.str()); 13795ffd940aSRaphael Isemann else 13805ffd940aSRaphael Isemann SM.PrintMessage(Range.Start, SourceMgr::DK_Note, OS.str()); 13815ffd940aSRaphael Isemann } 13825ffd940aSRaphael Isemann } 13835ffd940aSRaphael Isemann } 13845ffd940aSRaphael Isemann 13855ffd940aSRaphael Isemann void Pattern::printVariableDefs(const SourceMgr &SM, 13865ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy, 13875ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 13885ffd940aSRaphael Isemann if (VariableDefs.empty() && NumericVariableDefs.empty()) 13895ffd940aSRaphael Isemann return; 13905ffd940aSRaphael Isemann // Build list of variable captures. 13915ffd940aSRaphael Isemann struct VarCapture { 13925ffd940aSRaphael Isemann StringRef Name; 13935ffd940aSRaphael Isemann SMRange Range; 13945ffd940aSRaphael Isemann }; 13955ffd940aSRaphael Isemann SmallVector<VarCapture, 2> VarCaptures; 13965ffd940aSRaphael Isemann for (const auto &VariableDef : VariableDefs) { 13975ffd940aSRaphael Isemann VarCapture VC; 13985ffd940aSRaphael Isemann VC.Name = VariableDef.first; 13995ffd940aSRaphael Isemann StringRef Value = Context->GlobalVariableTable[VC.Name]; 14005ffd940aSRaphael Isemann SMLoc Start = SMLoc::getFromPointer(Value.data()); 14015ffd940aSRaphael Isemann SMLoc End = SMLoc::getFromPointer(Value.data() + Value.size()); 14025ffd940aSRaphael Isemann VC.Range = SMRange(Start, End); 14035ffd940aSRaphael Isemann VarCaptures.push_back(VC); 14045ffd940aSRaphael Isemann } 14055ffd940aSRaphael Isemann for (const auto &VariableDef : NumericVariableDefs) { 14065ffd940aSRaphael Isemann VarCapture VC; 14075ffd940aSRaphael Isemann VC.Name = VariableDef.getKey(); 1408*dd59c132SJoel E. Denny Optional<StringRef> StrValue = 1409*dd59c132SJoel E. Denny VariableDef.getValue().DefinedNumericVariable->getStringValue(); 1410*dd59c132SJoel E. Denny if (!StrValue) 1411*dd59c132SJoel E. Denny continue; 1412*dd59c132SJoel E. Denny SMLoc Start = SMLoc::getFromPointer(StrValue->data()); 1413*dd59c132SJoel E. Denny SMLoc End = SMLoc::getFromPointer(StrValue->data() + StrValue->size()); 14145ffd940aSRaphael Isemann VC.Range = SMRange(Start, End); 14155ffd940aSRaphael Isemann VarCaptures.push_back(VC); 14165ffd940aSRaphael Isemann } 14175ffd940aSRaphael Isemann // Sort variable captures by the order in which they matched the input. 14185ffd940aSRaphael Isemann // Ranges shouldn't be overlapping, so we can just compare the start. 1419352fcfc6SKazu Hirata llvm::sort(VarCaptures, [](const VarCapture &A, const VarCapture &B) { 14205ffd940aSRaphael Isemann assert(A.Range.Start != B.Range.Start && 14215ffd940aSRaphael Isemann "unexpected overlapping variable captures"); 14225ffd940aSRaphael Isemann return A.Range.Start.getPointer() < B.Range.Start.getPointer(); 14235ffd940aSRaphael Isemann }); 14245ffd940aSRaphael Isemann // Create notes for the sorted captures. 14255ffd940aSRaphael Isemann for (const VarCapture &VC : VarCaptures) { 14265ffd940aSRaphael Isemann SmallString<256> Msg; 14275ffd940aSRaphael Isemann raw_svector_ostream OS(Msg); 14285ffd940aSRaphael Isemann OS << "captured var \"" << VC.Name << "\""; 14295ffd940aSRaphael Isemann if (Diags) 14305ffd940aSRaphael Isemann Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, VC.Range, OS.str()); 14315ffd940aSRaphael Isemann else 14325ffd940aSRaphael Isemann SM.PrintMessage(VC.Range.Start, SourceMgr::DK_Note, OS.str(), VC.Range); 14335ffd940aSRaphael Isemann } 14345ffd940aSRaphael Isemann } 14355ffd940aSRaphael Isemann 14365ffd940aSRaphael Isemann static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy, 14375ffd940aSRaphael Isemann const SourceMgr &SM, SMLoc Loc, 14385ffd940aSRaphael Isemann Check::FileCheckType CheckTy, 14395ffd940aSRaphael Isemann StringRef Buffer, size_t Pos, size_t Len, 14405ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags, 14415ffd940aSRaphael Isemann bool AdjustPrevDiags = false) { 14425ffd940aSRaphael Isemann SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos); 14435ffd940aSRaphael Isemann SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len); 14445ffd940aSRaphael Isemann SMRange Range(Start, End); 14455ffd940aSRaphael Isemann if (Diags) { 14465ffd940aSRaphael Isemann if (AdjustPrevDiags) { 14475ffd940aSRaphael Isemann SMLoc CheckLoc = Diags->rbegin()->CheckLoc; 14485ffd940aSRaphael Isemann for (auto I = Diags->rbegin(), E = Diags->rend(); 14495ffd940aSRaphael Isemann I != E && I->CheckLoc == CheckLoc; ++I) 14505ffd940aSRaphael Isemann I->MatchTy = MatchTy; 14515ffd940aSRaphael Isemann } else 14525ffd940aSRaphael Isemann Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range); 14535ffd940aSRaphael Isemann } 14545ffd940aSRaphael Isemann return Range; 14555ffd940aSRaphael Isemann } 14565ffd940aSRaphael Isemann 14575ffd940aSRaphael Isemann void Pattern::printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, 14585ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 14595ffd940aSRaphael Isemann // Attempt to find the closest/best fuzzy match. Usually an error happens 14605ffd940aSRaphael Isemann // because some string in the output didn't exactly match. In these cases, we 14615ffd940aSRaphael Isemann // would like to show the user a best guess at what "should have" matched, to 14625ffd940aSRaphael Isemann // save them having to actually check the input manually. 14635ffd940aSRaphael Isemann size_t NumLinesForward = 0; 14645ffd940aSRaphael Isemann size_t Best = StringRef::npos; 14655ffd940aSRaphael Isemann double BestQuality = 0; 14665ffd940aSRaphael Isemann 14675ffd940aSRaphael Isemann // Use an arbitrary 4k limit on how far we will search. 14685ffd940aSRaphael Isemann for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) { 14695ffd940aSRaphael Isemann if (Buffer[i] == '\n') 14705ffd940aSRaphael Isemann ++NumLinesForward; 14715ffd940aSRaphael Isemann 14725ffd940aSRaphael Isemann // Patterns have leading whitespace stripped, so skip whitespace when 14735ffd940aSRaphael Isemann // looking for something which looks like a pattern. 14745ffd940aSRaphael Isemann if (Buffer[i] == ' ' || Buffer[i] == '\t') 14755ffd940aSRaphael Isemann continue; 14765ffd940aSRaphael Isemann 14775ffd940aSRaphael Isemann // Compute the "quality" of this match as an arbitrary combination of the 14785ffd940aSRaphael Isemann // match distance and the number of lines skipped to get to this match. 14795ffd940aSRaphael Isemann unsigned Distance = computeMatchDistance(Buffer.substr(i)); 14805ffd940aSRaphael Isemann double Quality = Distance + (NumLinesForward / 100.); 14815ffd940aSRaphael Isemann 14825ffd940aSRaphael Isemann if (Quality < BestQuality || Best == StringRef::npos) { 14835ffd940aSRaphael Isemann Best = i; 14845ffd940aSRaphael Isemann BestQuality = Quality; 14855ffd940aSRaphael Isemann } 14865ffd940aSRaphael Isemann } 14875ffd940aSRaphael Isemann 14885ffd940aSRaphael Isemann // Print the "possible intended match here" line if we found something 14895ffd940aSRaphael Isemann // reasonable and not equal to what we showed in the "scanning from here" 14905ffd940aSRaphael Isemann // line. 14915ffd940aSRaphael Isemann if (Best && Best != StringRef::npos && BestQuality < 50) { 14925ffd940aSRaphael Isemann SMRange MatchRange = 14935ffd940aSRaphael Isemann ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(), 14945ffd940aSRaphael Isemann getCheckTy(), Buffer, Best, 0, Diags); 14955ffd940aSRaphael Isemann SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, 14965ffd940aSRaphael Isemann "possible intended match here"); 14975ffd940aSRaphael Isemann 14985ffd940aSRaphael Isemann // FIXME: If we wanted to be really friendly we would show why the match 14995ffd940aSRaphael Isemann // failed, as it can be hard to spot simple one character differences. 15005ffd940aSRaphael Isemann } 15015ffd940aSRaphael Isemann } 15025ffd940aSRaphael Isemann 15035ffd940aSRaphael Isemann Expected<StringRef> 15045ffd940aSRaphael Isemann FileCheckPatternContext::getPatternVarValue(StringRef VarName) { 15055ffd940aSRaphael Isemann auto VarIter = GlobalVariableTable.find(VarName); 15065ffd940aSRaphael Isemann if (VarIter == GlobalVariableTable.end()) 15075ffd940aSRaphael Isemann return make_error<UndefVarError>(VarName); 15085ffd940aSRaphael Isemann 15095ffd940aSRaphael Isemann return VarIter->second; 15105ffd940aSRaphael Isemann } 15115ffd940aSRaphael Isemann 15125ffd940aSRaphael Isemann template <class... Types> 15135ffd940aSRaphael Isemann NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) { 15145ffd940aSRaphael Isemann NumericVariables.push_back(std::make_unique<NumericVariable>(args...)); 15155ffd940aSRaphael Isemann return NumericVariables.back().get(); 15165ffd940aSRaphael Isemann } 15175ffd940aSRaphael Isemann 15185ffd940aSRaphael Isemann Substitution * 15195ffd940aSRaphael Isemann FileCheckPatternContext::makeStringSubstitution(StringRef VarName, 15205ffd940aSRaphael Isemann size_t InsertIdx) { 15215ffd940aSRaphael Isemann Substitutions.push_back( 15225ffd940aSRaphael Isemann std::make_unique<StringSubstitution>(this, VarName, InsertIdx)); 15235ffd940aSRaphael Isemann return Substitutions.back().get(); 15245ffd940aSRaphael Isemann } 15255ffd940aSRaphael Isemann 15265ffd940aSRaphael Isemann Substitution *FileCheckPatternContext::makeNumericSubstitution( 15275ffd940aSRaphael Isemann StringRef ExpressionStr, std::unique_ptr<Expression> Expression, 15285ffd940aSRaphael Isemann size_t InsertIdx) { 15295ffd940aSRaphael Isemann Substitutions.push_back(std::make_unique<NumericSubstitution>( 15305ffd940aSRaphael Isemann this, ExpressionStr, std::move(Expression), InsertIdx)); 15315ffd940aSRaphael Isemann return Substitutions.back().get(); 15325ffd940aSRaphael Isemann } 15335ffd940aSRaphael Isemann 15345ffd940aSRaphael Isemann size_t Pattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { 15355ffd940aSRaphael Isemann // Offset keeps track of the current offset within the input Str 15365ffd940aSRaphael Isemann size_t Offset = 0; 15375ffd940aSRaphael Isemann // [...] Nesting depth 15385ffd940aSRaphael Isemann size_t BracketDepth = 0; 15395ffd940aSRaphael Isemann 15405ffd940aSRaphael Isemann while (!Str.empty()) { 15415ffd940aSRaphael Isemann if (Str.startswith("]]") && BracketDepth == 0) 15425ffd940aSRaphael Isemann return Offset; 15435ffd940aSRaphael Isemann if (Str[0] == '\\') { 15445ffd940aSRaphael Isemann // Backslash escapes the next char within regexes, so skip them both. 15455ffd940aSRaphael Isemann Str = Str.substr(2); 15465ffd940aSRaphael Isemann Offset += 2; 15475ffd940aSRaphael Isemann } else { 15485ffd940aSRaphael Isemann switch (Str[0]) { 15495ffd940aSRaphael Isemann default: 15505ffd940aSRaphael Isemann break; 15515ffd940aSRaphael Isemann case '[': 15525ffd940aSRaphael Isemann BracketDepth++; 15535ffd940aSRaphael Isemann break; 15545ffd940aSRaphael Isemann case ']': 15555ffd940aSRaphael Isemann if (BracketDepth == 0) { 15565ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Str.data()), 15575ffd940aSRaphael Isemann SourceMgr::DK_Error, 15585ffd940aSRaphael Isemann "missing closing \"]\" for regex variable"); 15595ffd940aSRaphael Isemann exit(1); 15605ffd940aSRaphael Isemann } 15615ffd940aSRaphael Isemann BracketDepth--; 15625ffd940aSRaphael Isemann break; 15635ffd940aSRaphael Isemann } 15645ffd940aSRaphael Isemann Str = Str.substr(1); 15655ffd940aSRaphael Isemann Offset++; 15665ffd940aSRaphael Isemann } 15675ffd940aSRaphael Isemann } 15685ffd940aSRaphael Isemann 15695ffd940aSRaphael Isemann return StringRef::npos; 15705ffd940aSRaphael Isemann } 15715ffd940aSRaphael Isemann 15725ffd940aSRaphael Isemann StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB, 15735ffd940aSRaphael Isemann SmallVectorImpl<char> &OutputBuffer) { 15745ffd940aSRaphael Isemann OutputBuffer.reserve(MB.getBufferSize()); 15755ffd940aSRaphael Isemann 15765ffd940aSRaphael Isemann for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd(); 15775ffd940aSRaphael Isemann Ptr != End; ++Ptr) { 15785ffd940aSRaphael Isemann // Eliminate trailing dosish \r. 15795ffd940aSRaphael Isemann if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') { 15805ffd940aSRaphael Isemann continue; 15815ffd940aSRaphael Isemann } 15825ffd940aSRaphael Isemann 15835ffd940aSRaphael Isemann // If current char is not a horizontal whitespace or if horizontal 15845ffd940aSRaphael Isemann // whitespace canonicalization is disabled, dump it to output as is. 15855ffd940aSRaphael Isemann if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) { 15865ffd940aSRaphael Isemann OutputBuffer.push_back(*Ptr); 15875ffd940aSRaphael Isemann continue; 15885ffd940aSRaphael Isemann } 15895ffd940aSRaphael Isemann 15905ffd940aSRaphael Isemann // Otherwise, add one space and advance over neighboring space. 15915ffd940aSRaphael Isemann OutputBuffer.push_back(' '); 15925ffd940aSRaphael Isemann while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t')) 15935ffd940aSRaphael Isemann ++Ptr; 15945ffd940aSRaphael Isemann } 15955ffd940aSRaphael Isemann 15965ffd940aSRaphael Isemann // Add a null byte and then return all but that byte. 15975ffd940aSRaphael Isemann OutputBuffer.push_back('\0'); 15985ffd940aSRaphael Isemann return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1); 15995ffd940aSRaphael Isemann } 16005ffd940aSRaphael Isemann 16015ffd940aSRaphael Isemann FileCheckDiag::FileCheckDiag(const SourceMgr &SM, 16025ffd940aSRaphael Isemann const Check::FileCheckType &CheckTy, 16035ffd940aSRaphael Isemann SMLoc CheckLoc, MatchType MatchTy, 16045ffd940aSRaphael Isemann SMRange InputRange, StringRef Note) 16055ffd940aSRaphael Isemann : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy), Note(Note) { 16065ffd940aSRaphael Isemann auto Start = SM.getLineAndColumn(InputRange.Start); 16075ffd940aSRaphael Isemann auto End = SM.getLineAndColumn(InputRange.End); 16085ffd940aSRaphael Isemann InputStartLine = Start.first; 16095ffd940aSRaphael Isemann InputStartCol = Start.second; 16105ffd940aSRaphael Isemann InputEndLine = End.first; 16115ffd940aSRaphael Isemann InputEndCol = End.second; 16125ffd940aSRaphael Isemann } 16135ffd940aSRaphael Isemann 16145ffd940aSRaphael Isemann static bool IsPartOfWord(char c) { 16155ffd940aSRaphael Isemann return (isAlnum(c) || c == '-' || c == '_'); 16165ffd940aSRaphael Isemann } 16175ffd940aSRaphael Isemann 16185ffd940aSRaphael Isemann Check::FileCheckType &Check::FileCheckType::setCount(int C) { 16195ffd940aSRaphael Isemann assert(Count > 0 && "zero and negative counts are not supported"); 16205ffd940aSRaphael Isemann assert((C == 1 || Kind == CheckPlain) && 16215ffd940aSRaphael Isemann "count supported only for plain CHECK directives"); 16225ffd940aSRaphael Isemann Count = C; 16235ffd940aSRaphael Isemann return *this; 16245ffd940aSRaphael Isemann } 16255ffd940aSRaphael Isemann 162644f399ccSJacques Pienaar std::string Check::FileCheckType::getModifiersDescription() const { 162744f399ccSJacques Pienaar if (Modifiers.none()) 162844f399ccSJacques Pienaar return ""; 162944f399ccSJacques Pienaar std::string Ret; 163044f399ccSJacques Pienaar raw_string_ostream OS(Ret); 163144f399ccSJacques Pienaar OS << '{'; 163244f399ccSJacques Pienaar if (isLiteralMatch()) 163344f399ccSJacques Pienaar OS << "LITERAL"; 163444f399ccSJacques Pienaar OS << '}'; 163544f399ccSJacques Pienaar return OS.str(); 163644f399ccSJacques Pienaar } 163744f399ccSJacques Pienaar 16385ffd940aSRaphael Isemann std::string Check::FileCheckType::getDescription(StringRef Prefix) const { 163944f399ccSJacques Pienaar // Append directive modifiers. 164044f399ccSJacques Pienaar auto WithModifiers = [this, Prefix](StringRef Str) -> std::string { 164144f399ccSJacques Pienaar return (Prefix + Str + getModifiersDescription()).str(); 164244f399ccSJacques Pienaar }; 164344f399ccSJacques Pienaar 16445ffd940aSRaphael Isemann switch (Kind) { 16455ffd940aSRaphael Isemann case Check::CheckNone: 16465ffd940aSRaphael Isemann return "invalid"; 16475ffd940aSRaphael Isemann case Check::CheckPlain: 16485ffd940aSRaphael Isemann if (Count > 1) 164944f399ccSJacques Pienaar return WithModifiers("-COUNT"); 165044f399ccSJacques Pienaar return WithModifiers(""); 16515ffd940aSRaphael Isemann case Check::CheckNext: 165244f399ccSJacques Pienaar return WithModifiers("-NEXT"); 16535ffd940aSRaphael Isemann case Check::CheckSame: 165444f399ccSJacques Pienaar return WithModifiers("-SAME"); 16555ffd940aSRaphael Isemann case Check::CheckNot: 165644f399ccSJacques Pienaar return WithModifiers("-NOT"); 16575ffd940aSRaphael Isemann case Check::CheckDAG: 165844f399ccSJacques Pienaar return WithModifiers("-DAG"); 16595ffd940aSRaphael Isemann case Check::CheckLabel: 166044f399ccSJacques Pienaar return WithModifiers("-LABEL"); 16615ffd940aSRaphael Isemann case Check::CheckEmpty: 166244f399ccSJacques Pienaar return WithModifiers("-EMPTY"); 16635ffd940aSRaphael Isemann case Check::CheckComment: 16645ffd940aSRaphael Isemann return std::string(Prefix); 16655ffd940aSRaphael Isemann case Check::CheckEOF: 16665ffd940aSRaphael Isemann return "implicit EOF"; 16675ffd940aSRaphael Isemann case Check::CheckBadNot: 16685ffd940aSRaphael Isemann return "bad NOT"; 16695ffd940aSRaphael Isemann case Check::CheckBadCount: 16705ffd940aSRaphael Isemann return "bad COUNT"; 16715ffd940aSRaphael Isemann } 16725ffd940aSRaphael Isemann llvm_unreachable("unknown FileCheckType"); 16735ffd940aSRaphael Isemann } 16745ffd940aSRaphael Isemann 16755ffd940aSRaphael Isemann static std::pair<Check::FileCheckType, StringRef> 16765ffd940aSRaphael Isemann FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix) { 16775ffd940aSRaphael Isemann if (Buffer.size() <= Prefix.size()) 16785ffd940aSRaphael Isemann return {Check::CheckNone, StringRef()}; 16795ffd940aSRaphael Isemann 168044f399ccSJacques Pienaar StringRef Rest = Buffer.drop_front(Prefix.size()); 16815ffd940aSRaphael Isemann // Check for comment. 16825ffd940aSRaphael Isemann if (llvm::is_contained(Req.CommentPrefixes, Prefix)) { 168344f399ccSJacques Pienaar if (Rest.consume_front(":")) 16845ffd940aSRaphael Isemann return {Check::CheckComment, Rest}; 16855ffd940aSRaphael Isemann // Ignore a comment prefix if it has a suffix like "-NOT". 16865ffd940aSRaphael Isemann return {Check::CheckNone, StringRef()}; 16875ffd940aSRaphael Isemann } 16885ffd940aSRaphael Isemann 168944f399ccSJacques Pienaar auto ConsumeModifiers = [&](Check::FileCheckType Ret) 169044f399ccSJacques Pienaar -> std::pair<Check::FileCheckType, StringRef> { 169144f399ccSJacques Pienaar if (Rest.consume_front(":")) 169244f399ccSJacques Pienaar return {Ret, Rest}; 169344f399ccSJacques Pienaar if (!Rest.consume_front("{")) 169444f399ccSJacques Pienaar return {Check::CheckNone, StringRef()}; 16955ffd940aSRaphael Isemann 169644f399ccSJacques Pienaar // Parse the modifiers, speparated by commas. 169744f399ccSJacques Pienaar do { 169844f399ccSJacques Pienaar // Allow whitespace in modifiers list. 169944f399ccSJacques Pienaar Rest = Rest.ltrim(); 170044f399ccSJacques Pienaar if (Rest.consume_front("LITERAL")) 170144f399ccSJacques Pienaar Ret.setLiteralMatch(); 170244f399ccSJacques Pienaar else 170344f399ccSJacques Pienaar return {Check::CheckNone, Rest}; 170444f399ccSJacques Pienaar // Allow whitespace in modifiers list. 170544f399ccSJacques Pienaar Rest = Rest.ltrim(); 170644f399ccSJacques Pienaar } while (Rest.consume_front(",")); 170744f399ccSJacques Pienaar if (!Rest.consume_front("}:")) 170844f399ccSJacques Pienaar return {Check::CheckNone, Rest}; 170944f399ccSJacques Pienaar return {Ret, Rest}; 171044f399ccSJacques Pienaar }; 171144f399ccSJacques Pienaar 171244f399ccSJacques Pienaar // Verify that the prefix is followed by directive modifiers or a colon. 171344f399ccSJacques Pienaar if (Rest.consume_front(":")) 171444f399ccSJacques Pienaar return {Check::CheckPlain, Rest}; 171544f399ccSJacques Pienaar if (Rest.front() == '{') 171644f399ccSJacques Pienaar return ConsumeModifiers(Check::CheckPlain); 171744f399ccSJacques Pienaar 171844f399ccSJacques Pienaar if (!Rest.consume_front("-")) 17195ffd940aSRaphael Isemann return {Check::CheckNone, StringRef()}; 17205ffd940aSRaphael Isemann 17215ffd940aSRaphael Isemann if (Rest.consume_front("COUNT-")) { 17225ffd940aSRaphael Isemann int64_t Count; 17235ffd940aSRaphael Isemann if (Rest.consumeInteger(10, Count)) 17245ffd940aSRaphael Isemann // Error happened in parsing integer. 17255ffd940aSRaphael Isemann return {Check::CheckBadCount, Rest}; 17265ffd940aSRaphael Isemann if (Count <= 0 || Count > INT32_MAX) 17275ffd940aSRaphael Isemann return {Check::CheckBadCount, Rest}; 172844f399ccSJacques Pienaar if (Rest.front() != ':' && Rest.front() != '{') 17295ffd940aSRaphael Isemann return {Check::CheckBadCount, Rest}; 173044f399ccSJacques Pienaar return ConsumeModifiers( 173144f399ccSJacques Pienaar Check::FileCheckType(Check::CheckPlain).setCount(Count)); 17325ffd940aSRaphael Isemann } 17335ffd940aSRaphael Isemann 17345ffd940aSRaphael Isemann // You can't combine -NOT with another suffix. 17355ffd940aSRaphael Isemann if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || 17365ffd940aSRaphael Isemann Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") || 17375ffd940aSRaphael Isemann Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") || 17385ffd940aSRaphael Isemann Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:")) 17395ffd940aSRaphael Isemann return {Check::CheckBadNot, Rest}; 17405ffd940aSRaphael Isemann 174144f399ccSJacques Pienaar if (Rest.consume_front("NEXT")) 174244f399ccSJacques Pienaar return ConsumeModifiers(Check::CheckNext); 174344f399ccSJacques Pienaar 174444f399ccSJacques Pienaar if (Rest.consume_front("SAME")) 174544f399ccSJacques Pienaar return ConsumeModifiers(Check::CheckSame); 174644f399ccSJacques Pienaar 174744f399ccSJacques Pienaar if (Rest.consume_front("NOT")) 174844f399ccSJacques Pienaar return ConsumeModifiers(Check::CheckNot); 174944f399ccSJacques Pienaar 175044f399ccSJacques Pienaar if (Rest.consume_front("DAG")) 175144f399ccSJacques Pienaar return ConsumeModifiers(Check::CheckDAG); 175244f399ccSJacques Pienaar 175344f399ccSJacques Pienaar if (Rest.consume_front("LABEL")) 175444f399ccSJacques Pienaar return ConsumeModifiers(Check::CheckLabel); 175544f399ccSJacques Pienaar 175644f399ccSJacques Pienaar if (Rest.consume_front("EMPTY")) 175744f399ccSJacques Pienaar return ConsumeModifiers(Check::CheckEmpty); 175844f399ccSJacques Pienaar 17595ffd940aSRaphael Isemann return {Check::CheckNone, Rest}; 17605ffd940aSRaphael Isemann } 17615ffd940aSRaphael Isemann 17625ffd940aSRaphael Isemann // From the given position, find the next character after the word. 17635ffd940aSRaphael Isemann static size_t SkipWord(StringRef Str, size_t Loc) { 17645ffd940aSRaphael Isemann while (Loc < Str.size() && IsPartOfWord(Str[Loc])) 17655ffd940aSRaphael Isemann ++Loc; 17665ffd940aSRaphael Isemann return Loc; 17675ffd940aSRaphael Isemann } 17685ffd940aSRaphael Isemann 17695ffd940aSRaphael Isemann /// Searches the buffer for the first prefix in the prefix regular expression. 17705ffd940aSRaphael Isemann /// 17715ffd940aSRaphael Isemann /// This searches the buffer using the provided regular expression, however it 17725ffd940aSRaphael Isemann /// enforces constraints beyond that: 17735ffd940aSRaphael Isemann /// 1) The found prefix must not be a suffix of something that looks like 17745ffd940aSRaphael Isemann /// a valid prefix. 17755ffd940aSRaphael Isemann /// 2) The found prefix must be followed by a valid check type suffix using \c 17765ffd940aSRaphael Isemann /// FindCheckType above. 17775ffd940aSRaphael Isemann /// 17785ffd940aSRaphael Isemann /// \returns a pair of StringRefs into the Buffer, which combines: 17795ffd940aSRaphael Isemann /// - the first match of the regular expression to satisfy these two is 17805ffd940aSRaphael Isemann /// returned, 17815ffd940aSRaphael Isemann /// otherwise an empty StringRef is returned to indicate failure. 17825ffd940aSRaphael Isemann /// - buffer rewound to the location right after parsed suffix, for parsing 17835ffd940aSRaphael Isemann /// to continue from 17845ffd940aSRaphael Isemann /// 17855ffd940aSRaphael Isemann /// If this routine returns a valid prefix, it will also shrink \p Buffer to 17865ffd940aSRaphael Isemann /// start at the beginning of the returned prefix, increment \p LineNumber for 17875ffd940aSRaphael Isemann /// each new line consumed from \p Buffer, and set \p CheckTy to the type of 17885ffd940aSRaphael Isemann /// check found by examining the suffix. 17895ffd940aSRaphael Isemann /// 17905ffd940aSRaphael Isemann /// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy 17915ffd940aSRaphael Isemann /// is unspecified. 17925ffd940aSRaphael Isemann static std::pair<StringRef, StringRef> 17935ffd940aSRaphael Isemann FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE, 17945ffd940aSRaphael Isemann StringRef &Buffer, unsigned &LineNumber, 17955ffd940aSRaphael Isemann Check::FileCheckType &CheckTy) { 17965ffd940aSRaphael Isemann SmallVector<StringRef, 2> Matches; 17975ffd940aSRaphael Isemann 17985ffd940aSRaphael Isemann while (!Buffer.empty()) { 17995ffd940aSRaphael Isemann // Find the first (longest) match using the RE. 18005ffd940aSRaphael Isemann if (!PrefixRE.match(Buffer, &Matches)) 18015ffd940aSRaphael Isemann // No match at all, bail. 18025ffd940aSRaphael Isemann return {StringRef(), StringRef()}; 18035ffd940aSRaphael Isemann 18045ffd940aSRaphael Isemann StringRef Prefix = Matches[0]; 18055ffd940aSRaphael Isemann Matches.clear(); 18065ffd940aSRaphael Isemann 18075ffd940aSRaphael Isemann assert(Prefix.data() >= Buffer.data() && 18085ffd940aSRaphael Isemann Prefix.data() < Buffer.data() + Buffer.size() && 18095ffd940aSRaphael Isemann "Prefix doesn't start inside of buffer!"); 18105ffd940aSRaphael Isemann size_t Loc = Prefix.data() - Buffer.data(); 18115ffd940aSRaphael Isemann StringRef Skipped = Buffer.substr(0, Loc); 18125ffd940aSRaphael Isemann Buffer = Buffer.drop_front(Loc); 18135ffd940aSRaphael Isemann LineNumber += Skipped.count('\n'); 18145ffd940aSRaphael Isemann 18155ffd940aSRaphael Isemann // Check that the matched prefix isn't a suffix of some other check-like 18165ffd940aSRaphael Isemann // word. 18175ffd940aSRaphael Isemann // FIXME: This is a very ad-hoc check. it would be better handled in some 18185ffd940aSRaphael Isemann // other way. Among other things it seems hard to distinguish between 18195ffd940aSRaphael Isemann // intentional and unintentional uses of this feature. 18205ffd940aSRaphael Isemann if (Skipped.empty() || !IsPartOfWord(Skipped.back())) { 18215ffd940aSRaphael Isemann // Now extract the type. 18225ffd940aSRaphael Isemann StringRef AfterSuffix; 18235ffd940aSRaphael Isemann std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix); 18245ffd940aSRaphael Isemann 18255ffd940aSRaphael Isemann // If we've found a valid check type for this prefix, we're done. 18265ffd940aSRaphael Isemann if (CheckTy != Check::CheckNone) 18275ffd940aSRaphael Isemann return {Prefix, AfterSuffix}; 18285ffd940aSRaphael Isemann } 18295ffd940aSRaphael Isemann 18305ffd940aSRaphael Isemann // If we didn't successfully find a prefix, we need to skip this invalid 18315ffd940aSRaphael Isemann // prefix and continue scanning. We directly skip the prefix that was 18325ffd940aSRaphael Isemann // matched and any additional parts of that check-like word. 18335ffd940aSRaphael Isemann Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size())); 18345ffd940aSRaphael Isemann } 18355ffd940aSRaphael Isemann 18365ffd940aSRaphael Isemann // We ran out of buffer while skipping partial matches so give up. 18375ffd940aSRaphael Isemann return {StringRef(), StringRef()}; 18385ffd940aSRaphael Isemann } 18395ffd940aSRaphael Isemann 18405ffd940aSRaphael Isemann void FileCheckPatternContext::createLineVariable() { 18415ffd940aSRaphael Isemann assert(!LineVariable && "@LINE pseudo numeric variable already created"); 18425ffd940aSRaphael Isemann StringRef LineName = "@LINE"; 18435ffd940aSRaphael Isemann LineVariable = makeNumericVariable( 18445ffd940aSRaphael Isemann LineName, ExpressionFormat(ExpressionFormat::Kind::Unsigned)); 18455ffd940aSRaphael Isemann GlobalNumericVariableTable[LineName] = LineVariable; 18465ffd940aSRaphael Isemann } 18475ffd940aSRaphael Isemann 18485ffd940aSRaphael Isemann FileCheck::FileCheck(FileCheckRequest Req) 18495ffd940aSRaphael Isemann : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()), 18505ffd940aSRaphael Isemann CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {} 18515ffd940aSRaphael Isemann 18525ffd940aSRaphael Isemann FileCheck::~FileCheck() = default; 18535ffd940aSRaphael Isemann 18545ffd940aSRaphael Isemann bool FileCheck::readCheckFile( 18555ffd940aSRaphael Isemann SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, 18565ffd940aSRaphael Isemann std::pair<unsigned, unsigned> *ImpPatBufferIDRange) { 18575ffd940aSRaphael Isemann if (ImpPatBufferIDRange) 18585ffd940aSRaphael Isemann ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0; 18595ffd940aSRaphael Isemann 18605ffd940aSRaphael Isemann Error DefineError = 18615ffd940aSRaphael Isemann PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM); 18625ffd940aSRaphael Isemann if (DefineError) { 18635ffd940aSRaphael Isemann logAllUnhandledErrors(std::move(DefineError), errs()); 18645ffd940aSRaphael Isemann return true; 18655ffd940aSRaphael Isemann } 18665ffd940aSRaphael Isemann 18675ffd940aSRaphael Isemann PatternContext->createLineVariable(); 18685ffd940aSRaphael Isemann 18695ffd940aSRaphael Isemann std::vector<Pattern> ImplicitNegativeChecks; 18705ffd940aSRaphael Isemann for (StringRef PatternString : Req.ImplicitCheckNot) { 18715ffd940aSRaphael Isemann // Create a buffer with fake command line content in order to display the 18725ffd940aSRaphael Isemann // command line option responsible for the specific implicit CHECK-NOT. 18735ffd940aSRaphael Isemann std::string Prefix = "-implicit-check-not='"; 18745ffd940aSRaphael Isemann std::string Suffix = "'"; 18755ffd940aSRaphael Isemann std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy( 18765ffd940aSRaphael Isemann (Prefix + PatternString + Suffix).str(), "command line"); 18775ffd940aSRaphael Isemann 18785ffd940aSRaphael Isemann StringRef PatternInBuffer = 18795ffd940aSRaphael Isemann CmdLine->getBuffer().substr(Prefix.size(), PatternString.size()); 18805ffd940aSRaphael Isemann unsigned BufferID = SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); 18815ffd940aSRaphael Isemann if (ImpPatBufferIDRange) { 18825ffd940aSRaphael Isemann if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) { 18835ffd940aSRaphael Isemann ImpPatBufferIDRange->first = BufferID; 18845ffd940aSRaphael Isemann ImpPatBufferIDRange->second = BufferID + 1; 18855ffd940aSRaphael Isemann } else { 18865ffd940aSRaphael Isemann assert(BufferID == ImpPatBufferIDRange->second && 18875ffd940aSRaphael Isemann "expected consecutive source buffer IDs"); 18885ffd940aSRaphael Isemann ++ImpPatBufferIDRange->second; 18895ffd940aSRaphael Isemann } 18905ffd940aSRaphael Isemann } 18915ffd940aSRaphael Isemann 18925ffd940aSRaphael Isemann ImplicitNegativeChecks.push_back( 18935ffd940aSRaphael Isemann Pattern(Check::CheckNot, PatternContext.get())); 18945ffd940aSRaphael Isemann ImplicitNegativeChecks.back().parsePattern(PatternInBuffer, 18955ffd940aSRaphael Isemann "IMPLICIT-CHECK", SM, Req); 18965ffd940aSRaphael Isemann } 18975ffd940aSRaphael Isemann 18985ffd940aSRaphael Isemann std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks; 18995ffd940aSRaphael Isemann 19005ffd940aSRaphael Isemann // LineNumber keeps track of the line on which CheckPrefix instances are 19015ffd940aSRaphael Isemann // found. 19025ffd940aSRaphael Isemann unsigned LineNumber = 1; 19035ffd940aSRaphael Isemann 1904871d658cSMircea Trofin std::set<StringRef> PrefixesNotFound(Req.CheckPrefixes.begin(), 1905871d658cSMircea Trofin Req.CheckPrefixes.end()); 1906871d658cSMircea Trofin const size_t DistinctPrefixes = PrefixesNotFound.size(); 1907871d658cSMircea Trofin while (true) { 19085ffd940aSRaphael Isemann Check::FileCheckType CheckTy; 19095ffd940aSRaphael Isemann 19105ffd940aSRaphael Isemann // See if a prefix occurs in the memory buffer. 19115ffd940aSRaphael Isemann StringRef UsedPrefix; 19125ffd940aSRaphael Isemann StringRef AfterSuffix; 19135ffd940aSRaphael Isemann std::tie(UsedPrefix, AfterSuffix) = 19145ffd940aSRaphael Isemann FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy); 19155ffd940aSRaphael Isemann if (UsedPrefix.empty()) 19165ffd940aSRaphael Isemann break; 19175ffd940aSRaphael Isemann if (CheckTy != Check::CheckComment) 1918871d658cSMircea Trofin PrefixesNotFound.erase(UsedPrefix); 19195ffd940aSRaphael Isemann 19205ffd940aSRaphael Isemann assert(UsedPrefix.data() == Buffer.data() && 19215ffd940aSRaphael Isemann "Failed to move Buffer's start forward, or pointed prefix outside " 19225ffd940aSRaphael Isemann "of the buffer!"); 19235ffd940aSRaphael Isemann assert(AfterSuffix.data() >= Buffer.data() && 19245ffd940aSRaphael Isemann AfterSuffix.data() < Buffer.data() + Buffer.size() && 19255ffd940aSRaphael Isemann "Parsing after suffix doesn't start inside of buffer!"); 19265ffd940aSRaphael Isemann 19275ffd940aSRaphael Isemann // Location to use for error messages. 19285ffd940aSRaphael Isemann const char *UsedPrefixStart = UsedPrefix.data(); 19295ffd940aSRaphael Isemann 19305ffd940aSRaphael Isemann // Skip the buffer to the end of parsed suffix (or just prefix, if no good 19315ffd940aSRaphael Isemann // suffix was processed). 19325ffd940aSRaphael Isemann Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size()) 19335ffd940aSRaphael Isemann : AfterSuffix; 19345ffd940aSRaphael Isemann 19355ffd940aSRaphael Isemann // Complain about useful-looking but unsupported suffixes. 19365ffd940aSRaphael Isemann if (CheckTy == Check::CheckBadNot) { 19375ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, 19385ffd940aSRaphael Isemann "unsupported -NOT combo on prefix '" + UsedPrefix + "'"); 19395ffd940aSRaphael Isemann return true; 19405ffd940aSRaphael Isemann } 19415ffd940aSRaphael Isemann 19425ffd940aSRaphael Isemann // Complain about invalid count specification. 19435ffd940aSRaphael Isemann if (CheckTy == Check::CheckBadCount) { 19445ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error, 19455ffd940aSRaphael Isemann "invalid count in -COUNT specification on prefix '" + 19465ffd940aSRaphael Isemann UsedPrefix + "'"); 19475ffd940aSRaphael Isemann return true; 19485ffd940aSRaphael Isemann } 19495ffd940aSRaphael Isemann 19505ffd940aSRaphael Isemann // Okay, we found the prefix, yay. Remember the rest of the line, but ignore 19515ffd940aSRaphael Isemann // leading whitespace. 19525ffd940aSRaphael Isemann if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) 19535ffd940aSRaphael Isemann Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); 19545ffd940aSRaphael Isemann 19555ffd940aSRaphael Isemann // Scan ahead to the end of line. 19565ffd940aSRaphael Isemann size_t EOL = Buffer.find_first_of("\n\r"); 19575ffd940aSRaphael Isemann 19585ffd940aSRaphael Isemann // Remember the location of the start of the pattern, for diagnostics. 19595ffd940aSRaphael Isemann SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); 19605ffd940aSRaphael Isemann 19615ffd940aSRaphael Isemann // Extract the pattern from the buffer. 19625ffd940aSRaphael Isemann StringRef PatternBuffer = Buffer.substr(0, EOL); 19635ffd940aSRaphael Isemann Buffer = Buffer.substr(EOL); 19645ffd940aSRaphael Isemann 19655ffd940aSRaphael Isemann // If this is a comment, we're done. 19665ffd940aSRaphael Isemann if (CheckTy == Check::CheckComment) 19675ffd940aSRaphael Isemann continue; 19685ffd940aSRaphael Isemann 19695ffd940aSRaphael Isemann // Parse the pattern. 19705ffd940aSRaphael Isemann Pattern P(CheckTy, PatternContext.get(), LineNumber); 19715ffd940aSRaphael Isemann if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req)) 19725ffd940aSRaphael Isemann return true; 19735ffd940aSRaphael Isemann 19745ffd940aSRaphael Isemann // Verify that CHECK-LABEL lines do not define or use variables 19755ffd940aSRaphael Isemann if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { 19765ffd940aSRaphael Isemann SM.PrintMessage( 19775ffd940aSRaphael Isemann SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, 19785ffd940aSRaphael Isemann "found '" + UsedPrefix + "-LABEL:'" 19795ffd940aSRaphael Isemann " with variable definition or use"); 19805ffd940aSRaphael Isemann return true; 19815ffd940aSRaphael Isemann } 19825ffd940aSRaphael Isemann 19835ffd940aSRaphael Isemann // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them. 19845ffd940aSRaphael Isemann if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame || 19855ffd940aSRaphael Isemann CheckTy == Check::CheckEmpty) && 19865ffd940aSRaphael Isemann CheckStrings->empty()) { 19875ffd940aSRaphael Isemann StringRef Type = CheckTy == Check::CheckNext 19885ffd940aSRaphael Isemann ? "NEXT" 19895ffd940aSRaphael Isemann : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME"; 19905ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), 19915ffd940aSRaphael Isemann SourceMgr::DK_Error, 19925ffd940aSRaphael Isemann "found '" + UsedPrefix + "-" + Type + 19935ffd940aSRaphael Isemann "' without previous '" + UsedPrefix + ": line"); 19945ffd940aSRaphael Isemann return true; 19955ffd940aSRaphael Isemann } 19965ffd940aSRaphael Isemann 19975ffd940aSRaphael Isemann // Handle CHECK-DAG/-NOT. 19985ffd940aSRaphael Isemann if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { 19995ffd940aSRaphael Isemann DagNotMatches.push_back(P); 20005ffd940aSRaphael Isemann continue; 20015ffd940aSRaphael Isemann } 20025ffd940aSRaphael Isemann 20035ffd940aSRaphael Isemann // Okay, add the string we captured to the output vector and move on. 20045ffd940aSRaphael Isemann CheckStrings->emplace_back(P, UsedPrefix, PatternLoc); 20055ffd940aSRaphael Isemann std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); 20065ffd940aSRaphael Isemann DagNotMatches = ImplicitNegativeChecks; 20075ffd940aSRaphael Isemann } 20085ffd940aSRaphael Isemann 20095ffd940aSRaphael Isemann // When there are no used prefixes we report an error except in the case that 20105ffd940aSRaphael Isemann // no prefix is specified explicitly but -implicit-check-not is specified. 2011871d658cSMircea Trofin const bool NoPrefixesFound = PrefixesNotFound.size() == DistinctPrefixes; 2012871d658cSMircea Trofin const bool SomePrefixesUnexpectedlyNotUsed = 2013871d658cSMircea Trofin !Req.AllowUnusedPrefixes && !PrefixesNotFound.empty(); 2014871d658cSMircea Trofin if ((NoPrefixesFound || SomePrefixesUnexpectedlyNotUsed) && 20155ffd940aSRaphael Isemann (ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) { 20165ffd940aSRaphael Isemann errs() << "error: no check strings found with prefix" 2017871d658cSMircea Trofin << (PrefixesNotFound.size() > 1 ? "es " : " "); 2018871d658cSMircea Trofin bool First = true; 2019871d658cSMircea Trofin for (StringRef MissingPrefix : PrefixesNotFound) { 2020871d658cSMircea Trofin if (!First) 20215ffd940aSRaphael Isemann errs() << ", "; 2022871d658cSMircea Trofin errs() << "\'" << MissingPrefix << ":'"; 2023871d658cSMircea Trofin First = false; 20245ffd940aSRaphael Isemann } 20255ffd940aSRaphael Isemann errs() << '\n'; 20265ffd940aSRaphael Isemann return true; 20275ffd940aSRaphael Isemann } 20285ffd940aSRaphael Isemann 20295ffd940aSRaphael Isemann // Add an EOF pattern for any trailing --implicit-check-not/CHECK-DAG/-NOTs, 20305ffd940aSRaphael Isemann // and use the first prefix as a filler for the error message. 20315ffd940aSRaphael Isemann if (!DagNotMatches.empty()) { 20325ffd940aSRaphael Isemann CheckStrings->emplace_back( 20335ffd940aSRaphael Isemann Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1), 20345ffd940aSRaphael Isemann *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data())); 20355ffd940aSRaphael Isemann std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); 20365ffd940aSRaphael Isemann } 20375ffd940aSRaphael Isemann 20385ffd940aSRaphael Isemann return false; 20395ffd940aSRaphael Isemann } 20405ffd940aSRaphael Isemann 2041*dd59c132SJoel E. Denny /// Returns either (1) \c ErrorSuccess if there was no error or (2) 2042*dd59c132SJoel E. Denny /// \c ErrorReported if an error was reported, such as an unexpected match. 2043*dd59c132SJoel E. Denny static Error printMatch(bool ExpectedMatch, const SourceMgr &SM, 20445ffd940aSRaphael Isemann StringRef Prefix, SMLoc Loc, const Pattern &Pat, 2045*dd59c132SJoel E. Denny int MatchedCount, StringRef Buffer, 2046*dd59c132SJoel E. Denny Pattern::MatchResult MatchResult, 2047*dd59c132SJoel E. Denny const FileCheckRequest &Req, 20485ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) { 2049*dd59c132SJoel E. Denny // Suppress some verbosity if there's no error. 2050*dd59c132SJoel E. Denny bool HasError = !ExpectedMatch || MatchResult.TheError; 20515ffd940aSRaphael Isemann bool PrintDiag = true; 2052*dd59c132SJoel E. Denny if (!HasError) { 20535ffd940aSRaphael Isemann if (!Req.Verbose) 2054*dd59c132SJoel E. Denny return ErrorReported::reportedOrSuccess(HasError); 20555ffd940aSRaphael Isemann if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF) 2056*dd59c132SJoel E. Denny return ErrorReported::reportedOrSuccess(HasError); 20575ffd940aSRaphael Isemann // Due to their verbosity, we don't print verbose diagnostics here if we're 2058*dd59c132SJoel E. Denny // gathering them for Diags to be rendered elsewhere, but we always print 2059*dd59c132SJoel E. Denny // other diagnostics. 20605ffd940aSRaphael Isemann PrintDiag = !Diags; 20615ffd940aSRaphael Isemann } 2062*dd59c132SJoel E. Denny 2063*dd59c132SJoel E. Denny // Add "found" diagnostic, substitutions, and variable definitions to Diags. 20645ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy = ExpectedMatch 20655ffd940aSRaphael Isemann ? FileCheckDiag::MatchFoundAndExpected 20665ffd940aSRaphael Isemann : FileCheckDiag::MatchFoundButExcluded; 20675ffd940aSRaphael Isemann SMRange MatchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), 2068*dd59c132SJoel E. Denny Buffer, MatchResult.TheMatch->Pos, 2069*dd59c132SJoel E. Denny MatchResult.TheMatch->Len, Diags); 20705ffd940aSRaphael Isemann if (Diags) { 20715ffd940aSRaphael Isemann Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, Diags); 20725ffd940aSRaphael Isemann Pat.printVariableDefs(SM, MatchTy, Diags); 20735ffd940aSRaphael Isemann } 2074*dd59c132SJoel E. Denny if (!PrintDiag) { 2075*dd59c132SJoel E. Denny assert(!HasError && "expected to report more diagnostics for error"); 2076*dd59c132SJoel E. Denny return ErrorReported::reportedOrSuccess(HasError); 2077*dd59c132SJoel E. Denny } 20785ffd940aSRaphael Isemann 2079*dd59c132SJoel E. Denny // Print the match. 20805ffd940aSRaphael Isemann std::string Message = formatv("{0}: {1} string found in input", 20815ffd940aSRaphael Isemann Pat.getCheckTy().getDescription(Prefix), 20825ffd940aSRaphael Isemann (ExpectedMatch ? "expected" : "excluded")) 20835ffd940aSRaphael Isemann .str(); 20845ffd940aSRaphael Isemann if (Pat.getCount() > 1) 20855ffd940aSRaphael Isemann Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); 20865ffd940aSRaphael Isemann SM.PrintMessage( 20875ffd940aSRaphael Isemann Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message); 20885ffd940aSRaphael Isemann SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here", 20895ffd940aSRaphael Isemann {MatchRange}); 2090*dd59c132SJoel E. Denny 2091*dd59c132SJoel E. Denny // Print additional information, which can be useful even if there are errors. 20925ffd940aSRaphael Isemann Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, nullptr); 20935ffd940aSRaphael Isemann Pat.printVariableDefs(SM, MatchTy, nullptr); 2094*dd59c132SJoel E. Denny 2095*dd59c132SJoel E. Denny // Print errors and add them to Diags. We report these errors after the match 2096*dd59c132SJoel E. Denny // itself because we found them after the match. If we had found them before 2097*dd59c132SJoel E. Denny // the match, we'd be in printNoMatch. 2098*dd59c132SJoel E. Denny handleAllErrors(std::move(MatchResult.TheError), 2099*dd59c132SJoel E. Denny [&](const ErrorDiagnostic &E) { 2100*dd59c132SJoel E. Denny E.log(errs()); 2101*dd59c132SJoel E. Denny if (Diags) { 2102*dd59c132SJoel E. Denny Diags->emplace_back(SM, Pat.getCheckTy(), Loc, 2103*dd59c132SJoel E. Denny FileCheckDiag::MatchFoundErrorNote, 2104*dd59c132SJoel E. Denny E.getRange(), E.getMessage().str()); 2105*dd59c132SJoel E. Denny } 2106*dd59c132SJoel E. Denny }); 2107*dd59c132SJoel E. Denny return ErrorReported::reportedOrSuccess(HasError); 21085ffd940aSRaphael Isemann } 21095ffd940aSRaphael Isemann 2110*dd59c132SJoel E. Denny /// Returns either (1) \c ErrorSuccess if there was no error, or (2) 2111*dd59c132SJoel E. Denny /// \c ErrorReported if an error was reported, such as an expected match not 2112*dd59c132SJoel E. Denny /// found. 2113*dd59c132SJoel E. Denny static Error printNoMatch(bool ExpectedMatch, const SourceMgr &SM, 21145ffd940aSRaphael Isemann StringRef Prefix, SMLoc Loc, const Pattern &Pat, 2115*dd59c132SJoel E. Denny int MatchedCount, StringRef Buffer, Error MatchError, 2116*dd59c132SJoel E. Denny bool VerboseVerbose, 2117*dd59c132SJoel E. Denny std::vector<FileCheckDiag> *Diags) { 2118*dd59c132SJoel E. Denny // Print any pattern errors, and record them to be added to Diags later. 2119*dd59c132SJoel E. Denny bool HasError = ExpectedMatch; 2120*dd59c132SJoel E. Denny bool HasPatternError = false; 21215ffd940aSRaphael Isemann FileCheckDiag::MatchType MatchTy = ExpectedMatch 21225ffd940aSRaphael Isemann ? FileCheckDiag::MatchNoneButExpected 21235ffd940aSRaphael Isemann : FileCheckDiag::MatchNoneAndExcluded; 2124*dd59c132SJoel E. Denny SmallVector<std::string, 4> ErrorMsgs; 2125*dd59c132SJoel E. Denny handleAllErrors( 2126*dd59c132SJoel E. Denny std::move(MatchError), 2127*dd59c132SJoel E. Denny [&](const ErrorDiagnostic &E) { 2128*dd59c132SJoel E. Denny HasError = HasPatternError = true; 2129*dd59c132SJoel E. Denny MatchTy = FileCheckDiag::MatchNoneForInvalidPattern; 2130*dd59c132SJoel E. Denny E.log(errs()); 21315ffd940aSRaphael Isemann if (Diags) 2132*dd59c132SJoel E. Denny ErrorMsgs.push_back(E.getMessage().str()); 2133*dd59c132SJoel E. Denny }, 2134*dd59c132SJoel E. Denny // UndefVarError is reported in printSubstitutions below. 2135*dd59c132SJoel E. Denny // FIXME: It probably should be handled as a pattern error and actually 2136*dd59c132SJoel E. Denny // change the exit status to 1, even if !ExpectedMatch. To do so, we 2137*dd59c132SJoel E. Denny // could stop calling printSubstitutions and actually report the error 2138*dd59c132SJoel E. Denny // here as we do ErrorDiagnostic above. 2139*dd59c132SJoel E. Denny [](const UndefVarError &E) {}, 2140*dd59c132SJoel E. Denny // NotFoundError is why printNoMatch was invoked. 2141*dd59c132SJoel E. Denny [](const NotFoundError &E) {}); 2142*dd59c132SJoel E. Denny 2143*dd59c132SJoel E. Denny // Suppress some verbosity if there's no error. 2144*dd59c132SJoel E. Denny bool PrintDiag = true; 2145*dd59c132SJoel E. Denny if (!HasError) { 2146*dd59c132SJoel E. Denny if (!VerboseVerbose) 2147*dd59c132SJoel E. Denny return ErrorReported::reportedOrSuccess(HasError); 2148*dd59c132SJoel E. Denny // Due to their verbosity, we don't print verbose diagnostics here if we're 2149*dd59c132SJoel E. Denny // gathering them for Diags to be rendered elsewhere, but we always print 2150*dd59c132SJoel E. Denny // other diagnostics. 2151*dd59c132SJoel E. Denny PrintDiag = !Diags; 21525ffd940aSRaphael Isemann } 21535ffd940aSRaphael Isemann 2154*dd59c132SJoel E. Denny // Add "not found" diagnostic, substitutions, and pattern errors to Diags. 2155*dd59c132SJoel E. Denny // 2156*dd59c132SJoel E. Denny // We handle Diags a little differently than the errors we print directly: 2157*dd59c132SJoel E. Denny // we add the "not found" diagnostic to Diags even if there are pattern 2158*dd59c132SJoel E. Denny // errors. The reason is that we need to attach pattern errors as notes 2159*dd59c132SJoel E. Denny // somewhere in the input, and the input search range from the "not found" 2160*dd59c132SJoel E. Denny // diagnostic is all we have to anchor them. 2161*dd59c132SJoel E. Denny SMRange SearchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), 2162*dd59c132SJoel E. Denny Buffer, 0, Buffer.size(), Diags); 2163*dd59c132SJoel E. Denny if (Diags) { 2164*dd59c132SJoel E. Denny SMRange NoteRange = SMRange(SearchRange.Start, SearchRange.Start); 2165*dd59c132SJoel E. Denny for (StringRef ErrorMsg : ErrorMsgs) 2166*dd59c132SJoel E. Denny Diags->emplace_back(SM, Pat.getCheckTy(), Loc, MatchTy, NoteRange, 2167*dd59c132SJoel E. Denny ErrorMsg); 2168*dd59c132SJoel E. Denny Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, Diags); 2169*dd59c132SJoel E. Denny } 2170*dd59c132SJoel E. Denny if (!PrintDiag) { 2171*dd59c132SJoel E. Denny assert(!HasError && "expected to report more diagnostics for error"); 2172*dd59c132SJoel E. Denny return ErrorReported::reportedOrSuccess(HasError); 2173*dd59c132SJoel E. Denny } 21745ffd940aSRaphael Isemann 2175*dd59c132SJoel E. Denny // Print "not found" diagnostic, except that's implied if we already printed a 2176*dd59c132SJoel E. Denny // pattern error. 2177*dd59c132SJoel E. Denny if (!HasPatternError) { 21785ffd940aSRaphael Isemann std::string Message = formatv("{0}: {1} string not found in input", 21795ffd940aSRaphael Isemann Pat.getCheckTy().getDescription(Prefix), 21805ffd940aSRaphael Isemann (ExpectedMatch ? "expected" : "excluded")) 21815ffd940aSRaphael Isemann .str(); 21825ffd940aSRaphael Isemann if (Pat.getCount() > 1) 2183*dd59c132SJoel E. Denny Message += 2184*dd59c132SJoel E. Denny formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); 2185*dd59c132SJoel E. Denny SM.PrintMessage(Loc, 2186*dd59c132SJoel E. Denny ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, 2187*dd59c132SJoel E. Denny Message); 2188*dd59c132SJoel E. Denny SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, 2189*dd59c132SJoel E. Denny "scanning from here"); 21905ffd940aSRaphael Isemann } 21915ffd940aSRaphael Isemann 2192*dd59c132SJoel E. Denny // Print additional information, which can be useful even after a pattern 2193*dd59c132SJoel E. Denny // error. 2194*dd59c132SJoel E. Denny Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, nullptr); 2195*dd59c132SJoel E. Denny if (ExpectedMatch) 2196*dd59c132SJoel E. Denny Pat.printFuzzyMatch(SM, Buffer, Diags); 2197*dd59c132SJoel E. Denny return ErrorReported::reportedOrSuccess(HasError); 2198*dd59c132SJoel E. Denny } 2199*dd59c132SJoel E. Denny 2200*dd59c132SJoel E. Denny /// Returns either (1) \c ErrorSuccess if there was no error, or (2) 2201*dd59c132SJoel E. Denny /// \c ErrorReported if an error was reported. 2202*dd59c132SJoel E. Denny static Error reportMatchResult(bool ExpectedMatch, const SourceMgr &SM, 2203*dd59c132SJoel E. Denny StringRef Prefix, SMLoc Loc, const Pattern &Pat, 2204*dd59c132SJoel E. Denny int MatchedCount, StringRef Buffer, 2205*dd59c132SJoel E. Denny Pattern::MatchResult MatchResult, 2206*dd59c132SJoel E. Denny const FileCheckRequest &Req, 2207*dd59c132SJoel E. Denny std::vector<FileCheckDiag> *Diags) { 2208*dd59c132SJoel E. Denny if (MatchResult.TheMatch) 2209*dd59c132SJoel E. Denny return printMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer, 2210*dd59c132SJoel E. Denny std::move(MatchResult), Req, Diags); 2211*dd59c132SJoel E. Denny return printNoMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer, 2212*dd59c132SJoel E. Denny std::move(MatchResult.TheError), Req.VerboseVerbose, 2213*dd59c132SJoel E. Denny Diags); 22145ffd940aSRaphael Isemann } 22155ffd940aSRaphael Isemann 22165ffd940aSRaphael Isemann /// Counts the number of newlines in the specified range. 22175ffd940aSRaphael Isemann static unsigned CountNumNewlinesBetween(StringRef Range, 22185ffd940aSRaphael Isemann const char *&FirstNewLine) { 22195ffd940aSRaphael Isemann unsigned NumNewLines = 0; 22205ffd940aSRaphael Isemann while (1) { 22215ffd940aSRaphael Isemann // Scan for newline. 22225ffd940aSRaphael Isemann Range = Range.substr(Range.find_first_of("\n\r")); 22235ffd940aSRaphael Isemann if (Range.empty()) 22245ffd940aSRaphael Isemann return NumNewLines; 22255ffd940aSRaphael Isemann 22265ffd940aSRaphael Isemann ++NumNewLines; 22275ffd940aSRaphael Isemann 22285ffd940aSRaphael Isemann // Handle \n\r and \r\n as a single newline. 22295ffd940aSRaphael Isemann if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') && 22305ffd940aSRaphael Isemann (Range[0] != Range[1])) 22315ffd940aSRaphael Isemann Range = Range.substr(1); 22325ffd940aSRaphael Isemann Range = Range.substr(1); 22335ffd940aSRaphael Isemann 22345ffd940aSRaphael Isemann if (NumNewLines == 1) 22355ffd940aSRaphael Isemann FirstNewLine = Range.begin(); 22365ffd940aSRaphael Isemann } 22375ffd940aSRaphael Isemann } 22385ffd940aSRaphael Isemann 22395ffd940aSRaphael Isemann size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, 22405ffd940aSRaphael Isemann bool IsLabelScanMode, size_t &MatchLen, 22415ffd940aSRaphael Isemann FileCheckRequest &Req, 22425ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 22435ffd940aSRaphael Isemann size_t LastPos = 0; 22445ffd940aSRaphael Isemann std::vector<const Pattern *> NotStrings; 22455ffd940aSRaphael Isemann 22465ffd940aSRaphael Isemann // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL 22475ffd940aSRaphael Isemann // bounds; we have not processed variable definitions within the bounded block 22485ffd940aSRaphael Isemann // yet so cannot handle any final CHECK-DAG yet; this is handled when going 22495ffd940aSRaphael Isemann // over the block again (including the last CHECK-LABEL) in normal mode. 22505ffd940aSRaphael Isemann if (!IsLabelScanMode) { 22515ffd940aSRaphael Isemann // Match "dag strings" (with mixed "not strings" if any). 22525ffd940aSRaphael Isemann LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags); 22535ffd940aSRaphael Isemann if (LastPos == StringRef::npos) 22545ffd940aSRaphael Isemann return StringRef::npos; 22555ffd940aSRaphael Isemann } 22565ffd940aSRaphael Isemann 22575ffd940aSRaphael Isemann // Match itself from the last position after matching CHECK-DAG. 22585ffd940aSRaphael Isemann size_t LastMatchEnd = LastPos; 22595ffd940aSRaphael Isemann size_t FirstMatchPos = 0; 22605ffd940aSRaphael Isemann // Go match the pattern Count times. Majority of patterns only match with 22615ffd940aSRaphael Isemann // count 1 though. 22625ffd940aSRaphael Isemann assert(Pat.getCount() != 0 && "pattern count can not be zero"); 22635ffd940aSRaphael Isemann for (int i = 1; i <= Pat.getCount(); i++) { 22645ffd940aSRaphael Isemann StringRef MatchBuffer = Buffer.substr(LastMatchEnd); 22655ffd940aSRaphael Isemann // get a match at current start point 2266*dd59c132SJoel E. Denny Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM); 22675ffd940aSRaphael Isemann 22685ffd940aSRaphael Isemann // report 2269*dd59c132SJoel E. Denny if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, Loc, 2270*dd59c132SJoel E. Denny Pat, i, MatchBuffer, 2271*dd59c132SJoel E. Denny std::move(MatchResult), Req, Diags)) { 2272*dd59c132SJoel E. Denny cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {})); 22735ffd940aSRaphael Isemann return StringRef::npos; 22745ffd940aSRaphael Isemann } 2275*dd59c132SJoel E. Denny 2276*dd59c132SJoel E. Denny size_t MatchPos = MatchResult.TheMatch->Pos; 22775ffd940aSRaphael Isemann if (i == 1) 22785ffd940aSRaphael Isemann FirstMatchPos = LastPos + MatchPos; 22795ffd940aSRaphael Isemann 22805ffd940aSRaphael Isemann // move start point after the match 2281*dd59c132SJoel E. Denny LastMatchEnd += MatchPos + MatchResult.TheMatch->Len; 22825ffd940aSRaphael Isemann } 22835ffd940aSRaphael Isemann // Full match len counts from first match pos. 22845ffd940aSRaphael Isemann MatchLen = LastMatchEnd - FirstMatchPos; 22855ffd940aSRaphael Isemann 22865ffd940aSRaphael Isemann // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT 22875ffd940aSRaphael Isemann // or CHECK-NOT 22885ffd940aSRaphael Isemann if (!IsLabelScanMode) { 22895ffd940aSRaphael Isemann size_t MatchPos = FirstMatchPos - LastPos; 22905ffd940aSRaphael Isemann StringRef MatchBuffer = Buffer.substr(LastPos); 22915ffd940aSRaphael Isemann StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); 22925ffd940aSRaphael Isemann 22935ffd940aSRaphael Isemann // If this check is a "CHECK-NEXT", verify that the previous match was on 22945ffd940aSRaphael Isemann // the previous line (i.e. that there is one newline between them). 22955ffd940aSRaphael Isemann if (CheckNext(SM, SkippedRegion)) { 22965ffd940aSRaphael Isemann ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, 22975ffd940aSRaphael Isemann Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, 22985ffd940aSRaphael Isemann Diags, Req.Verbose); 22995ffd940aSRaphael Isemann return StringRef::npos; 23005ffd940aSRaphael Isemann } 23015ffd940aSRaphael Isemann 23025ffd940aSRaphael Isemann // If this check is a "CHECK-SAME", verify that the previous match was on 23035ffd940aSRaphael Isemann // the same line (i.e. that there is no newline between them). 23045ffd940aSRaphael Isemann if (CheckSame(SM, SkippedRegion)) { 23055ffd940aSRaphael Isemann ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc, 23065ffd940aSRaphael Isemann Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, 23075ffd940aSRaphael Isemann Diags, Req.Verbose); 23085ffd940aSRaphael Isemann return StringRef::npos; 23095ffd940aSRaphael Isemann } 23105ffd940aSRaphael Isemann 23115ffd940aSRaphael Isemann // If this match had "not strings", verify that they don't exist in the 23125ffd940aSRaphael Isemann // skipped region. 23135ffd940aSRaphael Isemann if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) 23145ffd940aSRaphael Isemann return StringRef::npos; 23155ffd940aSRaphael Isemann } 23165ffd940aSRaphael Isemann 23175ffd940aSRaphael Isemann return FirstMatchPos; 23185ffd940aSRaphael Isemann } 23195ffd940aSRaphael Isemann 23205ffd940aSRaphael Isemann bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { 23215ffd940aSRaphael Isemann if (Pat.getCheckTy() != Check::CheckNext && 23225ffd940aSRaphael Isemann Pat.getCheckTy() != Check::CheckEmpty) 23235ffd940aSRaphael Isemann return false; 23245ffd940aSRaphael Isemann 23255ffd940aSRaphael Isemann Twine CheckName = 23265ffd940aSRaphael Isemann Prefix + 23275ffd940aSRaphael Isemann Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT"); 23285ffd940aSRaphael Isemann 23295ffd940aSRaphael Isemann // Count the number of newlines between the previous match and this one. 23305ffd940aSRaphael Isemann const char *FirstNewLine = nullptr; 23315ffd940aSRaphael Isemann unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); 23325ffd940aSRaphael Isemann 23335ffd940aSRaphael Isemann if (NumNewLines == 0) { 23345ffd940aSRaphael Isemann SM.PrintMessage(Loc, SourceMgr::DK_Error, 23355ffd940aSRaphael Isemann CheckName + ": is on the same line as previous match"); 23365ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 23375ffd940aSRaphael Isemann "'next' match was here"); 23385ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 23395ffd940aSRaphael Isemann "previous match ended here"); 23405ffd940aSRaphael Isemann return true; 23415ffd940aSRaphael Isemann } 23425ffd940aSRaphael Isemann 23435ffd940aSRaphael Isemann if (NumNewLines != 1) { 23445ffd940aSRaphael Isemann SM.PrintMessage(Loc, SourceMgr::DK_Error, 23455ffd940aSRaphael Isemann CheckName + 23465ffd940aSRaphael Isemann ": is not on the line after the previous match"); 23475ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 23485ffd940aSRaphael Isemann "'next' match was here"); 23495ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 23505ffd940aSRaphael Isemann "previous match ended here"); 23515ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note, 23525ffd940aSRaphael Isemann "non-matching line after previous match is here"); 23535ffd940aSRaphael Isemann return true; 23545ffd940aSRaphael Isemann } 23555ffd940aSRaphael Isemann 23565ffd940aSRaphael Isemann return false; 23575ffd940aSRaphael Isemann } 23585ffd940aSRaphael Isemann 23595ffd940aSRaphael Isemann bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { 23605ffd940aSRaphael Isemann if (Pat.getCheckTy() != Check::CheckSame) 23615ffd940aSRaphael Isemann return false; 23625ffd940aSRaphael Isemann 23635ffd940aSRaphael Isemann // Count the number of newlines between the previous match and this one. 23645ffd940aSRaphael Isemann const char *FirstNewLine = nullptr; 23655ffd940aSRaphael Isemann unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); 23665ffd940aSRaphael Isemann 23675ffd940aSRaphael Isemann if (NumNewLines != 0) { 23685ffd940aSRaphael Isemann SM.PrintMessage(Loc, SourceMgr::DK_Error, 23695ffd940aSRaphael Isemann Prefix + 23705ffd940aSRaphael Isemann "-SAME: is not on the same line as the previous match"); 23715ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, 23725ffd940aSRaphael Isemann "'next' match was here"); 23735ffd940aSRaphael Isemann SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, 23745ffd940aSRaphael Isemann "previous match ended here"); 23755ffd940aSRaphael Isemann return true; 23765ffd940aSRaphael Isemann } 23775ffd940aSRaphael Isemann 23785ffd940aSRaphael Isemann return false; 23795ffd940aSRaphael Isemann } 23805ffd940aSRaphael Isemann 23815ffd940aSRaphael Isemann bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, 23825ffd940aSRaphael Isemann const std::vector<const Pattern *> &NotStrings, 23835ffd940aSRaphael Isemann const FileCheckRequest &Req, 23845ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 23855ffd940aSRaphael Isemann bool DirectiveFail = false; 23865ffd940aSRaphael Isemann for (const Pattern *Pat : NotStrings) { 23875ffd940aSRaphael Isemann assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); 2388*dd59c132SJoel E. Denny Pattern::MatchResult MatchResult = Pat->match(Buffer, SM); 2389*dd59c132SJoel E. Denny if (Error Err = reportMatchResult(/*ExpectedMatch=*/false, SM, Prefix, 2390*dd59c132SJoel E. Denny Pat->getLoc(), *Pat, 1, Buffer, 2391*dd59c132SJoel E. Denny std::move(MatchResult), Req, Diags)) { 2392*dd59c132SJoel E. Denny cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {})); 2393*dd59c132SJoel E. Denny DirectiveFail = true; 23945ffd940aSRaphael Isemann continue; 23955ffd940aSRaphael Isemann } 23965ffd940aSRaphael Isemann } 23975ffd940aSRaphael Isemann return DirectiveFail; 23985ffd940aSRaphael Isemann } 23995ffd940aSRaphael Isemann 24005ffd940aSRaphael Isemann size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, 24015ffd940aSRaphael Isemann std::vector<const Pattern *> &NotStrings, 24025ffd940aSRaphael Isemann const FileCheckRequest &Req, 24035ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) const { 24045ffd940aSRaphael Isemann if (DagNotStrings.empty()) 24055ffd940aSRaphael Isemann return 0; 24065ffd940aSRaphael Isemann 24075ffd940aSRaphael Isemann // The start of the search range. 24085ffd940aSRaphael Isemann size_t StartPos = 0; 24095ffd940aSRaphael Isemann 24105ffd940aSRaphael Isemann struct MatchRange { 24115ffd940aSRaphael Isemann size_t Pos; 24125ffd940aSRaphael Isemann size_t End; 24135ffd940aSRaphael Isemann }; 24145ffd940aSRaphael Isemann // A sorted list of ranges for non-overlapping CHECK-DAG matches. Match 24155ffd940aSRaphael Isemann // ranges are erased from this list once they are no longer in the search 24165ffd940aSRaphael Isemann // range. 24175ffd940aSRaphael Isemann std::list<MatchRange> MatchRanges; 24185ffd940aSRaphael Isemann 24195ffd940aSRaphael Isemann // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG 24205ffd940aSRaphael Isemann // group, so we don't use a range-based for loop here. 24215ffd940aSRaphael Isemann for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end(); 24225ffd940aSRaphael Isemann PatItr != PatEnd; ++PatItr) { 24235ffd940aSRaphael Isemann const Pattern &Pat = *PatItr; 24245ffd940aSRaphael Isemann assert((Pat.getCheckTy() == Check::CheckDAG || 24255ffd940aSRaphael Isemann Pat.getCheckTy() == Check::CheckNot) && 24265ffd940aSRaphael Isemann "Invalid CHECK-DAG or CHECK-NOT!"); 24275ffd940aSRaphael Isemann 24285ffd940aSRaphael Isemann if (Pat.getCheckTy() == Check::CheckNot) { 24295ffd940aSRaphael Isemann NotStrings.push_back(&Pat); 24305ffd940aSRaphael Isemann continue; 24315ffd940aSRaphael Isemann } 24325ffd940aSRaphael Isemann 24335ffd940aSRaphael Isemann assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); 24345ffd940aSRaphael Isemann 24355ffd940aSRaphael Isemann // CHECK-DAG always matches from the start. 24365ffd940aSRaphael Isemann size_t MatchLen = 0, MatchPos = StartPos; 24375ffd940aSRaphael Isemann 24385ffd940aSRaphael Isemann // Search for a match that doesn't overlap a previous match in this 24395ffd940aSRaphael Isemann // CHECK-DAG group. 24405ffd940aSRaphael Isemann for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) { 24415ffd940aSRaphael Isemann StringRef MatchBuffer = Buffer.substr(MatchPos); 2442*dd59c132SJoel E. Denny Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM); 24435ffd940aSRaphael Isemann // With a group of CHECK-DAGs, a single mismatching means the match on 24445ffd940aSRaphael Isemann // that group of CHECK-DAGs fails immediately. 2445*dd59c132SJoel E. Denny if (MatchResult.TheError || Req.VerboseVerbose) { 2446*dd59c132SJoel E. Denny if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, 2447*dd59c132SJoel E. Denny Pat.getLoc(), Pat, 1, MatchBuffer, 2448*dd59c132SJoel E. Denny std::move(MatchResult), Req, Diags)) { 2449*dd59c132SJoel E. Denny cantFail( 2450*dd59c132SJoel E. Denny handleErrors(std::move(Err), [&](const ErrorReported &E) {})); 24515ffd940aSRaphael Isemann return StringRef::npos; 24525ffd940aSRaphael Isemann } 2453*dd59c132SJoel E. Denny } 2454*dd59c132SJoel E. Denny MatchLen = MatchResult.TheMatch->Len; 2455*dd59c132SJoel E. Denny // Re-calc it as the offset relative to the start of the original 2456*dd59c132SJoel E. Denny // string. 2457*dd59c132SJoel E. Denny MatchPos += MatchResult.TheMatch->Pos; 24585ffd940aSRaphael Isemann MatchRange M{MatchPos, MatchPos + MatchLen}; 24595ffd940aSRaphael Isemann if (Req.AllowDeprecatedDagOverlap) { 24605ffd940aSRaphael Isemann // We don't need to track all matches in this mode, so we just maintain 24615ffd940aSRaphael Isemann // one match range that encompasses the current CHECK-DAG group's 24625ffd940aSRaphael Isemann // matches. 24635ffd940aSRaphael Isemann if (MatchRanges.empty()) 24645ffd940aSRaphael Isemann MatchRanges.insert(MatchRanges.end(), M); 24655ffd940aSRaphael Isemann else { 24665ffd940aSRaphael Isemann auto Block = MatchRanges.begin(); 24675ffd940aSRaphael Isemann Block->Pos = std::min(Block->Pos, M.Pos); 24685ffd940aSRaphael Isemann Block->End = std::max(Block->End, M.End); 24695ffd940aSRaphael Isemann } 24705ffd940aSRaphael Isemann break; 24715ffd940aSRaphael Isemann } 24725ffd940aSRaphael Isemann // Iterate previous matches until overlapping match or insertion point. 24735ffd940aSRaphael Isemann bool Overlap = false; 24745ffd940aSRaphael Isemann for (; MI != ME; ++MI) { 24755ffd940aSRaphael Isemann if (M.Pos < MI->End) { 24765ffd940aSRaphael Isemann // !Overlap => New match has no overlap and is before this old match. 24775ffd940aSRaphael Isemann // Overlap => New match overlaps this old match. 24785ffd940aSRaphael Isemann Overlap = MI->Pos < M.End; 24795ffd940aSRaphael Isemann break; 24805ffd940aSRaphael Isemann } 24815ffd940aSRaphael Isemann } 24825ffd940aSRaphael Isemann if (!Overlap) { 24835ffd940aSRaphael Isemann // Insert non-overlapping match into list. 24845ffd940aSRaphael Isemann MatchRanges.insert(MI, M); 24855ffd940aSRaphael Isemann break; 24865ffd940aSRaphael Isemann } 24875ffd940aSRaphael Isemann if (Req.VerboseVerbose) { 24885ffd940aSRaphael Isemann // Due to their verbosity, we don't print verbose diagnostics here if 24895ffd940aSRaphael Isemann // we're gathering them for a different rendering, but we always print 24905ffd940aSRaphael Isemann // other diagnostics. 24915ffd940aSRaphael Isemann if (!Diags) { 24925ffd940aSRaphael Isemann SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos); 24935ffd940aSRaphael Isemann SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End); 24945ffd940aSRaphael Isemann SMRange OldRange(OldStart, OldEnd); 24955ffd940aSRaphael Isemann SM.PrintMessage(OldStart, SourceMgr::DK_Note, 24965ffd940aSRaphael Isemann "match discarded, overlaps earlier DAG match here", 24975ffd940aSRaphael Isemann {OldRange}); 24985ffd940aSRaphael Isemann } else { 24995ffd940aSRaphael Isemann SMLoc CheckLoc = Diags->rbegin()->CheckLoc; 25005ffd940aSRaphael Isemann for (auto I = Diags->rbegin(), E = Diags->rend(); 25015ffd940aSRaphael Isemann I != E && I->CheckLoc == CheckLoc; ++I) 25025ffd940aSRaphael Isemann I->MatchTy = FileCheckDiag::MatchFoundButDiscarded; 25035ffd940aSRaphael Isemann } 25045ffd940aSRaphael Isemann } 25055ffd940aSRaphael Isemann MatchPos = MI->End; 25065ffd940aSRaphael Isemann } 25075ffd940aSRaphael Isemann if (!Req.VerboseVerbose) 2508*dd59c132SJoel E. Denny cantFail(printMatch( 2509*dd59c132SJoel E. Denny /*ExpectedMatch=*/true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, 2510*dd59c132SJoel E. Denny Pattern::MatchResult(MatchPos, MatchLen, Error::success()), Req, 2511*dd59c132SJoel E. Denny Diags)); 25125ffd940aSRaphael Isemann 25135ffd940aSRaphael Isemann // Handle the end of a CHECK-DAG group. 25145ffd940aSRaphael Isemann if (std::next(PatItr) == PatEnd || 25155ffd940aSRaphael Isemann std::next(PatItr)->getCheckTy() == Check::CheckNot) { 25165ffd940aSRaphael Isemann if (!NotStrings.empty()) { 25175ffd940aSRaphael Isemann // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to 25185ffd940aSRaphael Isemann // CHECK-DAG, verify that there are no 'not' strings occurred in that 25195ffd940aSRaphael Isemann // region. 25205ffd940aSRaphael Isemann StringRef SkippedRegion = 25215ffd940aSRaphael Isemann Buffer.slice(StartPos, MatchRanges.begin()->Pos); 25225ffd940aSRaphael Isemann if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) 25235ffd940aSRaphael Isemann return StringRef::npos; 25245ffd940aSRaphael Isemann // Clear "not strings". 25255ffd940aSRaphael Isemann NotStrings.clear(); 25265ffd940aSRaphael Isemann } 25275ffd940aSRaphael Isemann // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the 25285ffd940aSRaphael Isemann // end of this CHECK-DAG group's match range. 25295ffd940aSRaphael Isemann StartPos = MatchRanges.rbegin()->End; 25305ffd940aSRaphael Isemann // Don't waste time checking for (impossible) overlaps before that. 25315ffd940aSRaphael Isemann MatchRanges.clear(); 25325ffd940aSRaphael Isemann } 25335ffd940aSRaphael Isemann } 25345ffd940aSRaphael Isemann 25355ffd940aSRaphael Isemann return StartPos; 25365ffd940aSRaphael Isemann } 25375ffd940aSRaphael Isemann 25385ffd940aSRaphael Isemann static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, 25395ffd940aSRaphael Isemann ArrayRef<StringRef> SuppliedPrefixes) { 25405ffd940aSRaphael Isemann for (StringRef Prefix : SuppliedPrefixes) { 25415ffd940aSRaphael Isemann if (Prefix.empty()) { 25425ffd940aSRaphael Isemann errs() << "error: supplied " << Kind << " prefix must not be the empty " 25435ffd940aSRaphael Isemann << "string\n"; 25445ffd940aSRaphael Isemann return false; 25455ffd940aSRaphael Isemann } 25465ffd940aSRaphael Isemann static const Regex Validator("^[a-zA-Z0-9_-]*$"); 25475ffd940aSRaphael Isemann if (!Validator.match(Prefix)) { 25485ffd940aSRaphael Isemann errs() << "error: supplied " << Kind << " prefix must start with a " 25495ffd940aSRaphael Isemann << "letter and contain only alphanumeric characters, hyphens, and " 25505ffd940aSRaphael Isemann << "underscores: '" << Prefix << "'\n"; 25515ffd940aSRaphael Isemann return false; 25525ffd940aSRaphael Isemann } 25535ffd940aSRaphael Isemann if (!UniquePrefixes.insert(Prefix).second) { 25545ffd940aSRaphael Isemann errs() << "error: supplied " << Kind << " prefix must be unique among " 25555ffd940aSRaphael Isemann << "check and comment prefixes: '" << Prefix << "'\n"; 25565ffd940aSRaphael Isemann return false; 25575ffd940aSRaphael Isemann } 25585ffd940aSRaphael Isemann } 25595ffd940aSRaphael Isemann return true; 25605ffd940aSRaphael Isemann } 25615ffd940aSRaphael Isemann 25625ffd940aSRaphael Isemann static const char *DefaultCheckPrefixes[] = {"CHECK"}; 25635ffd940aSRaphael Isemann static const char *DefaultCommentPrefixes[] = {"COM", "RUN"}; 25645ffd940aSRaphael Isemann 25655ffd940aSRaphael Isemann bool FileCheck::ValidateCheckPrefixes() { 25665ffd940aSRaphael Isemann StringSet<> UniquePrefixes; 25675ffd940aSRaphael Isemann // Add default prefixes to catch user-supplied duplicates of them below. 25685ffd940aSRaphael Isemann if (Req.CheckPrefixes.empty()) { 25695ffd940aSRaphael Isemann for (const char *Prefix : DefaultCheckPrefixes) 25705ffd940aSRaphael Isemann UniquePrefixes.insert(Prefix); 25715ffd940aSRaphael Isemann } 25725ffd940aSRaphael Isemann if (Req.CommentPrefixes.empty()) { 25735ffd940aSRaphael Isemann for (const char *Prefix : DefaultCommentPrefixes) 25745ffd940aSRaphael Isemann UniquePrefixes.insert(Prefix); 25755ffd940aSRaphael Isemann } 25765ffd940aSRaphael Isemann // Do not validate the default prefixes, or diagnostics about duplicates might 25775ffd940aSRaphael Isemann // incorrectly indicate that they were supplied by the user. 25785ffd940aSRaphael Isemann if (!ValidatePrefixes("check", UniquePrefixes, Req.CheckPrefixes)) 25795ffd940aSRaphael Isemann return false; 25805ffd940aSRaphael Isemann if (!ValidatePrefixes("comment", UniquePrefixes, Req.CommentPrefixes)) 25815ffd940aSRaphael Isemann return false; 25825ffd940aSRaphael Isemann return true; 25835ffd940aSRaphael Isemann } 25845ffd940aSRaphael Isemann 25855ffd940aSRaphael Isemann Regex FileCheck::buildCheckPrefixRegex() { 25865ffd940aSRaphael Isemann if (Req.CheckPrefixes.empty()) { 25875ffd940aSRaphael Isemann for (const char *Prefix : DefaultCheckPrefixes) 25885ffd940aSRaphael Isemann Req.CheckPrefixes.push_back(Prefix); 25895ffd940aSRaphael Isemann Req.IsDefaultCheckPrefix = true; 25905ffd940aSRaphael Isemann } 25915ffd940aSRaphael Isemann if (Req.CommentPrefixes.empty()) { 25925ffd940aSRaphael Isemann for (const char *Prefix : DefaultCommentPrefixes) 25935ffd940aSRaphael Isemann Req.CommentPrefixes.push_back(Prefix); 25945ffd940aSRaphael Isemann } 25955ffd940aSRaphael Isemann 25965ffd940aSRaphael Isemann // We already validated the contents of CheckPrefixes and CommentPrefixes so 25975ffd940aSRaphael Isemann // just concatenate them as alternatives. 25985ffd940aSRaphael Isemann SmallString<32> PrefixRegexStr; 25995ffd940aSRaphael Isemann for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { 26005ffd940aSRaphael Isemann if (I != 0) 26015ffd940aSRaphael Isemann PrefixRegexStr.push_back('|'); 26025ffd940aSRaphael Isemann PrefixRegexStr.append(Req.CheckPrefixes[I]); 26035ffd940aSRaphael Isemann } 26045ffd940aSRaphael Isemann for (StringRef Prefix : Req.CommentPrefixes) { 26055ffd940aSRaphael Isemann PrefixRegexStr.push_back('|'); 26065ffd940aSRaphael Isemann PrefixRegexStr.append(Prefix); 26075ffd940aSRaphael Isemann } 26085ffd940aSRaphael Isemann 26095ffd940aSRaphael Isemann return Regex(PrefixRegexStr); 26105ffd940aSRaphael Isemann } 26115ffd940aSRaphael Isemann 26125ffd940aSRaphael Isemann Error FileCheckPatternContext::defineCmdlineVariables( 26135ffd940aSRaphael Isemann ArrayRef<StringRef> CmdlineDefines, SourceMgr &SM) { 26145ffd940aSRaphael Isemann assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() && 26155ffd940aSRaphael Isemann "Overriding defined variable with command-line variable definitions"); 26165ffd940aSRaphael Isemann 26175ffd940aSRaphael Isemann if (CmdlineDefines.empty()) 26185ffd940aSRaphael Isemann return Error::success(); 26195ffd940aSRaphael Isemann 26205ffd940aSRaphael Isemann // Create a string representing the vector of command-line definitions. Each 26215ffd940aSRaphael Isemann // definition is on its own line and prefixed with a definition number to 26225ffd940aSRaphael Isemann // clarify which definition a given diagnostic corresponds to. 26235ffd940aSRaphael Isemann unsigned I = 0; 26245ffd940aSRaphael Isemann Error Errs = Error::success(); 26255ffd940aSRaphael Isemann std::string CmdlineDefsDiag; 26265ffd940aSRaphael Isemann SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices; 26275ffd940aSRaphael Isemann for (StringRef CmdlineDef : CmdlineDefines) { 26285ffd940aSRaphael Isemann std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str(); 26295ffd940aSRaphael Isemann size_t EqIdx = CmdlineDef.find('='); 26305ffd940aSRaphael Isemann if (EqIdx == StringRef::npos) { 26315ffd940aSRaphael Isemann CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0)); 26325ffd940aSRaphael Isemann continue; 26335ffd940aSRaphael Isemann } 26345ffd940aSRaphael Isemann // Numeric variable definition. 26355ffd940aSRaphael Isemann if (CmdlineDef[0] == '#') { 26365ffd940aSRaphael Isemann // Append a copy of the command-line definition adapted to use the same 26375ffd940aSRaphael Isemann // format as in the input file to be able to reuse 26385ffd940aSRaphael Isemann // parseNumericSubstitutionBlock. 26395ffd940aSRaphael Isemann CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str(); 26405ffd940aSRaphael Isemann std::string SubstitutionStr = std::string(CmdlineDef); 26415ffd940aSRaphael Isemann SubstitutionStr[EqIdx] = ':'; 26425ffd940aSRaphael Isemann CmdlineDefsIndices.push_back( 26435ffd940aSRaphael Isemann std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size())); 26445ffd940aSRaphael Isemann CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str(); 26455ffd940aSRaphael Isemann } else { 26465ffd940aSRaphael Isemann CmdlineDefsDiag += DefPrefix; 26475ffd940aSRaphael Isemann CmdlineDefsIndices.push_back( 26485ffd940aSRaphael Isemann std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size())); 26495ffd940aSRaphael Isemann CmdlineDefsDiag += (CmdlineDef + "\n").str(); 26505ffd940aSRaphael Isemann } 26515ffd940aSRaphael Isemann } 26525ffd940aSRaphael Isemann 26535ffd940aSRaphael Isemann // Create a buffer with fake command line content in order to display 26545ffd940aSRaphael Isemann // parsing diagnostic with location information and point to the 26555ffd940aSRaphael Isemann // global definition with invalid syntax. 26565ffd940aSRaphael Isemann std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer = 26575ffd940aSRaphael Isemann MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines"); 26585ffd940aSRaphael Isemann StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer(); 26595ffd940aSRaphael Isemann SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc()); 26605ffd940aSRaphael Isemann 26615ffd940aSRaphael Isemann for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) { 26625ffd940aSRaphael Isemann StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first, 26635ffd940aSRaphael Isemann CmdlineDefIndices.second); 26645ffd940aSRaphael Isemann if (CmdlineDef.empty()) { 26655ffd940aSRaphael Isemann Errs = joinErrors( 26665ffd940aSRaphael Isemann std::move(Errs), 26675ffd940aSRaphael Isemann ErrorDiagnostic::get(SM, CmdlineDef, 26685ffd940aSRaphael Isemann "missing equal sign in global definition")); 26695ffd940aSRaphael Isemann continue; 26705ffd940aSRaphael Isemann } 26715ffd940aSRaphael Isemann 26725ffd940aSRaphael Isemann // Numeric variable definition. 26735ffd940aSRaphael Isemann if (CmdlineDef[0] == '#') { 26745ffd940aSRaphael Isemann // Now parse the definition both to check that the syntax is correct and 26755ffd940aSRaphael Isemann // to create the necessary class instance. 26765ffd940aSRaphael Isemann StringRef CmdlineDefExpr = CmdlineDef.substr(1); 26775ffd940aSRaphael Isemann Optional<NumericVariable *> DefinedNumericVariable; 26785ffd940aSRaphael Isemann Expected<std::unique_ptr<Expression>> ExpressionResult = 26795ffd940aSRaphael Isemann Pattern::parseNumericSubstitutionBlock( 26805ffd940aSRaphael Isemann CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM); 26815ffd940aSRaphael Isemann if (!ExpressionResult) { 26825ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), ExpressionResult.takeError()); 26835ffd940aSRaphael Isemann continue; 26845ffd940aSRaphael Isemann } 26855ffd940aSRaphael Isemann std::unique_ptr<Expression> Expression = std::move(*ExpressionResult); 26865ffd940aSRaphael Isemann // Now evaluate the expression whose value this variable should be set 26875ffd940aSRaphael Isemann // to, since the expression of a command-line variable definition should 26885ffd940aSRaphael Isemann // only use variables defined earlier on the command-line. If not, this 26895ffd940aSRaphael Isemann // is an error and we report it. 26905ffd940aSRaphael Isemann Expected<ExpressionValue> Value = Expression->getAST()->eval(); 26915ffd940aSRaphael Isemann if (!Value) { 26925ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), Value.takeError()); 26935ffd940aSRaphael Isemann continue; 26945ffd940aSRaphael Isemann } 26955ffd940aSRaphael Isemann 26965ffd940aSRaphael Isemann assert(DefinedNumericVariable && "No variable defined"); 26975ffd940aSRaphael Isemann (*DefinedNumericVariable)->setValue(*Value); 26985ffd940aSRaphael Isemann 26995ffd940aSRaphael Isemann // Record this variable definition. 27005ffd940aSRaphael Isemann GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] = 27015ffd940aSRaphael Isemann *DefinedNumericVariable; 27025ffd940aSRaphael Isemann } else { 27035ffd940aSRaphael Isemann // String variable definition. 27045ffd940aSRaphael Isemann std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('='); 27055ffd940aSRaphael Isemann StringRef CmdlineName = CmdlineNameVal.first; 27065ffd940aSRaphael Isemann StringRef OrigCmdlineName = CmdlineName; 27075ffd940aSRaphael Isemann Expected<Pattern::VariableProperties> ParseVarResult = 27085ffd940aSRaphael Isemann Pattern::parseVariable(CmdlineName, SM); 27095ffd940aSRaphael Isemann if (!ParseVarResult) { 27105ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), ParseVarResult.takeError()); 27115ffd940aSRaphael Isemann continue; 27125ffd940aSRaphael Isemann } 27135ffd940aSRaphael Isemann // Check that CmdlineName does not denote a pseudo variable is only 27145ffd940aSRaphael Isemann // composed of the parsed numeric variable. This catches cases like 27155ffd940aSRaphael Isemann // "FOO+2" in a "FOO+2=10" definition. 27165ffd940aSRaphael Isemann if (ParseVarResult->IsPseudo || !CmdlineName.empty()) { 27175ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), 27185ffd940aSRaphael Isemann ErrorDiagnostic::get( 27195ffd940aSRaphael Isemann SM, OrigCmdlineName, 27205ffd940aSRaphael Isemann "invalid name in string variable definition '" + 27215ffd940aSRaphael Isemann OrigCmdlineName + "'")); 27225ffd940aSRaphael Isemann continue; 27235ffd940aSRaphael Isemann } 27245ffd940aSRaphael Isemann StringRef Name = ParseVarResult->Name; 27255ffd940aSRaphael Isemann 27265ffd940aSRaphael Isemann // Detect collisions between string and numeric variables when the former 27275ffd940aSRaphael Isemann // is created later than the latter. 27285ffd940aSRaphael Isemann if (GlobalNumericVariableTable.find(Name) != 27295ffd940aSRaphael Isemann GlobalNumericVariableTable.end()) { 27305ffd940aSRaphael Isemann Errs = joinErrors(std::move(Errs), 27315ffd940aSRaphael Isemann ErrorDiagnostic::get(SM, Name, 27325ffd940aSRaphael Isemann "numeric variable with name '" + 27335ffd940aSRaphael Isemann Name + "' already exists")); 27345ffd940aSRaphael Isemann continue; 27355ffd940aSRaphael Isemann } 27365ffd940aSRaphael Isemann GlobalVariableTable.insert(CmdlineNameVal); 27375ffd940aSRaphael Isemann // Mark the string variable as defined to detect collisions between 27385ffd940aSRaphael Isemann // string and numeric variables in defineCmdlineVariables when the latter 27395ffd940aSRaphael Isemann // is created later than the former. We cannot reuse GlobalVariableTable 27405ffd940aSRaphael Isemann // for this by populating it with an empty string since we would then 27415ffd940aSRaphael Isemann // lose the ability to detect the use of an undefined variable in 27425ffd940aSRaphael Isemann // match(). 27435ffd940aSRaphael Isemann DefinedVariableTable[Name] = true; 27445ffd940aSRaphael Isemann } 27455ffd940aSRaphael Isemann } 27465ffd940aSRaphael Isemann 27475ffd940aSRaphael Isemann return Errs; 27485ffd940aSRaphael Isemann } 27495ffd940aSRaphael Isemann 27505ffd940aSRaphael Isemann void FileCheckPatternContext::clearLocalVars() { 27515ffd940aSRaphael Isemann SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars; 27525ffd940aSRaphael Isemann for (const StringMapEntry<StringRef> &Var : GlobalVariableTable) 27535ffd940aSRaphael Isemann if (Var.first()[0] != '$') 27545ffd940aSRaphael Isemann LocalPatternVars.push_back(Var.first()); 27555ffd940aSRaphael Isemann 27565ffd940aSRaphael Isemann // Numeric substitution reads the value of a variable directly, not via 27575ffd940aSRaphael Isemann // GlobalNumericVariableTable. Therefore, we clear local variables by 27585ffd940aSRaphael Isemann // clearing their value which will lead to a numeric substitution failure. We 27595ffd940aSRaphael Isemann // also mark the variable for removal from GlobalNumericVariableTable since 27605ffd940aSRaphael Isemann // this is what defineCmdlineVariables checks to decide that no global 27615ffd940aSRaphael Isemann // variable has been defined. 27625ffd940aSRaphael Isemann for (const auto &Var : GlobalNumericVariableTable) 27635ffd940aSRaphael Isemann if (Var.first()[0] != '$') { 27645ffd940aSRaphael Isemann Var.getValue()->clearValue(); 27655ffd940aSRaphael Isemann LocalNumericVars.push_back(Var.first()); 27665ffd940aSRaphael Isemann } 27675ffd940aSRaphael Isemann 27685ffd940aSRaphael Isemann for (const auto &Var : LocalPatternVars) 27695ffd940aSRaphael Isemann GlobalVariableTable.erase(Var); 27705ffd940aSRaphael Isemann for (const auto &Var : LocalNumericVars) 27715ffd940aSRaphael Isemann GlobalNumericVariableTable.erase(Var); 27725ffd940aSRaphael Isemann } 27735ffd940aSRaphael Isemann 27745ffd940aSRaphael Isemann bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer, 27755ffd940aSRaphael Isemann std::vector<FileCheckDiag> *Diags) { 27765ffd940aSRaphael Isemann bool ChecksFailed = false; 27775ffd940aSRaphael Isemann 27785ffd940aSRaphael Isemann unsigned i = 0, j = 0, e = CheckStrings->size(); 27795ffd940aSRaphael Isemann while (true) { 27805ffd940aSRaphael Isemann StringRef CheckRegion; 27815ffd940aSRaphael Isemann if (j == e) { 27825ffd940aSRaphael Isemann CheckRegion = Buffer; 27835ffd940aSRaphael Isemann } else { 27845ffd940aSRaphael Isemann const FileCheckString &CheckLabelStr = (*CheckStrings)[j]; 27855ffd940aSRaphael Isemann if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) { 27865ffd940aSRaphael Isemann ++j; 27875ffd940aSRaphael Isemann continue; 27885ffd940aSRaphael Isemann } 27895ffd940aSRaphael Isemann 27905ffd940aSRaphael Isemann // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG 27915ffd940aSRaphael Isemann size_t MatchLabelLen = 0; 27925ffd940aSRaphael Isemann size_t MatchLabelPos = 27935ffd940aSRaphael Isemann CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags); 27945ffd940aSRaphael Isemann if (MatchLabelPos == StringRef::npos) 27955ffd940aSRaphael Isemann // Immediately bail if CHECK-LABEL fails, nothing else we can do. 27965ffd940aSRaphael Isemann return false; 27975ffd940aSRaphael Isemann 27985ffd940aSRaphael Isemann CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen); 27995ffd940aSRaphael Isemann Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); 28005ffd940aSRaphael Isemann ++j; 28015ffd940aSRaphael Isemann } 28025ffd940aSRaphael Isemann 28035ffd940aSRaphael Isemann // Do not clear the first region as it's the one before the first 28045ffd940aSRaphael Isemann // CHECK-LABEL and it would clear variables defined on the command-line 28055ffd940aSRaphael Isemann // before they get used. 28065ffd940aSRaphael Isemann if (i != 0 && Req.EnableVarScope) 28075ffd940aSRaphael Isemann PatternContext->clearLocalVars(); 28085ffd940aSRaphael Isemann 28095ffd940aSRaphael Isemann for (; i != j; ++i) { 28105ffd940aSRaphael Isemann const FileCheckString &CheckStr = (*CheckStrings)[i]; 28115ffd940aSRaphael Isemann 28125ffd940aSRaphael Isemann // Check each string within the scanned region, including a second check 28135ffd940aSRaphael Isemann // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) 28145ffd940aSRaphael Isemann size_t MatchLen = 0; 28155ffd940aSRaphael Isemann size_t MatchPos = 28165ffd940aSRaphael Isemann CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags); 28175ffd940aSRaphael Isemann 28185ffd940aSRaphael Isemann if (MatchPos == StringRef::npos) { 28195ffd940aSRaphael Isemann ChecksFailed = true; 28205ffd940aSRaphael Isemann i = j; 28215ffd940aSRaphael Isemann break; 28225ffd940aSRaphael Isemann } 28235ffd940aSRaphael Isemann 28245ffd940aSRaphael Isemann CheckRegion = CheckRegion.substr(MatchPos + MatchLen); 28255ffd940aSRaphael Isemann } 28265ffd940aSRaphael Isemann 28275ffd940aSRaphael Isemann if (j == e) 28285ffd940aSRaphael Isemann break; 28295ffd940aSRaphael Isemann } 28305ffd940aSRaphael Isemann 28315ffd940aSRaphael Isemann // Success if no checks failed. 28325ffd940aSRaphael Isemann return !ChecksFailed; 28335ffd940aSRaphael Isemann } 2834