xref: /llvm-project/llvm/unittests/FileCheck/FileCheckTest.cpp (revision 5c9d82de6b72cc0c037daecce452c450870f0034)
15ffd940aSRaphael Isemann //===- llvm/unittest/FileCheck/FileCheckTest.cpp - FileCheck tests --------===//
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 #include "llvm/FileCheck/FileCheck.h"
105ffd940aSRaphael Isemann #include "../lib/FileCheck/FileCheckImpl.h"
115ffd940aSRaphael Isemann #include "llvm/Support/Regex.h"
125ffd940aSRaphael Isemann #include "llvm/Testing/Support/Error.h"
135ffd940aSRaphael Isemann #include "gtest/gtest.h"
145ffd940aSRaphael Isemann #include <tuple>
155ffd940aSRaphael Isemann #include <unordered_set>
165ffd940aSRaphael Isemann 
175ffd940aSRaphael Isemann using namespace llvm;
185ffd940aSRaphael Isemann 
195ffd940aSRaphael Isemann namespace {
205ffd940aSRaphael Isemann 
215ffd940aSRaphael Isemann class FileCheckTest : public ::testing::Test {};
225ffd940aSRaphael Isemann 
bufferize(SourceMgr & SM,StringRef Str)235ffd940aSRaphael Isemann static StringRef bufferize(SourceMgr &SM, StringRef Str) {
245ffd940aSRaphael Isemann   std::unique_ptr<MemoryBuffer> Buffer =
255ffd940aSRaphael Isemann       MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
265ffd940aSRaphael Isemann   StringRef StrBufferRef = Buffer->getBuffer();
275ffd940aSRaphael Isemann   SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
285ffd940aSRaphael Isemann   return StrBufferRef;
295ffd940aSRaphael Isemann }
305ffd940aSRaphael Isemann 
toString(const std::unordered_set<std::string> & Set)315ffd940aSRaphael Isemann static std::string toString(const std::unordered_set<std::string> &Set) {
325ffd940aSRaphael Isemann   bool First = true;
335ffd940aSRaphael Isemann   std::string Str;
345ffd940aSRaphael Isemann   for (StringRef S : Set) {
355ffd940aSRaphael Isemann     Str += Twine(First ? "{" + S : ", " + S).str();
365ffd940aSRaphael Isemann     First = false;
375ffd940aSRaphael Isemann   }
385ffd940aSRaphael Isemann   Str += '}';
395ffd940aSRaphael Isemann   return Str;
405ffd940aSRaphael Isemann }
415ffd940aSRaphael Isemann 
425ffd940aSRaphael Isemann template <typename ErrorT>
expectSameErrors(std::unordered_set<std::string> ExpectedMsgs,Error Err)435ffd940aSRaphael Isemann static void expectSameErrors(std::unordered_set<std::string> ExpectedMsgs,
445ffd940aSRaphael Isemann                              Error Err) {
455ffd940aSRaphael Isemann   auto AnyErrorMsgMatch = [&ExpectedMsgs](std::string &&ErrorMsg) -> bool {
465ffd940aSRaphael Isemann     for (auto ExpectedMsgItr = ExpectedMsgs.begin(),
475ffd940aSRaphael Isemann               ExpectedMsgEnd = ExpectedMsgs.end();
485ffd940aSRaphael Isemann          ExpectedMsgItr != ExpectedMsgEnd; ++ExpectedMsgItr) {
495ffd940aSRaphael Isemann       if (ErrorMsg.find(*ExpectedMsgItr) != std::string::npos) {
505ffd940aSRaphael Isemann         ExpectedMsgs.erase(ExpectedMsgItr);
515ffd940aSRaphael Isemann         return true;
525ffd940aSRaphael Isemann       }
535ffd940aSRaphael Isemann     }
545ffd940aSRaphael Isemann     return false;
555ffd940aSRaphael Isemann   };
565ffd940aSRaphael Isemann 
575ffd940aSRaphael Isemann   Error RemainingErrors = std::move(Err);
585ffd940aSRaphael Isemann   do {
595ffd940aSRaphael Isemann     RemainingErrors =
605ffd940aSRaphael Isemann         handleErrors(std::move(RemainingErrors), [&](const ErrorT &E) {
615ffd940aSRaphael Isemann           EXPECT_TRUE(AnyErrorMsgMatch(E.message()))
625ffd940aSRaphael Isemann               << "Unexpected error message:" << std::endl
635ffd940aSRaphael Isemann               << E.message();
645ffd940aSRaphael Isemann         });
655ffd940aSRaphael Isemann   } while (RemainingErrors && !ExpectedMsgs.empty());
665ffd940aSRaphael Isemann   EXPECT_THAT_ERROR(std::move(RemainingErrors), Succeeded());
675ffd940aSRaphael Isemann   EXPECT_TRUE(ExpectedMsgs.empty())
685ffd940aSRaphael Isemann       << "Error message(s) not found:" << std::endl
695ffd940aSRaphael Isemann       << toString(ExpectedMsgs);
705ffd940aSRaphael Isemann }
715ffd940aSRaphael Isemann 
725ffd940aSRaphael Isemann template <typename ErrorT>
expectError(StringRef ExpectedMsg,Error Err)735ffd940aSRaphael Isemann static void expectError(StringRef ExpectedMsg, Error Err) {
745ffd940aSRaphael Isemann   expectSameErrors<ErrorT>({ExpectedMsg.str()}, std::move(Err));
755ffd940aSRaphael Isemann }
765ffd940aSRaphael Isemann 
expectDiagnosticError(StringRef ExpectedMsg,Error Err)775ffd940aSRaphael Isemann static void expectDiagnosticError(StringRef ExpectedMsg, Error Err) {
785ffd940aSRaphael Isemann   expectError<ErrorDiagnostic>(ExpectedMsg, std::move(Err));
795ffd940aSRaphael Isemann }
805ffd940aSRaphael Isemann 
815ffd940aSRaphael Isemann constexpr uint64_t MaxUint64 = std::numeric_limits<uint64_t>::max();
825ffd940aSRaphael Isemann constexpr int64_t MaxInt64 = std::numeric_limits<int64_t>::max();
835ffd940aSRaphael Isemann constexpr int64_t MinInt64 = std::numeric_limits<int64_t>::min();
845ffd940aSRaphael Isemann constexpr uint64_t AbsoluteMinInt64 =
855ffd940aSRaphael Isemann     static_cast<uint64_t>(-(MinInt64 + 1)) + 1;
865ffd940aSRaphael Isemann constexpr uint64_t AbsoluteMaxInt64 = static_cast<uint64_t>(MaxInt64);
870726cb00SThomas Preud'homme // Use 128 bitwidth for literals to keep one bit for sign for uint64_t
880726cb00SThomas Preud'homme // literals.
890726cb00SThomas Preud'homme constexpr unsigned LiteralsBitWidth = 128;
905ffd940aSRaphael Isemann 
915ffd940aSRaphael Isemann struct ExpressionFormatParameterisedFixture
925ffd940aSRaphael Isemann     : public ::testing::TestWithParam<
93f9e2a62cSThomas Preud'homme           std::tuple<ExpressionFormat::Kind, unsigned, bool>> {
94f9e2a62cSThomas Preud'homme   bool AlternateForm;
955ffd940aSRaphael Isemann   unsigned Precision;
965ffd940aSRaphael Isemann   bool Signed;
975ffd940aSRaphael Isemann   bool AllowHex;
985ffd940aSRaphael Isemann   bool AllowUpperHex;
995ffd940aSRaphael Isemann   ExpressionFormat Format;
1005ffd940aSRaphael Isemann   Regex WildcardRegex;
1015ffd940aSRaphael Isemann 
1025ffd940aSRaphael Isemann   StringRef TenStr;
1035ffd940aSRaphael Isemann   StringRef FifteenStr;
1045ffd940aSRaphael Isemann   std::string MaxUint64Str;
1055ffd940aSRaphael Isemann   std::string MaxInt64Str;
1065ffd940aSRaphael Isemann   std::string MinInt64Str;
1075ffd940aSRaphael Isemann   StringRef FirstInvalidCharDigits;
1085ffd940aSRaphael Isemann   StringRef AcceptedHexOnlyDigits;
1095ffd940aSRaphael Isemann   StringRef RefusedHexOnlyDigits;
1105ffd940aSRaphael Isemann 
1115ffd940aSRaphael Isemann   SourceMgr SM;
1125ffd940aSRaphael Isemann 
SetUp__anon6dfffe6a0111::ExpressionFormatParameterisedFixture1135ffd940aSRaphael Isemann   void SetUp() override {
1145ffd940aSRaphael Isemann     ExpressionFormat::Kind Kind;
115f9e2a62cSThomas Preud'homme     std::tie(Kind, Precision, AlternateForm) = GetParam();
1165ffd940aSRaphael Isemann     AllowHex = Kind == ExpressionFormat::Kind::HexLower ||
1175ffd940aSRaphael Isemann                Kind == ExpressionFormat::Kind::HexUpper;
1185ffd940aSRaphael Isemann     AllowUpperHex = Kind == ExpressionFormat::Kind::HexUpper;
1195ffd940aSRaphael Isemann     Signed = Kind == ExpressionFormat::Kind::Signed;
120f9e2a62cSThomas Preud'homme     Format = ExpressionFormat(Kind, Precision, AlternateForm);
1215ffd940aSRaphael Isemann 
1225ffd940aSRaphael Isemann     if (!AllowHex) {
1235ffd940aSRaphael Isemann       MaxUint64Str = std::to_string(MaxUint64);
1245ffd940aSRaphael Isemann       MaxInt64Str = std::to_string(MaxInt64);
1255ffd940aSRaphael Isemann       MinInt64Str = std::to_string(MinInt64);
1265ffd940aSRaphael Isemann       TenStr = "10";
1275ffd940aSRaphael Isemann       FifteenStr = "15";
1285ffd940aSRaphael Isemann       FirstInvalidCharDigits = "aA";
1295ffd940aSRaphael Isemann       AcceptedHexOnlyDigits = RefusedHexOnlyDigits = "N/A";
1305ffd940aSRaphael Isemann       return;
1315ffd940aSRaphael Isemann     }
1325ffd940aSRaphael Isemann 
1335ffd940aSRaphael Isemann     MaxUint64Str = AllowUpperHex ? "FFFFFFFFFFFFFFFF" : "ffffffffffffffff";
1345ffd940aSRaphael Isemann     MaxInt64Str = AllowUpperHex ? "7FFFFFFFFFFFFFFF" : "7fffffffffffffff";
1355ffd940aSRaphael Isemann     TenStr = AllowUpperHex ? "A" : "a";
1365ffd940aSRaphael Isemann     FifteenStr = AllowUpperHex ? "F" : "f";
1375ffd940aSRaphael Isemann     AcceptedHexOnlyDigits = AllowUpperHex ? "ABCDEF" : "abcdef";
1385ffd940aSRaphael Isemann     RefusedHexOnlyDigits = AllowUpperHex ? "abcdef" : "ABCDEF";
1395ffd940aSRaphael Isemann     MinInt64Str = "N/A";
1405ffd940aSRaphael Isemann     FirstInvalidCharDigits = "gG";
1415ffd940aSRaphael Isemann   }
1425ffd940aSRaphael Isemann 
checkWildcardRegexMatch__anon6dfffe6a0111::ExpressionFormatParameterisedFixture1435ffd940aSRaphael Isemann   void checkWildcardRegexMatch(StringRef Input,
1445ffd940aSRaphael Isemann                                unsigned TrailExtendTo = 0) const {
145f9e2a62cSThomas Preud'homme     ASSERT_TRUE(TrailExtendTo == 0 || AllowHex);
1465ffd940aSRaphael Isemann     SmallVector<StringRef, 4> Matches;
1475ffd940aSRaphael Isemann     std::string ExtendedInput = Input.str();
148f9e2a62cSThomas Preud'homme     size_t PrefixSize = AlternateForm ? 2 : 0;
149f9e2a62cSThomas Preud'homme     if (TrailExtendTo > Input.size() - PrefixSize) {
150f9e2a62cSThomas Preud'homme       size_t ExtensionSize = PrefixSize + TrailExtendTo - Input.size();
151f9e2a62cSThomas Preud'homme       ExtendedInput.append(ExtensionSize, Input[PrefixSize]);
1525ffd940aSRaphael Isemann     }
1535ffd940aSRaphael Isemann     ASSERT_TRUE(WildcardRegex.match(ExtendedInput, &Matches))
1545ffd940aSRaphael Isemann         << "Wildcard regex does not match " << ExtendedInput;
1555ffd940aSRaphael Isemann     EXPECT_EQ(Matches[0], ExtendedInput);
1565ffd940aSRaphael Isemann   }
1575ffd940aSRaphael Isemann 
checkWildcardRegexMatchFailure__anon6dfffe6a0111::ExpressionFormatParameterisedFixture1585ffd940aSRaphael Isemann   void checkWildcardRegexMatchFailure(StringRef Input) const {
1595ffd940aSRaphael Isemann     EXPECT_FALSE(WildcardRegex.match(Input));
1605ffd940aSRaphael Isemann   }
1615ffd940aSRaphael Isemann 
addBasePrefix__anon6dfffe6a0111::ExpressionFormatParameterisedFixture162f9e2a62cSThomas Preud'homme   std::string addBasePrefix(StringRef Num) const {
163f9e2a62cSThomas Preud'homme     StringRef Prefix = AlternateForm ? "0x" : "";
164f9e2a62cSThomas Preud'homme     return (Twine(Prefix) + Twine(Num)).str();
165f9e2a62cSThomas Preud'homme   }
166f9e2a62cSThomas Preud'homme 
checkPerCharWildcardRegexMatchFailure__anon6dfffe6a0111::ExpressionFormatParameterisedFixture1675ca168b0SThomas Preud'homme   void checkPerCharWildcardRegexMatchFailure(StringRef Chars) const {
168f9e2a62cSThomas Preud'homme     for (auto C : Chars) {
169f9e2a62cSThomas Preud'homme       std::string Str = addBasePrefix(StringRef(&C, 1));
170f9e2a62cSThomas Preud'homme       EXPECT_FALSE(WildcardRegex.match(Str));
171f9e2a62cSThomas Preud'homme     }
1725ffd940aSRaphael Isemann   }
1735ffd940aSRaphael Isemann 
padWithLeadingZeros__anon6dfffe6a0111::ExpressionFormatParameterisedFixture1745ffd940aSRaphael Isemann   std::string padWithLeadingZeros(StringRef NumStr) const {
175*5c9d82deSKazu Hirata     bool Negative = NumStr.starts_with("-");
1765ffd940aSRaphael Isemann     if (NumStr.size() - unsigned(Negative) >= Precision)
1775ffd940aSRaphael Isemann       return NumStr.str();
1785ffd940aSRaphael Isemann 
1795ffd940aSRaphael Isemann     std::string PaddedStr;
1805ffd940aSRaphael Isemann     if (Negative) {
1815ffd940aSRaphael Isemann       PaddedStr = "-";
1825ffd940aSRaphael Isemann       NumStr = NumStr.drop_front();
1835ffd940aSRaphael Isemann     }
1845ffd940aSRaphael Isemann     PaddedStr.append(Precision - NumStr.size(), '0');
1855ffd940aSRaphael Isemann     PaddedStr.append(NumStr.str());
1865ffd940aSRaphael Isemann     return PaddedStr;
1875ffd940aSRaphael Isemann   }
1885ffd940aSRaphael Isemann 
checkMatchingString__anon6dfffe6a0111::ExpressionFormatParameterisedFixture1895ffd940aSRaphael Isemann   template <class T> void checkMatchingString(T Val, StringRef ExpectedStr) {
1900726cb00SThomas Preud'homme     APInt Value(LiteralsBitWidth, Val, std::is_signed_v<T>);
191e15e969aSThomas Preud'homme     Expected<std::string> MatchingString = Format.getMatchingString(Value);
1925ffd940aSRaphael Isemann     ASSERT_THAT_EXPECTED(MatchingString, Succeeded())
1935ffd940aSRaphael Isemann         << "No matching string for " << Val;
1945ffd940aSRaphael Isemann     EXPECT_EQ(*MatchingString, ExpectedStr);
1955ffd940aSRaphael Isemann   }
1965ffd940aSRaphael Isemann 
checkMatchingStringFailure__anon6dfffe6a0111::ExpressionFormatParameterisedFixture1975ffd940aSRaphael Isemann   template <class T> void checkMatchingStringFailure(T Val) {
1980726cb00SThomas Preud'homme     APInt Value(LiteralsBitWidth, Val, std::is_signed_v<T>);
199e15e969aSThomas Preud'homme     Expected<std::string> MatchingString = Format.getMatchingString(Value);
200e15e969aSThomas Preud'homme     // Error message tested in ExpressionFormat unit tests.
2015ffd940aSRaphael Isemann     EXPECT_THAT_EXPECTED(MatchingString, Failed());
2025ffd940aSRaphael Isemann   }
2035ffd940aSRaphael Isemann 
2045ffd940aSRaphael Isemann   template <class T>
checkValueFromStringRepr__anon6dfffe6a0111::ExpressionFormatParameterisedFixture2055ffd940aSRaphael Isemann   void checkValueFromStringRepr(StringRef Str, T ExpectedVal) {
206b743c193SThomas Preud'homme     StringRef BufferizedStr = bufferize(SM, Str);
207b743c193SThomas Preud'homme     APInt ResultValue = Format.valueFromStringRepr(BufferizedStr, SM);
208b743c193SThomas Preud'homme     ASSERT_EQ(ResultValue.isNegative(), ExpectedVal < 0)
2095ffd940aSRaphael Isemann         << "Value for " << Str << " is not " << ExpectedVal;
210b743c193SThomas Preud'homme     if (ResultValue.isNegative())
211b743c193SThomas Preud'homme       EXPECT_EQ(ResultValue.getSExtValue(), static_cast<int64_t>(ExpectedVal));
2125ffd940aSRaphael Isemann     else
213b743c193SThomas Preud'homme       EXPECT_EQ(ResultValue.getZExtValue(), static_cast<uint64_t>(ExpectedVal));
2145ffd940aSRaphael Isemann   }
2155ffd940aSRaphael Isemann };
2165ffd940aSRaphael Isemann 
TEST_P(ExpressionFormatParameterisedFixture,FormatGetWildcardRegex)2175ffd940aSRaphael Isemann TEST_P(ExpressionFormatParameterisedFixture, FormatGetWildcardRegex) {
2185ffd940aSRaphael Isemann   // Wildcard regex is valid.
2195ffd940aSRaphael Isemann   Expected<std::string> WildcardPattern = Format.getWildcardRegex();
2205ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(WildcardPattern, Succeeded());
2215ffd940aSRaphael Isemann   WildcardRegex = Regex((Twine("^") + *WildcardPattern + "$").str());
2225ffd940aSRaphael Isemann   ASSERT_TRUE(WildcardRegex.isValid());
2235ffd940aSRaphael Isemann 
2245ffd940aSRaphael Isemann   // Does not match empty string.
2255ffd940aSRaphael Isemann   checkWildcardRegexMatchFailure("");
2265ffd940aSRaphael Isemann 
227f9e2a62cSThomas Preud'homme   // Matches all decimal digits, matches several of them and match 0x prefix
228f9e2a62cSThomas Preud'homme   // if and only if AlternateForm is true.
2295ffd940aSRaphael Isemann   StringRef LongNumber = "12345678901234567890";
230f9e2a62cSThomas Preud'homme   StringRef PrefixedLongNumber = "0x12345678901234567890";
231f9e2a62cSThomas Preud'homme   if (AlternateForm) {
232f9e2a62cSThomas Preud'homme     checkWildcardRegexMatch(PrefixedLongNumber);
233f9e2a62cSThomas Preud'homme     checkWildcardRegexMatchFailure(LongNumber);
234f9e2a62cSThomas Preud'homme   } else {
2355ffd940aSRaphael Isemann     checkWildcardRegexMatch(LongNumber);
236f9e2a62cSThomas Preud'homme     checkWildcardRegexMatchFailure(PrefixedLongNumber);
237f9e2a62cSThomas Preud'homme   }
2385ffd940aSRaphael Isemann 
2395ffd940aSRaphael Isemann   // Matches negative digits.
2405ffd940aSRaphael Isemann   LongNumber = "-12345678901234567890";
2415ffd940aSRaphael Isemann   if (Signed)
2425ffd940aSRaphael Isemann     checkWildcardRegexMatch(LongNumber);
2435ffd940aSRaphael Isemann   else
2445ffd940aSRaphael Isemann     checkWildcardRegexMatchFailure(LongNumber);
2455ffd940aSRaphael Isemann 
2465ffd940aSRaphael Isemann   // Check non digits or digits with wrong casing are not matched.
247f9e2a62cSThomas Preud'homme   std::string LongNumberStr;
2485ffd940aSRaphael Isemann   if (AllowHex) {
249f9e2a62cSThomas Preud'homme     LongNumberStr = addBasePrefix(AcceptedHexOnlyDigits);
250f9e2a62cSThomas Preud'homme     checkWildcardRegexMatch(LongNumberStr, 16);
2515ca168b0SThomas Preud'homme     checkPerCharWildcardRegexMatchFailure(RefusedHexOnlyDigits);
2525ffd940aSRaphael Isemann   }
2535ca168b0SThomas Preud'homme   checkPerCharWildcardRegexMatchFailure(FirstInvalidCharDigits);
2545ffd940aSRaphael Isemann 
2555ffd940aSRaphael Isemann   // Check leading zeros are only accepted if number of digits is less than the
2565ffd940aSRaphael Isemann   // precision.
2575ffd940aSRaphael Isemann   LongNumber = "01234567890123456789";
2585ffd940aSRaphael Isemann   if (Precision) {
259f9e2a62cSThomas Preud'homme     LongNumberStr = addBasePrefix(LongNumber.take_front(Precision));
260f9e2a62cSThomas Preud'homme     checkWildcardRegexMatch(LongNumberStr);
261f9e2a62cSThomas Preud'homme     LongNumberStr = addBasePrefix(LongNumber.take_front(Precision - 1));
262f9e2a62cSThomas Preud'homme     checkWildcardRegexMatchFailure(LongNumberStr);
263f9e2a62cSThomas Preud'homme     if (Precision < LongNumber.size()) {
264f9e2a62cSThomas Preud'homme       LongNumberStr = addBasePrefix(LongNumber.take_front(Precision + 1));
265f9e2a62cSThomas Preud'homme       checkWildcardRegexMatchFailure(LongNumberStr);
266f9e2a62cSThomas Preud'homme     }
267f9e2a62cSThomas Preud'homme   } else {
268f9e2a62cSThomas Preud'homme     LongNumberStr = addBasePrefix(LongNumber);
269f9e2a62cSThomas Preud'homme     checkWildcardRegexMatch(LongNumberStr);
270f9e2a62cSThomas Preud'homme   }
2715ffd940aSRaphael Isemann }
2725ffd940aSRaphael Isemann 
TEST_P(ExpressionFormatParameterisedFixture,FormatGetMatchingString)2735ffd940aSRaphael Isemann TEST_P(ExpressionFormatParameterisedFixture, FormatGetMatchingString) {
274f9e2a62cSThomas Preud'homme   checkMatchingString(0, addBasePrefix(padWithLeadingZeros("0")));
275f9e2a62cSThomas Preud'homme   checkMatchingString(9, addBasePrefix(padWithLeadingZeros("9")));
2765ffd940aSRaphael Isemann 
2775ffd940aSRaphael Isemann   if (Signed) {
2785ffd940aSRaphael Isemann     checkMatchingString(-5, padWithLeadingZeros("-5"));
2790726cb00SThomas Preud'homme     checkMatchingString(MaxUint64, padWithLeadingZeros(MaxUint64Str));
2805ffd940aSRaphael Isemann     checkMatchingString(MaxInt64, padWithLeadingZeros(MaxInt64Str));
2815ffd940aSRaphael Isemann     checkMatchingString(MinInt64, padWithLeadingZeros(MinInt64Str));
2825ffd940aSRaphael Isemann   } else {
2835ffd940aSRaphael Isemann     checkMatchingStringFailure(-5);
284f9e2a62cSThomas Preud'homme     checkMatchingString(MaxUint64,
285f9e2a62cSThomas Preud'homme                         addBasePrefix(padWithLeadingZeros(MaxUint64Str)));
286f9e2a62cSThomas Preud'homme     checkMatchingString(MaxInt64,
287f9e2a62cSThomas Preud'homme                         addBasePrefix(padWithLeadingZeros(MaxInt64Str)));
2885ffd940aSRaphael Isemann     checkMatchingStringFailure(MinInt64);
2895ffd940aSRaphael Isemann   }
2905ffd940aSRaphael Isemann 
291f9e2a62cSThomas Preud'homme   checkMatchingString(10, addBasePrefix(padWithLeadingZeros(TenStr)));
292f9e2a62cSThomas Preud'homme   checkMatchingString(15, addBasePrefix(padWithLeadingZeros(FifteenStr)));
2935ffd940aSRaphael Isemann }
2945ffd940aSRaphael Isemann 
TEST_P(ExpressionFormatParameterisedFixture,FormatValueFromStringRepr)2955ffd940aSRaphael Isemann TEST_P(ExpressionFormatParameterisedFixture, FormatValueFromStringRepr) {
296f9e2a62cSThomas Preud'homme   checkValueFromStringRepr(addBasePrefix("0"), 0);
297f9e2a62cSThomas Preud'homme   checkValueFromStringRepr(addBasePrefix("9"), 9);
2985ffd940aSRaphael Isemann 
2995ffd940aSRaphael Isemann   if (Signed) {
3005ffd940aSRaphael Isemann     checkValueFromStringRepr("-5", -5);
3010726cb00SThomas Preud'homme     checkValueFromStringRepr(MaxUint64Str, MaxUint64);
3025ffd940aSRaphael Isemann   } else {
303f9e2a62cSThomas Preud'homme     checkValueFromStringRepr(addBasePrefix(MaxUint64Str), MaxUint64);
3045ffd940aSRaphael Isemann   }
3055ffd940aSRaphael Isemann 
306f9e2a62cSThomas Preud'homme   checkValueFromStringRepr(addBasePrefix(TenStr), 10);
307f9e2a62cSThomas Preud'homme   checkValueFromStringRepr(addBasePrefix(FifteenStr), 15);
3085ffd940aSRaphael Isemann 
3095ffd940aSRaphael Isemann   // Wrong casing is not tested because valueFromStringRepr() relies on
3105ffd940aSRaphael Isemann   // StringRef's getAsInteger() which does not allow to restrict casing.
311b743c193SThomas Preud'homme 
312b743c193SThomas Preud'homme   // Likewise, wrong letter digit for hex value is not tested because it is
313b743c193SThomas Preud'homme   // only caught by an assert in FileCheck due to getWildcardRegex()
314b743c193SThomas Preud'homme   // guaranteeing only valid letter digits are used.
3155ffd940aSRaphael Isemann }
3165ffd940aSRaphael Isemann 
TEST_P(ExpressionFormatParameterisedFixture,FormatBoolOperator)3175ffd940aSRaphael Isemann TEST_P(ExpressionFormatParameterisedFixture, FormatBoolOperator) {
3185ffd940aSRaphael Isemann   EXPECT_TRUE(bool(Format));
3195ffd940aSRaphael Isemann }
3205ffd940aSRaphael Isemann 
321d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(
3225ffd940aSRaphael Isemann     AllowedExplicitExpressionFormat, ExpressionFormatParameterisedFixture,
323f9e2a62cSThomas Preud'homme     ::testing::Values(
324f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::Unsigned, 0, false),
325f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::Signed, 0, false),
326f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexLower, 0, false),
327f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexLower, 0, true),
328f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexUpper, 0, false),
329f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexUpper, 0, true),
3305ffd940aSRaphael Isemann 
331f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::Unsigned, 1, false),
332f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::Signed, 1, false),
333f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexLower, 1, false),
334f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexLower, 1, true),
335f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexUpper, 1, false),
336f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexUpper, 1, true),
3375ffd940aSRaphael Isemann 
338f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::Unsigned, 16, false),
339f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::Signed, 16, false),
340f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexLower, 16, false),
341f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexLower, 16, true),
342f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexUpper, 16, false),
343f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::HexUpper, 16, true),
3445ffd940aSRaphael Isemann 
345f9e2a62cSThomas Preud'homme         std::make_tuple(ExpressionFormat::Kind::Unsigned, 20, false),
346d4d80a29SBenjamin Kramer         std::make_tuple(ExpressionFormat::Kind::Signed, 20, false)));
3475ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,NoFormatProperties)3485ffd940aSRaphael Isemann TEST_F(FileCheckTest, NoFormatProperties) {
3495ffd940aSRaphael Isemann   ExpressionFormat NoFormat(ExpressionFormat::Kind::NoFormat);
3505ffd940aSRaphael Isemann   expectError<StringError>("trying to match value with invalid format",
3515ffd940aSRaphael Isemann                            NoFormat.getWildcardRegex().takeError());
3525ffd940aSRaphael Isemann   expectError<StringError>(
3535ffd940aSRaphael Isemann       "trying to match value with invalid format",
354e15e969aSThomas Preud'homme       NoFormat.getMatchingString(APInt(64, 18u)).takeError());
3555ffd940aSRaphael Isemann   EXPECT_FALSE(bool(NoFormat));
3565ffd940aSRaphael Isemann }
3575ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,FormatEqualityOperators)3585ffd940aSRaphael Isemann TEST_F(FileCheckTest, FormatEqualityOperators) {
3595ffd940aSRaphael Isemann   ExpressionFormat UnsignedFormat(ExpressionFormat::Kind::Unsigned);
3605ffd940aSRaphael Isemann   ExpressionFormat UnsignedFormat2(ExpressionFormat::Kind::Unsigned);
3615ffd940aSRaphael Isemann   EXPECT_TRUE(UnsignedFormat == UnsignedFormat2);
3625ffd940aSRaphael Isemann   EXPECT_FALSE(UnsignedFormat != UnsignedFormat2);
3635ffd940aSRaphael Isemann 
3645ffd940aSRaphael Isemann   ExpressionFormat HexLowerFormat(ExpressionFormat::Kind::HexLower);
3655ffd940aSRaphael Isemann   EXPECT_FALSE(UnsignedFormat == HexLowerFormat);
3665ffd940aSRaphael Isemann   EXPECT_TRUE(UnsignedFormat != HexLowerFormat);
3675ffd940aSRaphael Isemann 
3685ffd940aSRaphael Isemann   ExpressionFormat NoFormat(ExpressionFormat::Kind::NoFormat);
3695ffd940aSRaphael Isemann   ExpressionFormat NoFormat2(ExpressionFormat::Kind::NoFormat);
3705ffd940aSRaphael Isemann   EXPECT_FALSE(NoFormat == NoFormat2);
3715ffd940aSRaphael Isemann   EXPECT_TRUE(NoFormat != NoFormat2);
3725ffd940aSRaphael Isemann }
3735ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,FormatKindEqualityOperators)3745ffd940aSRaphael Isemann TEST_F(FileCheckTest, FormatKindEqualityOperators) {
3755ffd940aSRaphael Isemann   ExpressionFormat UnsignedFormat(ExpressionFormat::Kind::Unsigned);
3765ffd940aSRaphael Isemann   EXPECT_TRUE(UnsignedFormat == ExpressionFormat::Kind::Unsigned);
3775ffd940aSRaphael Isemann   EXPECT_FALSE(UnsignedFormat != ExpressionFormat::Kind::Unsigned);
3785ffd940aSRaphael Isemann   EXPECT_FALSE(UnsignedFormat == ExpressionFormat::Kind::HexLower);
3795ffd940aSRaphael Isemann   EXPECT_TRUE(UnsignedFormat != ExpressionFormat::Kind::HexLower);
3805ffd940aSRaphael Isemann   ExpressionFormat NoFormat(ExpressionFormat::Kind::NoFormat);
3815ffd940aSRaphael Isemann   EXPECT_TRUE(NoFormat == ExpressionFormat::Kind::NoFormat);
3825ffd940aSRaphael Isemann   EXPECT_FALSE(NoFormat != ExpressionFormat::Kind::NoFormat);
3835ffd940aSRaphael Isemann }
3845ffd940aSRaphael Isemann 
expectOperationValueResult(binop_eval_t Operation,APInt LeftValue,APInt RightValue,APInt ExpectedValue)3850726cb00SThomas Preud'homme static void expectOperationValueResult(binop_eval_t Operation, APInt LeftValue,
3860726cb00SThomas Preud'homme                                        APInt RightValue, APInt ExpectedValue) {
3870726cb00SThomas Preud'homme   bool Overflow;
388e15e969aSThomas Preud'homme   Expected<APInt> OperationResult = Operation(LeftValue, RightValue, Overflow);
3890726cb00SThomas Preud'homme   ASSERT_THAT_EXPECTED(OperationResult, Succeeded());
390e15e969aSThomas Preud'homme   EXPECT_EQ(*OperationResult, ExpectedValue);
3915ffd940aSRaphael Isemann }
3925ffd940aSRaphael Isemann 
3935ffd940aSRaphael Isemann template <class T1, class T2, class TR>
expectOperationValueResult(binop_eval_t Operation,T1 LeftValue,T2 RightValue,TR ResultValue)3945ffd940aSRaphael Isemann static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue,
3955ffd940aSRaphael Isemann                                        T2 RightValue, TR ResultValue) {
3960726cb00SThomas Preud'homme   APInt LeftVal(LiteralsBitWidth, LeftValue, std::is_signed_v<T1>);
3970726cb00SThomas Preud'homme   APInt RightVal(LiteralsBitWidth, RightValue, std::is_signed_v<T2>);
3985bd8f481SSimon Pilgrim   APInt ResultVal;
3995bd8f481SSimon Pilgrim   if constexpr (std::is_integral_v<TR>)
4005bd8f481SSimon Pilgrim     ResultVal = APInt(LiteralsBitWidth, ResultValue, std::is_signed_v<TR>);
4015bd8f481SSimon Pilgrim   else
4025bd8f481SSimon Pilgrim     ResultVal = APInt(LiteralsBitWidth, ResultValue, /*Radix=*/10);
4030726cb00SThomas Preud'homme   expectOperationValueResult(Operation, LeftVal, RightVal, ResultVal);
4045ffd940aSRaphael Isemann }
4055ffd940aSRaphael Isemann 
4065ffd940aSRaphael Isemann template <class T1, class T2>
expectOperationValueResult(binop_eval_t Operation,T1 LeftValue,T2 RightValue)4075ffd940aSRaphael Isemann static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue,
4085ffd940aSRaphael Isemann                                        T2 RightValue) {
4090726cb00SThomas Preud'homme   bool Overflow;
410e15e969aSThomas Preud'homme   APInt LeftVal(LiteralsBitWidth, LeftValue, std::is_signed_v<T1>);
411e15e969aSThomas Preud'homme   APInt RightVal(LiteralsBitWidth, RightValue, std::is_signed_v<T2>);
4125ffd940aSRaphael Isemann   expectError<OverflowError>(
4130726cb00SThomas Preud'homme       "overflow error", Operation(LeftVal, RightVal, Overflow).takeError());
4145ffd940aSRaphael Isemann }
4155ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ExpressionValueAddition)4165ffd940aSRaphael Isemann TEST_F(FileCheckTest, ExpressionValueAddition) {
4175ffd940aSRaphael Isemann   // Test both negative values.
4180726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, -10, -10, -20);
4195ffd940aSRaphael Isemann 
4205ffd940aSRaphael Isemann   // Test both negative values with underflow.
4210726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, MinInt64, -1, "-9223372036854775809");
4220726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, MinInt64, MinInt64,
4230726cb00SThomas Preud'homme                              "-18446744073709551616");
4245ffd940aSRaphael Isemann 
4255ffd940aSRaphael Isemann   // Test negative and positive value.
4260726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, -10, 10, 0);
4270726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, -10, 11, 1);
4280726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, -11, 10, -1);
4295ffd940aSRaphael Isemann 
4305ffd940aSRaphael Isemann   // Test positive and negative value.
4310726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, 10, -10, 0);
4320726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, 10, -11, -1);
4330726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, 11, -10, 1);
4345ffd940aSRaphael Isemann 
4355ffd940aSRaphael Isemann   // Test both positive values.
4360726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, 10, 10, 20);
4375ffd940aSRaphael Isemann 
4380726cb00SThomas Preud'homme   // Test both positive values with result not representable as uint64_t.
4390726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, MaxUint64, 1, "18446744073709551616");
4400726cb00SThomas Preud'homme   expectOperationValueResult(exprAdd, MaxUint64, MaxUint64,
4410726cb00SThomas Preud'homme                              "36893488147419103230");
4425ffd940aSRaphael Isemann }
4435ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ExpressionValueSubtraction)4445ffd940aSRaphael Isemann TEST_F(FileCheckTest, ExpressionValueSubtraction) {
4455ffd940aSRaphael Isemann   // Test negative value and value bigger than int64_t max.
4460726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, -10, MaxUint64, "-18446744073709551625");
4475ffd940aSRaphael Isemann 
4480726cb00SThomas Preud'homme   // Test negative and positive value with result not representable as int64_t.
4490726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, MinInt64, 1, "-9223372036854775809");
4505ffd940aSRaphael Isemann 
4515ffd940aSRaphael Isemann   // Test negative and positive value.
4520726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, -10, 10, -20);
4535ffd940aSRaphael Isemann 
4545ffd940aSRaphael Isemann   // Test both negative values.
4550726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, -10, -10, 0);
4560726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, -11, -10, -1);
4570726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, -10, -11, 1);
4585ffd940aSRaphael Isemann 
4595ffd940aSRaphael Isemann   // Test positive and negative values.
4600726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, 10, -10, 20);
4615ffd940aSRaphael Isemann 
4625ffd940aSRaphael Isemann   // Test both positive values with result positive.
4630726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, 10, 5, 5);
4645ffd940aSRaphael Isemann 
4650726cb00SThomas Preud'homme   // Test both positive values with result not representable as int64_t.
4660726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, 0, MaxUint64, "-18446744073709551615");
4670726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, 0,
4680726cb00SThomas Preud'homme                              static_cast<uint64_t>(-(MinInt64 + 10)) + 11,
4690726cb00SThomas Preud'homme                              "-9223372036854775809");
4705ffd940aSRaphael Isemann 
4715ffd940aSRaphael Isemann   // Test both positive values with result < -(max int64_t)
4720726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, 10, static_cast<uint64_t>(MaxInt64) + 11,
4735ffd940aSRaphael Isemann                              -MaxInt64 - 1);
4745ffd940aSRaphael Isemann 
4755ffd940aSRaphael Isemann   // Test both positive values with 0 > result > -(max int64_t)
4760726cb00SThomas Preud'homme   expectOperationValueResult(exprSub, 10, 11, -1);
4775ffd940aSRaphael Isemann }
4785ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ExpressionValueMultiplication)4795ffd940aSRaphael Isemann TEST_F(FileCheckTest, ExpressionValueMultiplication) {
4805ffd940aSRaphael Isemann   // Test mixed signed values.
4810726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -3, 10, -30);
4820726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 2, -17, -34);
4830726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 0, MinInt64, 0);
4840726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MinInt64, 1, MinInt64);
4850726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 1, MinInt64, MinInt64);
4860726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MaxInt64, -1, -MaxInt64);
4870726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -1, MaxInt64, -MaxInt64);
4885ffd940aSRaphael Isemann 
4895ffd940aSRaphael Isemann   // Test both negative values.
4900726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -3, -10, 30);
4910726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -2, -17, 34);
4920726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MinInt64, -1, AbsoluteMinInt64);
4935ffd940aSRaphael Isemann 
4945ffd940aSRaphael Isemann   // Test both positive values.
4950726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 3, 10, 30);
4960726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 2, 17, 34);
4970726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 0, MaxUint64, 0);
4985ffd940aSRaphael Isemann 
4990726cb00SThomas Preud'homme   // Test negative results not representable as int64_t.
5000726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -10, MaxInt64, "-92233720368547758070");
5010726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MaxInt64, -10, "-92233720368547758070");
5020726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 10, MinInt64, "-92233720368547758080");
5030726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MinInt64, 10, "-92233720368547758080");
5040726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -1, MaxUint64, "-18446744073709551615");
5050726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MaxUint64, -1, "-18446744073709551615");
5060726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -1, AbsoluteMaxInt64 + 2,
5070726cb00SThomas Preud'homme                              "-9223372036854775809");
5080726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, AbsoluteMaxInt64 + 2, -1,
5090726cb00SThomas Preud'homme                              "-9223372036854775809");
5105ffd940aSRaphael Isemann 
5110726cb00SThomas Preud'homme   // Test positive results not representable as uint64_t.
5120726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, 10, MaxUint64, "184467440737095516150");
5130726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MaxUint64, 10, "184467440737095516150");
5140726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, MinInt64, -10, "92233720368547758080");
5150726cb00SThomas Preud'homme   expectOperationValueResult(exprMul, -10, MinInt64, "92233720368547758080");
5165ffd940aSRaphael Isemann }
5175ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ExpressionValueDivision)5185ffd940aSRaphael Isemann TEST_F(FileCheckTest, ExpressionValueDivision) {
5195ffd940aSRaphael Isemann   // Test mixed signed values.
5200726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, -30, 10, -3);
5210726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, 34, -17, -2);
5220726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, 0, -10, 0);
5230726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, MinInt64, 1, MinInt64);
5240726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, MaxInt64, -1, -MaxInt64);
5250726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, -MaxInt64, 1, -MaxInt64);
5265ffd940aSRaphael Isemann 
5275ffd940aSRaphael Isemann   // Test both negative values.
5280726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, -30, -10, 3);
5290726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, -34, -17, 2);
5305ffd940aSRaphael Isemann 
5315ffd940aSRaphael Isemann   // Test both positive values.
5320726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, 30, 10, 3);
5330726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, 34, 17, 2);
5340726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, 0, 10, 0);
5355ffd940aSRaphael Isemann 
5365ffd940aSRaphael Isemann   // Test divide by zero.
5370726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, -10, 0);
5380726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, 10, 0);
5390726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, 0, 0);
5405ffd940aSRaphael Isemann 
5410726cb00SThomas Preud'homme   // Test negative result not representable as int64_t.
5420726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, MaxUint64, -1, "-18446744073709551615");
5430726cb00SThomas Preud'homme   expectOperationValueResult(exprDiv, AbsoluteMaxInt64 + 2, -1,
5440726cb00SThomas Preud'homme                              "-9223372036854775809");
5455ffd940aSRaphael Isemann }
5465ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,Literal)5475ffd940aSRaphael Isemann TEST_F(FileCheckTest, Literal) {
5485ffd940aSRaphael Isemann   SourceMgr SM;
5495ffd940aSRaphael Isemann 
5505ffd940aSRaphael Isemann   // Eval returns the literal's value.
5510726cb00SThomas Preud'homme   ExpressionLiteral Ten(bufferize(SM, "10"), APInt(64, 10u));
552e15e969aSThomas Preud'homme   Expected<APInt> Value = Ten.eval();
5535ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(Value, Succeeded());
554e15e969aSThomas Preud'homme   EXPECT_EQ(10, Value->getSExtValue());
5555ffd940aSRaphael Isemann   Expected<ExpressionFormat> ImplicitFormat = Ten.getImplicitFormat(SM);
5565ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
5575ffd940aSRaphael Isemann   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::NoFormat);
5585ffd940aSRaphael Isemann 
5595ffd940aSRaphael Isemann   // Min value can be correctly represented.
5600726cb00SThomas Preud'homme   ExpressionLiteral Min(bufferize(SM, std::to_string(MinInt64)),
5610726cb00SThomas Preud'homme                         APInt(64, MinInt64, /*IsSigned=*/true));
5625ffd940aSRaphael Isemann   Value = Min.eval();
5635ffd940aSRaphael Isemann   ASSERT_TRUE(bool(Value));
564e15e969aSThomas Preud'homme   EXPECT_EQ(MinInt64, Value->getSExtValue());
5655ffd940aSRaphael Isemann 
5665ffd940aSRaphael Isemann   // Max value can be correctly represented.
5670726cb00SThomas Preud'homme   ExpressionLiteral Max(bufferize(SM, std::to_string(MaxUint64)),
5680726cb00SThomas Preud'homme                         APInt(64, MaxUint64));
5695ffd940aSRaphael Isemann   Value = Max.eval();
5705ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(Value, Succeeded());
571e15e969aSThomas Preud'homme   EXPECT_EQ(MaxUint64, Value->getZExtValue());
5725ffd940aSRaphael Isemann }
5735ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,Expression)5745ffd940aSRaphael Isemann TEST_F(FileCheckTest, Expression) {
5755ffd940aSRaphael Isemann   SourceMgr SM;
5765ffd940aSRaphael Isemann 
5775ffd940aSRaphael Isemann   std::unique_ptr<ExpressionLiteral> Ten =
5780726cb00SThomas Preud'homme       std::make_unique<ExpressionLiteral>(bufferize(SM, "10"), APInt(64, 10u));
5795ffd940aSRaphael Isemann   ExpressionLiteral *TenPtr = Ten.get();
5805ffd940aSRaphael Isemann   Expression Expr(std::move(Ten),
5815ffd940aSRaphael Isemann                   ExpressionFormat(ExpressionFormat::Kind::HexLower));
5825ffd940aSRaphael Isemann   EXPECT_EQ(Expr.getAST(), TenPtr);
5835ffd940aSRaphael Isemann   EXPECT_EQ(Expr.getFormat(), ExpressionFormat::Kind::HexLower);
5845ffd940aSRaphael Isemann }
5855ffd940aSRaphael Isemann 
5865ffd940aSRaphael Isemann static void
expectUndefErrors(std::unordered_set<std::string> ExpectedUndefVarNames,Error Err)5875ffd940aSRaphael Isemann expectUndefErrors(std::unordered_set<std::string> ExpectedUndefVarNames,
5885ffd940aSRaphael Isemann                   Error Err) {
5895ffd940aSRaphael Isemann   EXPECT_THAT_ERROR(handleErrors(std::move(Err),
5905ffd940aSRaphael Isemann                                  [&](const UndefVarError &E) {
5915ffd940aSRaphael Isemann                                    EXPECT_EQ(ExpectedUndefVarNames.erase(
5925ffd940aSRaphael Isemann                                                  std::string(E.getVarName())),
5935ffd940aSRaphael Isemann                                              1U);
5945ffd940aSRaphael Isemann                                  }),
5955ffd940aSRaphael Isemann                     Succeeded());
5965ffd940aSRaphael Isemann   EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);
5975ffd940aSRaphael Isemann }
5985ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,NumericVariable)5995ffd940aSRaphael Isemann TEST_F(FileCheckTest, NumericVariable) {
6005ffd940aSRaphael Isemann   SourceMgr SM;
6015ffd940aSRaphael Isemann 
6025ffd940aSRaphael Isemann   // Undefined variable: getValue and eval fail, error returned by eval holds
6035ffd940aSRaphael Isemann   // the name of the undefined variable.
6045ffd940aSRaphael Isemann   NumericVariable FooVar("FOO",
6055ffd940aSRaphael Isemann                          ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1);
6065ffd940aSRaphael Isemann   EXPECT_EQ("FOO", FooVar.getName());
6075ffd940aSRaphael Isemann   EXPECT_EQ(FooVar.getImplicitFormat(), ExpressionFormat::Kind::Unsigned);
6085ffd940aSRaphael Isemann   NumericVariableUse FooVarUse("FOO", &FooVar);
6095ffd940aSRaphael Isemann   Expected<ExpressionFormat> ImplicitFormat = FooVarUse.getImplicitFormat(SM);
6105ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
6115ffd940aSRaphael Isemann   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
6125ffd940aSRaphael Isemann   EXPECT_FALSE(FooVar.getValue());
613e15e969aSThomas Preud'homme   Expected<APInt> EvalResult = FooVarUse.eval();
6145ffd940aSRaphael Isemann   expectUndefErrors({"FOO"}, EvalResult.takeError());
6155ffd940aSRaphael Isemann 
6165ffd940aSRaphael Isemann   // Defined variable without string: only getValue and eval return value set.
617e15e969aSThomas Preud'homme   FooVar.setValue(APInt(64, 42u));
618e15e969aSThomas Preud'homme   std::optional<APInt> Value = FooVar.getValue();
6195ffd940aSRaphael Isemann   ASSERT_TRUE(Value);
620e15e969aSThomas Preud'homme   EXPECT_EQ(42, Value->getSExtValue());
6215ffd940aSRaphael Isemann   EXPECT_FALSE(FooVar.getStringValue());
6225ffd940aSRaphael Isemann   EvalResult = FooVarUse.eval();
6235ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(EvalResult, Succeeded());
624e15e969aSThomas Preud'homme   EXPECT_EQ(42, EvalResult->getSExtValue());
6255ffd940aSRaphael Isemann 
6265ffd940aSRaphael Isemann   // Defined variable with string: getValue, eval, and getStringValue return
6275ffd940aSRaphael Isemann   // value set.
6285ffd940aSRaphael Isemann   StringRef StringValue = "925";
629e15e969aSThomas Preud'homme   FooVar.setValue(APInt(64, 925u), StringValue);
6305ffd940aSRaphael Isemann   Value = FooVar.getValue();
6315ffd940aSRaphael Isemann   ASSERT_TRUE(Value);
632e15e969aSThomas Preud'homme   EXPECT_EQ(925, Value->getSExtValue());
6335ffd940aSRaphael Isemann   // getStringValue should return the same memory not just the same characters.
6342fa744e6SFangrui Song   EXPECT_EQ(StringValue.begin(), FooVar.getStringValue()->begin());
6352fa744e6SFangrui Song   EXPECT_EQ(StringValue.end(), FooVar.getStringValue()->end());
6365ffd940aSRaphael Isemann   EvalResult = FooVarUse.eval();
6375ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(EvalResult, Succeeded());
638e15e969aSThomas Preud'homme   EXPECT_EQ(925, EvalResult->getSExtValue());
639e15e969aSThomas Preud'homme   EXPECT_EQ(925, EvalResult->getSExtValue());
6405ffd940aSRaphael Isemann 
6415ffd940aSRaphael Isemann   // Clearing variable: getValue and eval fail. Error returned by eval holds
6425ffd940aSRaphael Isemann   // the name of the cleared variable.
6435ffd940aSRaphael Isemann   FooVar.clearValue();
6445ffd940aSRaphael Isemann   EXPECT_FALSE(FooVar.getValue());
6455ffd940aSRaphael Isemann   EXPECT_FALSE(FooVar.getStringValue());
6465ffd940aSRaphael Isemann   EvalResult = FooVarUse.eval();
6475ffd940aSRaphael Isemann   expectUndefErrors({"FOO"}, EvalResult.takeError());
6485ffd940aSRaphael Isemann }
6495ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,Binop)6505ffd940aSRaphael Isemann TEST_F(FileCheckTest, Binop) {
6515ffd940aSRaphael Isemann   SourceMgr SM;
6525ffd940aSRaphael Isemann 
6535ffd940aSRaphael Isemann   StringRef ExprStr = bufferize(SM, "FOO+BAR");
6545ffd940aSRaphael Isemann   StringRef FooStr = ExprStr.take_front(3);
6555ffd940aSRaphael Isemann   NumericVariable FooVar(FooStr,
6565ffd940aSRaphael Isemann                          ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1);
657e15e969aSThomas Preud'homme   FooVar.setValue(APInt(64, 42u));
6585ffd940aSRaphael Isemann   std::unique_ptr<NumericVariableUse> FooVarUse =
6595ffd940aSRaphael Isemann       std::make_unique<NumericVariableUse>(FooStr, &FooVar);
6605ffd940aSRaphael Isemann   StringRef BarStr = ExprStr.take_back(3);
6615ffd940aSRaphael Isemann   NumericVariable BarVar(BarStr,
6625ffd940aSRaphael Isemann                          ExpressionFormat(ExpressionFormat::Kind::Unsigned), 2);
663e15e969aSThomas Preud'homme   BarVar.setValue(APInt(64, 18u));
6645ffd940aSRaphael Isemann   std::unique_ptr<NumericVariableUse> BarVarUse =
6655ffd940aSRaphael Isemann       std::make_unique<NumericVariableUse>(BarStr, &BarVar);
6660726cb00SThomas Preud'homme   BinaryOperation Binop(ExprStr, exprAdd, std::move(FooVarUse),
6675ffd940aSRaphael Isemann                         std::move(BarVarUse));
6685ffd940aSRaphael Isemann 
6690726cb00SThomas Preud'homme   // Defined variables with same bitwidth and no overflow: eval returns right
6700726cb00SThomas Preud'homme   // value; implicit formas is as expected.
671e15e969aSThomas Preud'homme   Expected<APInt> Value = Binop.eval();
6725ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(Value, Succeeded());
673e15e969aSThomas Preud'homme   EXPECT_EQ(60, Value->getSExtValue());
6745ffd940aSRaphael Isemann   Expected<ExpressionFormat> ImplicitFormat = Binop.getImplicitFormat(SM);
6755ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
6765ffd940aSRaphael Isemann   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
6775ffd940aSRaphael Isemann 
6780726cb00SThomas Preud'homme   // Defined variables with different bitwidth and no overflow: eval succeeds
6790726cb00SThomas Preud'homme   // and return the right value.
680e15e969aSThomas Preud'homme   BarVar.setValue(APInt(32, 18u));
6810726cb00SThomas Preud'homme   Value = Binop.eval();
6820726cb00SThomas Preud'homme   ASSERT_THAT_EXPECTED(Value, Succeeded());
683e15e969aSThomas Preud'homme   EXPECT_EQ(60, Value->getSExtValue());
6840726cb00SThomas Preud'homme 
6850726cb00SThomas Preud'homme   // Defined variables with same bitwidth and wider result (i.e. overflow):
6860726cb00SThomas Preud'homme   // eval succeeds and return the right value in a wider APInt.
687e15e969aSThomas Preud'homme   BarVar.setValue(APInt(64, AbsoluteMaxInt64));
6880726cb00SThomas Preud'homme   Value = Binop.eval();
6890726cb00SThomas Preud'homme   ASSERT_THAT_EXPECTED(Value, Succeeded());
690e15e969aSThomas Preud'homme   EXPECT_EQ(128u, Value->getBitWidth());
691e15e969aSThomas Preud'homme   EXPECT_EQ(APInt(128, AbsoluteMaxInt64 + FooVar.getValue()->getZExtValue()),
692e15e969aSThomas Preud'homme             *Value);
6930726cb00SThomas Preud'homme 
6945ffd940aSRaphael Isemann   // 1 undefined variable: eval fails, error contains name of undefined
6955ffd940aSRaphael Isemann   // variable.
6965ffd940aSRaphael Isemann   FooVar.clearValue();
6975ffd940aSRaphael Isemann   Value = Binop.eval();
6985ffd940aSRaphael Isemann   expectUndefErrors({"FOO"}, Value.takeError());
6995ffd940aSRaphael Isemann 
7005ffd940aSRaphael Isemann   // 2 undefined variables: eval fails, error contains names of all undefined
7015ffd940aSRaphael Isemann   // variables.
7025ffd940aSRaphael Isemann   BarVar.clearValue();
7035ffd940aSRaphael Isemann   Value = Binop.eval();
7045ffd940aSRaphael Isemann   expectUndefErrors({"FOO", "BAR"}, Value.takeError());
7055ffd940aSRaphael Isemann 
7065ffd940aSRaphael Isemann   // Literal + Variable has format of variable.
7075ffd940aSRaphael Isemann   ExprStr = bufferize(SM, "FOO+18");
7085ffd940aSRaphael Isemann   FooStr = ExprStr.take_front(3);
7095ffd940aSRaphael Isemann   StringRef EighteenStr = ExprStr.take_back(2);
7105ffd940aSRaphael Isemann   FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
7115ffd940aSRaphael Isemann   std::unique_ptr<ExpressionLiteral> Eighteen =
7120726cb00SThomas Preud'homme       std::make_unique<ExpressionLiteral>(EighteenStr, APInt(64, 18u));
7130726cb00SThomas Preud'homme   Binop = BinaryOperation(ExprStr, exprAdd, std::move(FooVarUse),
7145ffd940aSRaphael Isemann                           std::move(Eighteen));
7155ffd940aSRaphael Isemann   ImplicitFormat = Binop.getImplicitFormat(SM);
7165ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
7175ffd940aSRaphael Isemann   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
7185ffd940aSRaphael Isemann   ExprStr = bufferize(SM, "18+FOO");
7195ffd940aSRaphael Isemann   FooStr = ExprStr.take_back(3);
7205ffd940aSRaphael Isemann   EighteenStr = ExprStr.take_front(2);
7215ffd940aSRaphael Isemann   FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
7220726cb00SThomas Preud'homme   Eighteen = std::make_unique<ExpressionLiteral>(EighteenStr, APInt(64, 18u));
7230726cb00SThomas Preud'homme   Binop = BinaryOperation(ExprStr, exprAdd, std::move(Eighteen),
7245ffd940aSRaphael Isemann                           std::move(FooVarUse));
7255ffd940aSRaphael Isemann   ImplicitFormat = Binop.getImplicitFormat(SM);
7265ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
7275ffd940aSRaphael Isemann   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
7285ffd940aSRaphael Isemann 
7295ffd940aSRaphael Isemann   // Variables with different implicit format conflict.
7305ffd940aSRaphael Isemann   ExprStr = bufferize(SM, "FOO+BAZ");
7315ffd940aSRaphael Isemann   FooStr = ExprStr.take_front(3);
7325ffd940aSRaphael Isemann   StringRef BazStr = ExprStr.take_back(3);
7335ffd940aSRaphael Isemann   NumericVariable BazVar(BazStr,
7345ffd940aSRaphael Isemann                          ExpressionFormat(ExpressionFormat::Kind::HexLower), 3);
7355ffd940aSRaphael Isemann   FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
7365ffd940aSRaphael Isemann   std::unique_ptr<NumericVariableUse> BazVarUse =
7375ffd940aSRaphael Isemann       std::make_unique<NumericVariableUse>(BazStr, &BazVar);
7380726cb00SThomas Preud'homme   Binop = BinaryOperation(ExprStr, exprAdd, std::move(FooVarUse),
7395ffd940aSRaphael Isemann                           std::move(BazVarUse));
7405ffd940aSRaphael Isemann   ImplicitFormat = Binop.getImplicitFormat(SM);
7415ffd940aSRaphael Isemann   expectDiagnosticError(
7425ffd940aSRaphael Isemann       "implicit format conflict between 'FOO' (%u) and 'BAZ' (%x), "
7435ffd940aSRaphael Isemann       "need an explicit format specifier",
7445ffd940aSRaphael Isemann       ImplicitFormat.takeError());
7455ffd940aSRaphael Isemann 
7465ffd940aSRaphael Isemann   // All variable conflicts are reported.
7475ffd940aSRaphael Isemann   ExprStr = bufferize(SM, "(FOO+BAZ)+(FOO+QUUX)");
7485ffd940aSRaphael Isemann   StringRef Paren1ExprStr = ExprStr.substr(1, 7);
7495ffd940aSRaphael Isemann   FooStr = Paren1ExprStr.take_front(3);
7505ffd940aSRaphael Isemann   BazStr = Paren1ExprStr.take_back(3);
7515ffd940aSRaphael Isemann   StringRef Paren2ExprStr = ExprStr.substr(ExprStr.rfind('(') + 1, 8);
7525ffd940aSRaphael Isemann   StringRef FooStr2 = Paren2ExprStr.take_front(3);
7535ffd940aSRaphael Isemann   StringRef QuuxStr = Paren2ExprStr.take_back(4);
7545ffd940aSRaphael Isemann   FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
7555ffd940aSRaphael Isemann   BazVarUse = std::make_unique<NumericVariableUse>(BazStr, &BazVar);
7565ffd940aSRaphael Isemann   std::unique_ptr<NumericVariableUse> FooVarUse2 =
7575ffd940aSRaphael Isemann       std::make_unique<NumericVariableUse>(FooStr2, &FooVar);
7585ffd940aSRaphael Isemann   NumericVariable QuuxVar(
7595ffd940aSRaphael Isemann       QuuxStr, ExpressionFormat(ExpressionFormat::Kind::HexLower), 4);
7605ffd940aSRaphael Isemann   std::unique_ptr<NumericVariableUse> QuuxVarUse =
7615ffd940aSRaphael Isemann       std::make_unique<NumericVariableUse>(QuuxStr, &QuuxVar);
7625ffd940aSRaphael Isemann   std::unique_ptr<BinaryOperation> Binop1 = std::make_unique<BinaryOperation>(
7630726cb00SThomas Preud'homme       ExprStr.take_front(9), exprAdd, std::move(FooVarUse),
7640726cb00SThomas Preud'homme       std::move(BazVarUse));
7655ffd940aSRaphael Isemann   std::unique_ptr<BinaryOperation> Binop2 = std::make_unique<BinaryOperation>(
7660726cb00SThomas Preud'homme       ExprStr.take_back(10), exprAdd, std::move(FooVarUse2),
7675ffd940aSRaphael Isemann       std::move(QuuxVarUse));
7685ffd940aSRaphael Isemann   std::unique_ptr<BinaryOperation> OuterBinop =
7690726cb00SThomas Preud'homme       std::make_unique<BinaryOperation>(ExprStr, exprAdd, std::move(Binop1),
7705ffd940aSRaphael Isemann                                         std::move(Binop2));
7715ffd940aSRaphael Isemann   ImplicitFormat = OuterBinop->getImplicitFormat(SM);
7725ffd940aSRaphael Isemann   expectSameErrors<ErrorDiagnostic>(
7735ffd940aSRaphael Isemann       {("implicit format conflict between 'FOO' (%u) and 'BAZ' (%x), need an "
7745ffd940aSRaphael Isemann        "explicit format specifier"),
7755ffd940aSRaphael Isemann        ("implicit format conflict between 'FOO' (%u) and 'QUUX' (%x), need an "
7765ffd940aSRaphael Isemann        "explicit format specifier")},
7775ffd940aSRaphael Isemann       ImplicitFormat.takeError());
7785ffd940aSRaphael Isemann }
7795ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ValidVarNameStart)7805ffd940aSRaphael Isemann TEST_F(FileCheckTest, ValidVarNameStart) {
7815ffd940aSRaphael Isemann   EXPECT_TRUE(Pattern::isValidVarNameStart('a'));
7825ffd940aSRaphael Isemann   EXPECT_TRUE(Pattern::isValidVarNameStart('G'));
7835ffd940aSRaphael Isemann   EXPECT_TRUE(Pattern::isValidVarNameStart('_'));
7845ffd940aSRaphael Isemann   EXPECT_FALSE(Pattern::isValidVarNameStart('2'));
7855ffd940aSRaphael Isemann   EXPECT_FALSE(Pattern::isValidVarNameStart('$'));
7865ffd940aSRaphael Isemann   EXPECT_FALSE(Pattern::isValidVarNameStart('@'));
7875ffd940aSRaphael Isemann   EXPECT_FALSE(Pattern::isValidVarNameStart('+'));
7885ffd940aSRaphael Isemann   EXPECT_FALSE(Pattern::isValidVarNameStart('-'));
7895ffd940aSRaphael Isemann   EXPECT_FALSE(Pattern::isValidVarNameStart(':'));
7905ffd940aSRaphael Isemann }
7915ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ParseVar)7925ffd940aSRaphael Isemann TEST_F(FileCheckTest, ParseVar) {
7935ffd940aSRaphael Isemann   SourceMgr SM;
7945ffd940aSRaphael Isemann   StringRef OrigVarName = bufferize(SM, "GoodVar42");
7955ffd940aSRaphael Isemann   StringRef VarName = OrigVarName;
7965ffd940aSRaphael Isemann   Expected<Pattern::VariableProperties> ParsedVarResult =
7975ffd940aSRaphael Isemann       Pattern::parseVariable(VarName, SM);
7985ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
7995ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
8005ffd940aSRaphael Isemann   EXPECT_TRUE(VarName.empty());
8015ffd940aSRaphael Isemann   EXPECT_FALSE(ParsedVarResult->IsPseudo);
8025ffd940aSRaphael Isemann 
8035ffd940aSRaphael Isemann   VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
8045ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8055ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
8065ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
8075ffd940aSRaphael Isemann   EXPECT_TRUE(VarName.empty());
8085ffd940aSRaphael Isemann   EXPECT_FALSE(ParsedVarResult->IsPseudo);
8095ffd940aSRaphael Isemann 
8105ffd940aSRaphael Isemann   VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
8115ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8125ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
8135ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
8145ffd940aSRaphael Isemann   EXPECT_TRUE(VarName.empty());
8155ffd940aSRaphael Isemann   EXPECT_TRUE(ParsedVarResult->IsPseudo);
8165ffd940aSRaphael Isemann 
8175ffd940aSRaphael Isemann   VarName = bufferize(SM, "42BadVar");
8185ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8195ffd940aSRaphael Isemann   expectDiagnosticError("invalid variable name", ParsedVarResult.takeError());
8205ffd940aSRaphael Isemann 
8215ffd940aSRaphael Isemann   VarName = bufferize(SM, "$@");
8225ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8235ffd940aSRaphael Isemann   expectDiagnosticError("invalid variable name", ParsedVarResult.takeError());
8245ffd940aSRaphael Isemann 
8255ffd940aSRaphael Isemann   VarName = OrigVarName = bufferize(SM, "B@dVar");
8265ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8275ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
8285ffd940aSRaphael Isemann   EXPECT_EQ(VarName, OrigVarName.substr(1));
8295ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, "B");
8305ffd940aSRaphael Isemann   EXPECT_FALSE(ParsedVarResult->IsPseudo);
8315ffd940aSRaphael Isemann 
8325ffd940aSRaphael Isemann   VarName = OrigVarName = bufferize(SM, "B$dVar");
8335ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8345ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
8355ffd940aSRaphael Isemann   EXPECT_EQ(VarName, OrigVarName.substr(1));
8365ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, "B");
8375ffd940aSRaphael Isemann   EXPECT_FALSE(ParsedVarResult->IsPseudo);
8385ffd940aSRaphael Isemann 
8395ffd940aSRaphael Isemann   VarName = bufferize(SM, "BadVar+");
8405ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8415ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
8425ffd940aSRaphael Isemann   EXPECT_EQ(VarName, "+");
8435ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, "BadVar");
8445ffd940aSRaphael Isemann   EXPECT_FALSE(ParsedVarResult->IsPseudo);
8455ffd940aSRaphael Isemann 
8465ffd940aSRaphael Isemann   VarName = bufferize(SM, "BadVar-");
8475ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8485ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
8495ffd940aSRaphael Isemann   EXPECT_EQ(VarName, "-");
8505ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, "BadVar");
8515ffd940aSRaphael Isemann   EXPECT_FALSE(ParsedVarResult->IsPseudo);
8525ffd940aSRaphael Isemann 
8535ffd940aSRaphael Isemann   VarName = bufferize(SM, "BadVar:");
8545ffd940aSRaphael Isemann   ParsedVarResult = Pattern::parseVariable(VarName, SM);
8555ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ParsedVarResult, Succeeded());
8565ffd940aSRaphael Isemann   EXPECT_EQ(VarName, ":");
8575ffd940aSRaphael Isemann   EXPECT_EQ(ParsedVarResult->Name, "BadVar");
8585ffd940aSRaphael Isemann   EXPECT_FALSE(ParsedVarResult->IsPseudo);
8595ffd940aSRaphael Isemann }
8605ffd940aSRaphael Isemann 
expectNotFoundError(Error Err)8615ffd940aSRaphael Isemann static void expectNotFoundError(Error Err) {
8625ffd940aSRaphael Isemann   expectError<NotFoundError>("String not found in input", std::move(Err));
8635ffd940aSRaphael Isemann }
8645ffd940aSRaphael Isemann 
8655ffd940aSRaphael Isemann class PatternTester {
8665ffd940aSRaphael Isemann private:
8675ffd940aSRaphael Isemann   size_t LineNumber = 1;
8685ffd940aSRaphael Isemann   SourceMgr SM;
8695ffd940aSRaphael Isemann   FileCheckRequest Req;
8705ffd940aSRaphael Isemann   FileCheckPatternContext Context;
8715ffd940aSRaphael Isemann   Pattern P{Check::CheckPlain, &Context, LineNumber};
8725ffd940aSRaphael Isemann 
8735ffd940aSRaphael Isemann public:
PatternTester()8745ffd940aSRaphael Isemann   PatternTester() {
8755ffd940aSRaphael Isemann     std::vector<StringRef> GlobalDefines = {"#FOO=42", "BAR=BAZ", "#add=7"};
8765ffd940aSRaphael Isemann     // An ASSERT_FALSE would make more sense but cannot be used in a
8775ffd940aSRaphael Isemann     // constructor.
8785ffd940aSRaphael Isemann     EXPECT_THAT_ERROR(Context.defineCmdlineVariables(GlobalDefines, SM),
8795ffd940aSRaphael Isemann                       Succeeded());
8805ffd940aSRaphael Isemann     Context.createLineVariable();
8815ffd940aSRaphael Isemann     // Call parsePattern to have @LINE defined.
8825ffd940aSRaphael Isemann     P.parsePattern("N/A", "CHECK", SM, Req);
8835ffd940aSRaphael Isemann     // parsePattern does not expect to be called twice for the same line and
8845ffd940aSRaphael Isemann     // will set FixedStr and RegExStr incorrectly if it is. Therefore prepare
8855ffd940aSRaphael Isemann     // a pattern for a different line.
8865ffd940aSRaphael Isemann     initNextPattern();
8875ffd940aSRaphael Isemann   }
8885ffd940aSRaphael Isemann 
initNextPattern()8895ffd940aSRaphael Isemann   void initNextPattern() {
8905ffd940aSRaphael Isemann     P = Pattern(Check::CheckPlain, &Context, ++LineNumber);
8915ffd940aSRaphael Isemann   }
8925ffd940aSRaphael Isemann 
getLineNumber() const8935ffd940aSRaphael Isemann   size_t getLineNumber() const { return LineNumber; }
8945ffd940aSRaphael Isemann 
8955ffd940aSRaphael Isemann   Expected<std::unique_ptr<Expression>>
parseSubst(StringRef Expr,bool IsLegacyLineExpr=false)8965ffd940aSRaphael Isemann   parseSubst(StringRef Expr, bool IsLegacyLineExpr = false) {
8975ffd940aSRaphael Isemann     StringRef ExprBufferRef = bufferize(SM, Expr);
89894081642SFangrui Song     std::optional<NumericVariable *> DefinedNumericVariable;
8995ffd940aSRaphael Isemann     return P.parseNumericSubstitutionBlock(
9005ffd940aSRaphael Isemann         ExprBufferRef, DefinedNumericVariable, IsLegacyLineExpr, LineNumber,
9015ffd940aSRaphael Isemann         &Context, SM);
9025ffd940aSRaphael Isemann   }
9035ffd940aSRaphael Isemann 
parsePattern(StringRef Pattern)9045ffd940aSRaphael Isemann   bool parsePattern(StringRef Pattern) {
9055ffd940aSRaphael Isemann     StringRef PatBufferRef = bufferize(SM, Pattern);
9065ffd940aSRaphael Isemann     return P.parsePattern(PatBufferRef, "CHECK", SM, Req);
9075ffd940aSRaphael Isemann   }
9085ffd940aSRaphael Isemann 
match(StringRef Buffer)9095ffd940aSRaphael Isemann   Expected<size_t> match(StringRef Buffer) {
9105ffd940aSRaphael Isemann     StringRef BufferRef = bufferize(SM, Buffer);
911dd59c132SJoel E. Denny     Pattern::MatchResult Res = P.match(BufferRef, SM);
912dd59c132SJoel E. Denny     if (Res.TheError)
913dd59c132SJoel E. Denny       return std::move(Res.TheError);
914dd59c132SJoel E. Denny     return Res.TheMatch->Pos;
9155ffd940aSRaphael Isemann   }
9165ffd940aSRaphael Isemann 
printVariableDefs(FileCheckDiag::MatchType MatchTy,std::vector<FileCheckDiag> & Diags)9175ffd940aSRaphael Isemann   void printVariableDefs(FileCheckDiag::MatchType MatchTy,
9185ffd940aSRaphael Isemann                          std::vector<FileCheckDiag> &Diags) {
9195ffd940aSRaphael Isemann     P.printVariableDefs(SM, MatchTy, &Diags);
9205ffd940aSRaphael Isemann   }
9215ffd940aSRaphael Isemann };
9225ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ParseNumericSubstitutionBlock)9235ffd940aSRaphael Isemann TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
9245ffd940aSRaphael Isemann   PatternTester Tester;
9255ffd940aSRaphael Isemann 
9265ffd940aSRaphael Isemann   // Variable definition.
9275ffd940aSRaphael Isemann 
9285ffd940aSRaphael Isemann   expectDiagnosticError("invalid variable name",
9295ffd940aSRaphael Isemann                         Tester.parseSubst("%VAR:").takeError());
9305ffd940aSRaphael Isemann 
9315ffd940aSRaphael Isemann   expectDiagnosticError("definition of pseudo numeric variable unsupported",
9325ffd940aSRaphael Isemann                         Tester.parseSubst("@LINE:").takeError());
9335ffd940aSRaphael Isemann 
9345ffd940aSRaphael Isemann   expectDiagnosticError("string variable with name 'BAR' already exists",
9355ffd940aSRaphael Isemann                         Tester.parseSubst("BAR:").takeError());
9365ffd940aSRaphael Isemann 
9375ffd940aSRaphael Isemann   expectDiagnosticError("unexpected characters after numeric variable name",
9385ffd940aSRaphael Isemann                         Tester.parseSubst("VAR GARBAGE:").takeError());
9395ffd940aSRaphael Isemann 
9405ffd940aSRaphael Isemann   // Change of format.
9415ffd940aSRaphael Isemann   expectDiagnosticError("format different from previous variable definition",
9425ffd940aSRaphael Isemann                         Tester.parseSubst("%X,FOO:").takeError());
9435ffd940aSRaphael Isemann 
9445ffd940aSRaphael Isemann   // Invalid format.
9455ffd940aSRaphael Isemann   expectDiagnosticError("invalid matching format specification in expression",
9465ffd940aSRaphael Isemann                         Tester.parseSubst("X,VAR1:").takeError());
9475ffd940aSRaphael Isemann   expectDiagnosticError("invalid format specifier in expression",
9485ffd940aSRaphael Isemann                         Tester.parseSubst("%F,VAR1:").takeError());
9495ffd940aSRaphael Isemann   expectDiagnosticError("invalid matching format specification in expression",
9505ffd940aSRaphael Isemann                         Tester.parseSubst("%X a,VAR1:").takeError());
9515ffd940aSRaphael Isemann 
9525ffd940aSRaphael Isemann   // Acceptable variable definition.
9535ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("VAR1:"), Succeeded());
9545ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("  VAR2:"), Succeeded());
9555ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("VAR3  :"), Succeeded());
9565ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("VAR3:  "), Succeeded());
9575ffd940aSRaphael Isemann 
9585ffd940aSRaphael Isemann   // Acceptable variable definition with format specifier. Use parsePattern for
9595ffd940aSRaphael Isemann   // variables whose definition needs to be visible for later checks.
9605ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[#%u, VAR_UNSIGNED:]]"));
9615ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[#%x, VAR_LOWER_HEX:]]"));
9625ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%X, VAR_UPPER_HEX:"), Succeeded());
9635ffd940aSRaphael Isemann 
9645ffd940aSRaphael Isemann   // Acceptable variable definition with precision specifier.
9655ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[#%.8X, PADDED_ADDR:]]"));
9665ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[#%.8, PADDED_NUM:]]"));
9675ffd940aSRaphael Isemann 
968f9e2a62cSThomas Preud'homme   // Acceptable variable definition in alternate form.
969f9e2a62cSThomas Preud'homme   EXPECT_THAT_EXPECTED(Tester.parseSubst("%#x, PREFIXED_ADDR:"), Succeeded());
970f9e2a62cSThomas Preud'homme   EXPECT_THAT_EXPECTED(Tester.parseSubst("%#X, PREFIXED_ADDR:"), Succeeded());
971f9e2a62cSThomas Preud'homme 
972f9e2a62cSThomas Preud'homme   // Acceptable variable definition in alternate form.
973f9e2a62cSThomas Preud'homme   expectDiagnosticError("alternate form only supported for hex values",
974f9e2a62cSThomas Preud'homme                         Tester.parseSubst("%#u, PREFIXED_UNSI:").takeError());
975f9e2a62cSThomas Preud'homme   expectDiagnosticError("alternate form only supported for hex values",
976f9e2a62cSThomas Preud'homme                         Tester.parseSubst("%#d, PREFIXED_UNSI:").takeError());
977f9e2a62cSThomas Preud'homme 
9785ffd940aSRaphael Isemann   // Acceptable variable definition from a numeric expression.
9795ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOOBAR: FOO+1"), Succeeded());
9805ffd940aSRaphael Isemann 
9815ffd940aSRaphael Isemann   // Numeric expression. Switch to next line to make above valid definition
9825ffd940aSRaphael Isemann   // available in expressions.
9835ffd940aSRaphael Isemann   Tester.initNextPattern();
9845ffd940aSRaphael Isemann 
9855ffd940aSRaphael Isemann   // Invalid variable name.
9865ffd940aSRaphael Isemann   expectDiagnosticError("invalid matching constraint or operand format",
9875ffd940aSRaphael Isemann                         Tester.parseSubst("%VAR").takeError());
9885ffd940aSRaphael Isemann 
9895ffd940aSRaphael Isemann   expectDiagnosticError("invalid pseudo numeric variable '@FOO'",
9905ffd940aSRaphael Isemann                         Tester.parseSubst("@FOO").takeError());
9915ffd940aSRaphael Isemann 
9925ffd940aSRaphael Isemann   // parsePattern() is used here instead of parseSubst() for the variable to be
9935ffd940aSRaphael Isemann   // recorded in GlobalNumericVariableTable and thus appear defined to
9945ffd940aSRaphael Isemann   // parseNumericVariableUse(). Note that the same pattern object is used for
9955ffd940aSRaphael Isemann   // the parsePattern() and parseSubst() since no initNextPattern() is called,
9965ffd940aSRaphael Isemann   // thus appearing as being on the same line from the pattern's point of view.
9975ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#SAME_LINE_VAR:]]"));
9985ffd940aSRaphael Isemann   expectDiagnosticError("numeric variable 'SAME_LINE_VAR' defined earlier in "
9995ffd940aSRaphael Isemann                         "the same CHECK directive",
10005ffd940aSRaphael Isemann                         Tester.parseSubst("SAME_LINE_VAR").takeError());
10015ffd940aSRaphael Isemann 
10025ffd940aSRaphael Isemann   // Invalid use of variable defined on the same line from an expression not
10035ffd940aSRaphael Isemann   // using any variable defined on the same line.
10045ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#SAME_LINE_EXPR_VAR:@LINE+1]]"));
10055ffd940aSRaphael Isemann   expectDiagnosticError("numeric variable 'SAME_LINE_EXPR_VAR' defined earlier "
10065ffd940aSRaphael Isemann                         "in the same CHECK directive",
10075ffd940aSRaphael Isemann                         Tester.parseSubst("SAME_LINE_EXPR_VAR").takeError());
10085ffd940aSRaphael Isemann 
10095ffd940aSRaphael Isemann   // Valid use of undefined variable which creates the variable and record it
10105ffd940aSRaphael Isemann   // in GlobalNumericVariableTable.
10115ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(Tester.parseSubst("UNDEF"), Succeeded());
10125ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[UNDEF:.*]]"));
10135ffd940aSRaphael Isemann 
10145ffd940aSRaphael Isemann   // Invalid literal.
10155ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation 'U'",
10165ffd940aSRaphael Isemann                         Tester.parseSubst("42U").takeError());
10175ffd940aSRaphael Isemann 
10185ffd940aSRaphael Isemann   // Valid empty expression.
10195ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst(""), Succeeded());
10205ffd940aSRaphael Isemann 
10215ffd940aSRaphael Isemann   // Invalid equality matching constraint with empty expression.
10225ffd940aSRaphael Isemann   expectDiagnosticError("empty numeric expression should not have a constraint",
10235ffd940aSRaphael Isemann                         Tester.parseSubst("==").takeError());
10245ffd940aSRaphael Isemann 
10255ffd940aSRaphael Isemann   // Valid single operand expression.
10265ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO"), Succeeded());
10275ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("18"), Succeeded());
10285ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst(std::to_string(MaxUint64)),
10295ffd940aSRaphael Isemann                        Succeeded());
10305ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("0x12"), Succeeded());
10315ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("-30"), Succeeded());
10325ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst(std::to_string(MinInt64)),
10335ffd940aSRaphael Isemann                        Succeeded());
10345ffd940aSRaphael Isemann 
10355ffd940aSRaphael Isemann   // Valid optional matching constraint.
10365ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("==FOO"), Succeeded());
10375ffd940aSRaphael Isemann 
10385ffd940aSRaphael Isemann   // Invalid matching constraint.
10395ffd940aSRaphael Isemann   expectDiagnosticError("invalid matching constraint or operand format",
10405ffd940aSRaphael Isemann                         Tester.parseSubst("+=FOO").takeError());
10415ffd940aSRaphael Isemann 
10425ffd940aSRaphael Isemann   // Invalid format.
10435ffd940aSRaphael Isemann   expectDiagnosticError("invalid matching format specification in expression",
10445ffd940aSRaphael Isemann                         Tester.parseSubst("X,FOO:").takeError());
10455ffd940aSRaphael Isemann   expectDiagnosticError("invalid format specifier in expression",
10465ffd940aSRaphael Isemann                         Tester.parseSubst("%F,FOO").takeError());
10475ffd940aSRaphael Isemann   expectDiagnosticError("invalid matching format specification in expression",
10485ffd940aSRaphael Isemann                         Tester.parseSubst("%X a,FOO").takeError());
10495ffd940aSRaphael Isemann 
10505ffd940aSRaphael Isemann   // Valid expression with 2 or more operands.
10515ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+3"), Succeeded());
10525ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+0xC"), Succeeded());
10535ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO-3+FOO"), Succeeded());
10545ffd940aSRaphael Isemann 
10555ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation '/'",
10565ffd940aSRaphael Isemann                         Tester.parseSubst("@LINE/2").takeError());
10575ffd940aSRaphael Isemann 
10585ffd940aSRaphael Isemann   expectDiagnosticError("missing operand in expression",
10595ffd940aSRaphael Isemann                         Tester.parseSubst("@LINE+").takeError());
10605ffd940aSRaphael Isemann 
10615ffd940aSRaphael Isemann   // Errors in RHS operand are bubbled up by parseBinop() to
10625ffd940aSRaphael Isemann   // parseNumericSubstitutionBlock().
10635ffd940aSRaphael Isemann   expectDiagnosticError("invalid operand format",
10645ffd940aSRaphael Isemann                         Tester.parseSubst("@LINE+%VAR").takeError());
10655ffd940aSRaphael Isemann 
10665ffd940aSRaphael Isemann   // Invalid legacy @LINE expression with non literal rhs.
10675ffd940aSRaphael Isemann   expectDiagnosticError(
10685ffd940aSRaphael Isemann       "invalid operand format",
10695ffd940aSRaphael Isemann       Tester.parseSubst("@LINE+@LINE", /*IsLegacyNumExpr=*/true).takeError());
10705ffd940aSRaphael Isemann 
10715ffd940aSRaphael Isemann   // Invalid legacy @LINE expression made of a single literal.
10725ffd940aSRaphael Isemann   expectDiagnosticError(
10735ffd940aSRaphael Isemann       "invalid variable name",
10745ffd940aSRaphael Isemann       Tester.parseSubst("2", /*IsLegacyNumExpr=*/true).takeError());
10755ffd940aSRaphael Isemann 
10765ffd940aSRaphael Isemann   // Invalid hex literal in legacy @LINE expression.
10775ffd940aSRaphael Isemann   expectDiagnosticError(
10785ffd940aSRaphael Isemann       "unexpected characters at end of expression 'xC'",
10795ffd940aSRaphael Isemann       Tester.parseSubst("@LINE+0xC", /*LegacyLineExpr=*/true).takeError());
10805ffd940aSRaphael Isemann 
10815ffd940aSRaphael Isemann   // Valid expression with format specifier.
10825ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%u, FOO"), Succeeded());
10835ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%d, FOO"), Succeeded());
10845ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%x, FOO"), Succeeded());
10855ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%X, FOO"), Succeeded());
10865ffd940aSRaphael Isemann 
10875ffd940aSRaphael Isemann   // Valid expression with precision specifier.
10885ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%.8u, FOO"), Succeeded());
10895ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%.8, FOO"), Succeeded());
10905ffd940aSRaphael Isemann 
10915ffd940aSRaphael Isemann   // Valid legacy @LINE expression.
10925ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("@LINE+2", /*IsLegacyNumExpr=*/true),
10935ffd940aSRaphael Isemann                        Succeeded());
10945ffd940aSRaphael Isemann 
10955ffd940aSRaphael Isemann   // Invalid legacy @LINE expression with more than 2 operands.
10965ffd940aSRaphael Isemann   expectDiagnosticError(
10975ffd940aSRaphael Isemann       "unexpected characters at end of expression '+@LINE'",
10985ffd940aSRaphael Isemann       Tester.parseSubst("@LINE+2+@LINE", /*IsLegacyNumExpr=*/true).takeError());
10995ffd940aSRaphael Isemann   expectDiagnosticError(
11005ffd940aSRaphael Isemann       "unexpected characters at end of expression '+2'",
11015ffd940aSRaphael Isemann       Tester.parseSubst("@LINE+2+2", /*IsLegacyNumExpr=*/true).takeError());
11025ffd940aSRaphael Isemann 
11035ffd940aSRaphael Isemann   // Valid expression with several variables when their implicit formats do not
11045ffd940aSRaphael Isemann   // conflict.
11055ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+VAR_UNSIGNED"), Succeeded());
11065ffd940aSRaphael Isemann 
11075ffd940aSRaphael Isemann   // Valid implicit format conflict in presence of explicit formats.
11085ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("%X,FOO+VAR_LOWER_HEX"), Succeeded());
11095ffd940aSRaphael Isemann 
11105ffd940aSRaphael Isemann   // Implicit format conflict.
11115ffd940aSRaphael Isemann   expectDiagnosticError(
11125ffd940aSRaphael Isemann       "implicit format conflict between 'FOO' (%u) and "
11135ffd940aSRaphael Isemann       "'VAR_LOWER_HEX' (%x), need an explicit format specifier",
11145ffd940aSRaphael Isemann       Tester.parseSubst("FOO+VAR_LOWER_HEX").takeError());
11155ffd940aSRaphael Isemann 
11165ffd940aSRaphael Isemann   // Simple parenthesized expressions:
11175ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("(1)"), Succeeded());
11185ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("(1+1)"), Succeeded());
11195ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("(1)+1"), Succeeded());
11205ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("((1)+1)"), Succeeded());
11215ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("((1)+X)"), Succeeded());
11225ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("((X)+Y)"), Succeeded());
11235ffd940aSRaphael Isemann 
11245ffd940aSRaphael Isemann   expectDiagnosticError("missing operand in expression",
11255ffd940aSRaphael Isemann                         Tester.parseSubst("(").takeError());
11265ffd940aSRaphael Isemann   expectDiagnosticError("missing ')' at end of nested expression",
11275ffd940aSRaphael Isemann                         Tester.parseSubst("(1").takeError());
11285ffd940aSRaphael Isemann   expectDiagnosticError("missing operand in expression",
11295ffd940aSRaphael Isemann                         Tester.parseSubst("(1+").takeError());
11305ffd940aSRaphael Isemann   expectDiagnosticError("missing ')' at end of nested expression",
11315ffd940aSRaphael Isemann                         Tester.parseSubst("(1+1").takeError());
11325ffd940aSRaphael Isemann   expectDiagnosticError("missing ')' at end of nested expression",
11335ffd940aSRaphael Isemann                         Tester.parseSubst("((1+2+3").takeError());
11345ffd940aSRaphael Isemann   expectDiagnosticError("missing ')' at end of nested expression",
11355ffd940aSRaphael Isemann                         Tester.parseSubst("((1+2)+3").takeError());
11365ffd940aSRaphael Isemann 
11375ffd940aSRaphael Isemann   // Test missing operation between operands:
11385ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation '('",
11395ffd940aSRaphael Isemann                         Tester.parseSubst("(1)(2)").takeError());
11405ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation '('",
11415ffd940aSRaphael Isemann                         Tester.parseSubst("2(X)").takeError());
11425ffd940aSRaphael Isemann 
11435ffd940aSRaphael Isemann   // Test more closing than opening parentheses. The diagnostic messages are
11445ffd940aSRaphael Isemann   // not ideal, but for now simply check that we reject invalid input.
11455ffd940aSRaphael Isemann   expectDiagnosticError("invalid matching constraint or operand format",
11465ffd940aSRaphael Isemann                         Tester.parseSubst(")").takeError());
11475ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation ')'",
11485ffd940aSRaphael Isemann                         Tester.parseSubst("1)").takeError());
11495ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation ')'",
11505ffd940aSRaphael Isemann                         Tester.parseSubst("(1+2))").takeError());
11515ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation ')'",
11525ffd940aSRaphael Isemann                         Tester.parseSubst("(2))").takeError());
11535ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation ')'",
11545ffd940aSRaphael Isemann                         Tester.parseSubst("(1))(").takeError());
11555ffd940aSRaphael Isemann 
11565ffd940aSRaphael Isemann   // Valid expression with function call.
11575ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO,3)"), Succeeded());
11585ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add (FOO,3)"), Succeeded());
11595ffd940aSRaphael Isemann   // Valid expression with nested function call.
11605ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO, min(BAR,10))"), Succeeded());
11615ffd940aSRaphael Isemann   // Valid expression with function call taking expression as argument.
11625ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO, (BAR+10) + 3)"),
11635ffd940aSRaphael Isemann                        Succeeded());
11645ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add(FOO, min (BAR,10) + 3)"),
11655ffd940aSRaphael Isemann                        Succeeded());
11665ffd940aSRaphael Isemann   // Valid expression with variable named the same as a function.
11675ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add"), Succeeded());
11685ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add+FOO"), Succeeded());
11695ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO+add"), Succeeded());
11705ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.parseSubst("add(add,add)+add"), Succeeded());
11715ffd940aSRaphael Isemann 
11725ffd940aSRaphael Isemann   // Malformed call syntax.
11735ffd940aSRaphael Isemann   expectDiagnosticError("missing ')' at end of call expression",
11745ffd940aSRaphael Isemann                         Tester.parseSubst("add(FOO,(BAR+7)").takeError());
11755ffd940aSRaphael Isemann   expectDiagnosticError("missing ')' at end of call expression",
11765ffd940aSRaphael Isemann                         Tester.parseSubst("add(FOO,min(BAR,7)").takeError());
11775ffd940aSRaphael Isemann   expectDiagnosticError("missing argument",
11785ffd940aSRaphael Isemann                         Tester.parseSubst("add(FOO,)").takeError());
11795ffd940aSRaphael Isemann   expectDiagnosticError("missing argument",
11805ffd940aSRaphael Isemann                         Tester.parseSubst("add(,FOO)").takeError());
11815ffd940aSRaphael Isemann   expectDiagnosticError("missing argument",
11825ffd940aSRaphael Isemann                         Tester.parseSubst("add(FOO,,3)").takeError());
11835ffd940aSRaphael Isemann 
11845ffd940aSRaphael Isemann   // Valid call, but to an unknown function.
11855ffd940aSRaphael Isemann   expectDiagnosticError("call to undefined function 'bogus_function'",
11865ffd940aSRaphael Isemann                         Tester.parseSubst("bogus_function(FOO,3)").takeError());
11875ffd940aSRaphael Isemann   expectDiagnosticError("call to undefined function '@add'",
11885ffd940aSRaphael Isemann                         Tester.parseSubst("@add(2,3)").takeError());
11895ffd940aSRaphael Isemann   expectDiagnosticError("call to undefined function '$add'",
11905ffd940aSRaphael Isemann                         Tester.parseSubst("$add(2,3)").takeError());
11915ffd940aSRaphael Isemann   expectDiagnosticError("call to undefined function 'FOO'",
11925ffd940aSRaphael Isemann                         Tester.parseSubst("FOO(2,3)").takeError());
11935ffd940aSRaphael Isemann   expectDiagnosticError("call to undefined function 'FOO'",
11945ffd940aSRaphael Isemann                         Tester.parseSubst("FOO (2,3)").takeError());
11955ffd940aSRaphael Isemann 
11965ffd940aSRaphael Isemann   // Valid call, but with incorrect argument count.
11975ffd940aSRaphael Isemann   expectDiagnosticError("function 'add' takes 2 arguments but 1 given",
11985ffd940aSRaphael Isemann                         Tester.parseSubst("add(FOO)").takeError());
11995ffd940aSRaphael Isemann   expectDiagnosticError("function 'add' takes 2 arguments but 3 given",
12005ffd940aSRaphael Isemann                         Tester.parseSubst("add(FOO,3,4)").takeError());
12015ffd940aSRaphael Isemann 
12025ffd940aSRaphael Isemann   // Valid call, but not part of a valid expression.
12035ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation 'a'",
12045ffd940aSRaphael Isemann                         Tester.parseSubst("2add(FOO,2)").takeError());
12055ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation 'a'",
12065ffd940aSRaphael Isemann                         Tester.parseSubst("FOO add(FOO,2)").takeError());
12075ffd940aSRaphael Isemann   expectDiagnosticError("unsupported operation 'a'",
12085ffd940aSRaphael Isemann                         Tester.parseSubst("add(FOO,2)add(FOO,2)").takeError());
12095ffd940aSRaphael Isemann }
12105ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,ParsePattern)12115ffd940aSRaphael Isemann TEST_F(FileCheckTest, ParsePattern) {
12125ffd940aSRaphael Isemann   PatternTester Tester;
12135ffd940aSRaphael Isemann 
12145ffd940aSRaphael Isemann   // Invalid space in string substitution.
12155ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[ BAR]]"));
12165ffd940aSRaphael Isemann 
12175ffd940aSRaphael Isemann   // Invalid variable name in string substitution.
12185ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[42INVALID]]"));
12195ffd940aSRaphael Isemann 
12205ffd940aSRaphael Isemann   // Invalid string variable definition.
12215ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[@PAT:]]"));
12225ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[PAT+2:]]"));
12235ffd940aSRaphael Isemann 
12245ffd940aSRaphael Isemann   // Collision with numeric variable.
12255ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[FOO:]]"));
12265ffd940aSRaphael Isemann 
1227058455ffSThomas Preud'homme   // Invalid use of string variable.
1228058455ffSThomas Preud'homme   EXPECT_TRUE(Tester.parsePattern("[[FOO-BAR]]"));
1229058455ffSThomas Preud'homme 
12305ffd940aSRaphael Isemann   // Valid use of string variable.
12315ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[BAR]]"));
12325ffd940aSRaphael Isemann 
12335ffd940aSRaphael Isemann   // Valid string variable definition.
12345ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[PAT:[0-9]+]]"));
12355ffd940aSRaphael Isemann 
12365ffd940aSRaphael Isemann   // Invalid numeric substitution.
12375ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[#42INVALID]]"));
12385ffd940aSRaphael Isemann 
12395ffd940aSRaphael Isemann   // Valid numeric substitution.
12405ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[#FOO]]"));
12415ffd940aSRaphael Isemann 
12425ffd940aSRaphael Isemann   // Valid legacy @LINE expression.
12435ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[@LINE+2]]"));
12445ffd940aSRaphael Isemann 
12455ffd940aSRaphael Isemann   // Invalid legacy @LINE expression with non decimal literal.
12465ffd940aSRaphael Isemann   EXPECT_TRUE(Tester.parsePattern("[[@LINE+0x3]]"));
12475ffd940aSRaphael Isemann }
12485ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,Match)12495ffd940aSRaphael Isemann TEST_F(FileCheckTest, Match) {
12505ffd940aSRaphael Isemann   PatternTester Tester;
12515ffd940aSRaphael Isemann 
12525ffd940aSRaphael Isemann   // Check a substitution error is diagnosed.
12535ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#%u, -1]]"));
12545ffd940aSRaphael Isemann   expectDiagnosticError(
12555ffd940aSRaphael Isemann       "unable to substitute variable or numeric expression: overflow error",
12565ffd940aSRaphael Isemann       Tester.match("").takeError());
12575ffd940aSRaphael Isemann 
12585ffd940aSRaphael Isemann   // Check matching an empty expression only matches a number.
12595ffd940aSRaphael Isemann   Tester.initNextPattern();
12605ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#]]"));
12615ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("FAIL").takeError());
12625ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
12635ffd940aSRaphael Isemann 
12645ffd940aSRaphael Isemann   // Check matching a definition only matches a number with the right format.
12655ffd940aSRaphael Isemann   Tester.initNextPattern();
12665ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR:]]"));
12675ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("FAIL").takeError());
12685ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("").takeError());
12695ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
12705ffd940aSRaphael Isemann   Tester.initNextPattern();
12715ffd940aSRaphael Isemann   Tester.parsePattern("[[#%u,NUMVAR_UNSIGNED:]]");
12725ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("C").takeError());
12735ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
12745ffd940aSRaphael Isemann   Tester.initNextPattern();
12755ffd940aSRaphael Isemann   Tester.parsePattern("[[#%x,NUMVAR_LOWER_HEX:]]");
12765ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("g").takeError());
12775ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("C").takeError());
12785ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("c"), Succeeded());
12795ffd940aSRaphael Isemann   Tester.initNextPattern();
12805ffd940aSRaphael Isemann   Tester.parsePattern("[[#%X,NUMVAR_UPPER_HEX:]]");
12815ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("H").takeError());
12825ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("b").takeError());
12835ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("B"), Succeeded());
12845ffd940aSRaphael Isemann 
12855ffd940aSRaphael Isemann   // Check matching expressions with no explicit format matches the values in
12865ffd940aSRaphael Isemann   // the right format.
12875ffd940aSRaphael Isemann   Tester.initNextPattern();
12885ffd940aSRaphael Isemann   Tester.parsePattern("[[#NUMVAR_UNSIGNED-5]]");
12895ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("f").takeError());
12905ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("F").takeError());
12915ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("15"), Succeeded());
12925ffd940aSRaphael Isemann   Tester.initNextPattern();
12935ffd940aSRaphael Isemann   Tester.parsePattern("[[#NUMVAR_LOWER_HEX+1]]");
12945ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("13").takeError());
12955ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("D").takeError());
12965ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("d"), Succeeded());
12975ffd940aSRaphael Isemann   Tester.initNextPattern();
12985ffd940aSRaphael Isemann   Tester.parsePattern("[[#NUMVAR_UPPER_HEX+1]]");
12995ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("12").takeError());
13005ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("c").takeError());
13015ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("C"), Succeeded());
13025ffd940aSRaphael Isemann 
13035ffd940aSRaphael Isemann   // Check matching an undefined variable returns a NotFound error.
13045ffd940aSRaphael Isemann   Tester.initNextPattern();
13055ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("100"));
13065ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("101").takeError());
13075ffd940aSRaphael Isemann 
13085ffd940aSRaphael Isemann   // Check matching the defined variable matches the correct number only.
13095ffd940aSRaphael Isemann   Tester.initNextPattern();
13105ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR]]"));
13115ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
13125ffd940aSRaphael Isemann 
13135ffd940aSRaphael Isemann   // Check matching several substitutions does not match them independently.
13145ffd940aSRaphael Isemann   Tester.initNextPattern();
13155ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR]] [[#NUMVAR+2]]"));
13165ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("19 21").takeError());
13175ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("18 21").takeError());
13185ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18 20"), Succeeded());
13195ffd940aSRaphael Isemann 
13205ffd940aSRaphael Isemann   // Check matching a numeric expression using @LINE after a match failure uses
13215ffd940aSRaphael Isemann   // the correct value for @LINE.
13225ffd940aSRaphael Isemann   Tester.initNextPattern();
13235ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#@LINE]]"));
13245ffd940aSRaphael Isemann   // Ok, @LINE matches the current line number.
13255ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match(std::to_string(Tester.getLineNumber())),
13265ffd940aSRaphael Isemann                        Succeeded());
13275ffd940aSRaphael Isemann   Tester.initNextPattern();
13285ffd940aSRaphael Isemann   // Match with substitution failure.
1329fd941036SThomas Preud'homme   ASSERT_FALSE(Tester.parsePattern("[[#UNKNOWN1+UNKNOWN2]]"));
1330fd941036SThomas Preud'homme   expectSameErrors<ErrorDiagnostic>(
1331fd941036SThomas Preud'homme       {"undefined variable: UNKNOWN1", "undefined variable: UNKNOWN2"},
1332fd941036SThomas Preud'homme       Tester.match("FOO").takeError());
13335ffd940aSRaphael Isemann   Tester.initNextPattern();
13345ffd940aSRaphael Isemann   // Check that @LINE matches the later (given the calls to initNextPattern())
13355ffd940aSRaphael Isemann   // line number.
13365ffd940aSRaphael Isemann   EXPECT_FALSE(Tester.parsePattern("[[#@LINE]]"));
13375ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match(std::to_string(Tester.getLineNumber())),
13385ffd940aSRaphael Isemann                        Succeeded());
13395ffd940aSRaphael Isemann }
13405ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,MatchParen)13415ffd940aSRaphael Isemann TEST_F(FileCheckTest, MatchParen) {
13425ffd940aSRaphael Isemann   PatternTester Tester;
13435ffd940aSRaphael Isemann   // Check simple parenthesized expressions
13445ffd940aSRaphael Isemann   Tester.initNextPattern();
13455ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR:]]"));
13465ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("FAIL").takeError());
13475ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("").takeError());
13485ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
13495ffd940aSRaphael Isemann 
13505ffd940aSRaphael Isemann   Tester.initNextPattern();
13515ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR + (2 + 2)]]"));
13525ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("21").takeError());
13535ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("22"), Succeeded());
13545ffd940aSRaphael Isemann   Tester.initNextPattern();
13555ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR + (2)]]"));
13565ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
13575ffd940aSRaphael Isemann   Tester.initNextPattern();
13585ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(2)]]"));
13595ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
13605ffd940aSRaphael Isemann   Tester.initNextPattern();
13615ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(NUMVAR)]]"));
13625ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("36"), Succeeded());
13635ffd940aSRaphael Isemann 
13645ffd940aSRaphael Isemann   // Check nested parenthesized expressions:
13655ffd940aSRaphael Isemann   Tester.initNextPattern();
13665ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(2+(2))]]"));
13675ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("22"), Succeeded());
13685ffd940aSRaphael Isemann   Tester.initNextPattern();
13695ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+(2+(NUMVAR))]]"));
13705ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("38"), Succeeded());
13715ffd940aSRaphael Isemann   Tester.initNextPattern();
13725ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+((((NUMVAR))))]]"));
13735ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("36"), Succeeded());
13745ffd940aSRaphael Isemann   Tester.initNextPattern();
13755ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR+((((NUMVAR)))-1)-1]]"));
13765ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("34"), Succeeded());
13775ffd940aSRaphael Isemann 
13785ffd940aSRaphael Isemann   // Parentheses can also be the first character after the '#':
13795ffd940aSRaphael Isemann   Tester.initNextPattern();
13805ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#(NUMVAR)]]"));
13815ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
13825ffd940aSRaphael Isemann   Tester.initNextPattern();
13835ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#(NUMVAR+2)]]"));
13845ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("20"), Succeeded());
13855ffd940aSRaphael Isemann }
13865ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,MatchBuiltinFunctions)13875ffd940aSRaphael Isemann TEST_F(FileCheckTest, MatchBuiltinFunctions) {
13885ffd940aSRaphael Isemann   PatternTester Tester;
13895ffd940aSRaphael Isemann   // Esnure #NUMVAR has the expected value.
13905ffd940aSRaphael Isemann   Tester.initNextPattern();
13915ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#NUMVAR:]]"));
13925ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("FAIL").takeError());
13935ffd940aSRaphael Isemann   expectNotFoundError(Tester.match("").takeError());
13945ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
13955ffd940aSRaphael Isemann 
13965ffd940aSRaphael Isemann   // Check each builtin function generates the expected result.
13975ffd940aSRaphael Isemann   Tester.initNextPattern();
13985ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#add(NUMVAR,13)]]"));
13995ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("31"), Succeeded());
14005ffd940aSRaphael Isemann   Tester.initNextPattern();
14015ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#div(NUMVAR,3)]]"));
14025ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("6"), Succeeded());
14035ffd940aSRaphael Isemann   Tester.initNextPattern();
14045ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#max(NUMVAR,5)]]"));
14055ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
14065ffd940aSRaphael Isemann   Tester.initNextPattern();
14075ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#max(NUMVAR,99)]]"));
14085ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("99"), Succeeded());
14095ffd940aSRaphael Isemann   Tester.initNextPattern();
14105ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#min(NUMVAR,5)]]"));
14115ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("5"), Succeeded());
14125ffd940aSRaphael Isemann   Tester.initNextPattern();
14135ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#min(NUMVAR,99)]]"));
14145ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
14155ffd940aSRaphael Isemann   Tester.initNextPattern();
14165ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#mul(NUMVAR,3)]]"));
14175ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("54"), Succeeded());
14185ffd940aSRaphael Isemann   Tester.initNextPattern();
14195ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#sub(NUMVAR,7)]]"));
14205ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("11"), Succeeded());
14215ffd940aSRaphael Isemann 
14225ffd940aSRaphael Isemann   // Check nested function calls.
14235ffd940aSRaphael Isemann   Tester.initNextPattern();
14245ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#add(min(7,2),max(4,10))]]"));
14255ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("12"), Succeeded());
14265ffd940aSRaphael Isemann 
14275ffd940aSRaphael Isemann   // Check function call that uses a variable of the same name.
14285ffd940aSRaphael Isemann   Tester.initNextPattern();
14295ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[#add(add,add)+min (add,3)+add]]"));
14305ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("24"), Succeeded());
14315ffd940aSRaphael Isemann }
14325ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,Substitution)14335ffd940aSRaphael Isemann TEST_F(FileCheckTest, Substitution) {
14345ffd940aSRaphael Isemann   SourceMgr SM;
14355ffd940aSRaphael Isemann   FileCheckPatternContext Context;
14365ffd940aSRaphael Isemann   EXPECT_THAT_ERROR(Context.defineCmdlineVariables({"FOO=BAR"}, SM),
14375ffd940aSRaphael Isemann                     Succeeded());
14385ffd940aSRaphael Isemann 
14395ffd940aSRaphael Isemann   // Substitution of an undefined string variable fails and error holds that
14405ffd940aSRaphael Isemann   // variable's name.
14415ffd940aSRaphael Isemann   StringSubstitution StringSubstitution(&Context, "VAR404", 42);
14425ffd940aSRaphael Isemann   Expected<std::string> SubstValue = StringSubstitution.getResult();
14435ffd940aSRaphael Isemann   expectUndefErrors({"VAR404"}, SubstValue.takeError());
14445ffd940aSRaphael Isemann 
14455ffd940aSRaphael Isemann   // Numeric substitution blocks constituted of defined numeric variables are
14465ffd940aSRaphael Isemann   // substituted for the variable's value.
14475ffd940aSRaphael Isemann   NumericVariable NVar("N", ExpressionFormat(ExpressionFormat::Kind::Unsigned),
14485ffd940aSRaphael Isemann                        1);
1449e15e969aSThomas Preud'homme   NVar.setValue(APInt(64, 10u));
14505ffd940aSRaphael Isemann   auto NVarUse = std::make_unique<NumericVariableUse>("N", &NVar);
14515ffd940aSRaphael Isemann   auto ExpressionN = std::make_unique<Expression>(
14525ffd940aSRaphael Isemann       std::move(NVarUse), ExpressionFormat(ExpressionFormat::Kind::HexUpper));
14535ffd940aSRaphael Isemann   NumericSubstitution SubstitutionN(&Context, "N", std::move(ExpressionN),
14545ffd940aSRaphael Isemann                                     /*InsertIdx=*/30);
14555ffd940aSRaphael Isemann   SubstValue = SubstitutionN.getResult();
14565ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(SubstValue, Succeeded());
14575ffd940aSRaphael Isemann   EXPECT_EQ("A", *SubstValue);
14585ffd940aSRaphael Isemann 
14595ffd940aSRaphael Isemann   // Substitution of an undefined numeric variable fails, error holds name of
14605ffd940aSRaphael Isemann   // undefined variable.
14615ffd940aSRaphael Isemann   NVar.clearValue();
14625ffd940aSRaphael Isemann   SubstValue = SubstitutionN.getResult();
14635ffd940aSRaphael Isemann   expectUndefErrors({"N"}, SubstValue.takeError());
14645ffd940aSRaphael Isemann 
14655ffd940aSRaphael Isemann   // Substitution of a defined string variable returns the right value.
14665ffd940aSRaphael Isemann   Pattern P(Check::CheckPlain, &Context, 1);
14675ffd940aSRaphael Isemann   StringSubstitution = llvm::StringSubstitution(&Context, "FOO", 42);
14685ffd940aSRaphael Isemann   SubstValue = StringSubstitution.getResult();
14695ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(SubstValue, Succeeded());
14705ffd940aSRaphael Isemann   EXPECT_EQ("BAR", *SubstValue);
14715ffd940aSRaphael Isemann }
14725ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,FileCheckContext)14735ffd940aSRaphael Isemann TEST_F(FileCheckTest, FileCheckContext) {
14745ffd940aSRaphael Isemann   FileCheckPatternContext Cxt;
14755ffd940aSRaphael Isemann   SourceMgr SM;
14765ffd940aSRaphael Isemann 
14775ffd940aSRaphael Isemann   // No definition.
14785ffd940aSRaphael Isemann   EXPECT_THAT_ERROR(Cxt.defineCmdlineVariables({}, SM), Succeeded());
14795ffd940aSRaphael Isemann 
14805ffd940aSRaphael Isemann   // Missing equal sign.
14815ffd940aSRaphael Isemann   expectDiagnosticError("missing equal sign in global definition",
14825ffd940aSRaphael Isemann                         Cxt.defineCmdlineVariables({"LocalVar"}, SM));
14835ffd940aSRaphael Isemann   expectDiagnosticError("missing equal sign in global definition",
14845ffd940aSRaphael Isemann                         Cxt.defineCmdlineVariables({"#LocalNumVar"}, SM));
14855ffd940aSRaphael Isemann 
14865ffd940aSRaphael Isemann   // Empty variable name.
14875ffd940aSRaphael Isemann   expectDiagnosticError("empty variable name",
14885ffd940aSRaphael Isemann                         Cxt.defineCmdlineVariables({"=18"}, SM));
14895ffd940aSRaphael Isemann   expectDiagnosticError("empty variable name",
14905ffd940aSRaphael Isemann                         Cxt.defineCmdlineVariables({"#=18"}, SM));
14915ffd940aSRaphael Isemann 
14925ffd940aSRaphael Isemann   // Invalid variable name.
14935ffd940aSRaphael Isemann   expectDiagnosticError("invalid variable name",
14945ffd940aSRaphael Isemann                         Cxt.defineCmdlineVariables({"18LocalVar=18"}, SM));
14955ffd940aSRaphael Isemann   expectDiagnosticError("invalid variable name",
14965ffd940aSRaphael Isemann                         Cxt.defineCmdlineVariables({"#18LocalNumVar=18"}, SM));
14975ffd940aSRaphael Isemann 
14985ffd940aSRaphael Isemann   // Name conflict between pattern and numeric variable.
14995ffd940aSRaphael Isemann   expectDiagnosticError(
15005ffd940aSRaphael Isemann       "string variable with name 'LocalVar' already exists",
15015ffd940aSRaphael Isemann       Cxt.defineCmdlineVariables({"LocalVar=18", "#LocalVar=36"}, SM));
15025ffd940aSRaphael Isemann   Cxt = FileCheckPatternContext();
15035ffd940aSRaphael Isemann   expectDiagnosticError(
15045ffd940aSRaphael Isemann       "numeric variable with name 'LocalNumVar' already exists",
15055ffd940aSRaphael Isemann       Cxt.defineCmdlineVariables({"#LocalNumVar=18", "LocalNumVar=36"}, SM));
15065ffd940aSRaphael Isemann   Cxt = FileCheckPatternContext();
15075ffd940aSRaphael Isemann 
15085ffd940aSRaphael Isemann   // Invalid numeric value for numeric variable.
15095ffd940aSRaphael Isemann   expectUndefErrors({"x"}, Cxt.defineCmdlineVariables({"#LocalNumVar=x"}, SM));
15105ffd940aSRaphael Isemann 
15115ffd940aSRaphael Isemann   // Define local variables from command-line.
15125ffd940aSRaphael Isemann   std::vector<StringRef> GlobalDefines;
15135ffd940aSRaphael Isemann   // Clear local variables to remove dummy numeric variable x that
15145ffd940aSRaphael Isemann   // parseNumericSubstitutionBlock would have created and stored in
15155ffd940aSRaphael Isemann   // GlobalNumericVariableTable.
15165ffd940aSRaphael Isemann   Cxt.clearLocalVars();
15175ffd940aSRaphael Isemann   GlobalDefines.emplace_back("LocalVar=FOO");
15185ffd940aSRaphael Isemann   GlobalDefines.emplace_back("EmptyVar=");
15195ffd940aSRaphael Isemann   GlobalDefines.emplace_back("#LocalNumVar1=18");
15205ffd940aSRaphael Isemann   GlobalDefines.emplace_back("#%x,LocalNumVar2=LocalNumVar1+2");
15215ffd940aSRaphael Isemann   GlobalDefines.emplace_back("#LocalNumVar3=0xc");
15225ffd940aSRaphael Isemann   ASSERT_THAT_ERROR(Cxt.defineCmdlineVariables(GlobalDefines, SM), Succeeded());
15235ffd940aSRaphael Isemann 
15245ffd940aSRaphael Isemann   // Create @LINE pseudo numeric variable and check it is present by matching
15255ffd940aSRaphael Isemann   // it.
15265ffd940aSRaphael Isemann   size_t LineNumber = 1;
15275ffd940aSRaphael Isemann   Pattern P(Check::CheckPlain, &Cxt, LineNumber);
15285ffd940aSRaphael Isemann   FileCheckRequest Req;
15295ffd940aSRaphael Isemann   Cxt.createLineVariable();
15305ffd940aSRaphael Isemann   ASSERT_FALSE(P.parsePattern("[[@LINE]]", "CHECK", SM, Req));
1531dd59c132SJoel E. Denny   Pattern::MatchResult Res = P.match("1", SM);
1532dd59c132SJoel E. Denny   ASSERT_THAT_ERROR(std::move(Res.TheError), Succeeded());
15335ffd940aSRaphael Isemann 
15345ffd940aSRaphael Isemann #ifndef NDEBUG
15355ffd940aSRaphael Isemann   // Recreating @LINE pseudo numeric variable fails.
15365ffd940aSRaphael Isemann   EXPECT_DEATH(Cxt.createLineVariable(),
15375ffd940aSRaphael Isemann                "@LINE pseudo numeric variable already created");
15385ffd940aSRaphael Isemann #endif
15395ffd940aSRaphael Isemann 
15405ffd940aSRaphael Isemann   // Check defined variables are present and undefined ones are absent.
15415ffd940aSRaphael Isemann   StringRef LocalVarStr = "LocalVar";
15425ffd940aSRaphael Isemann   StringRef LocalNumVar1Ref = bufferize(SM, "LocalNumVar1");
15435ffd940aSRaphael Isemann   StringRef LocalNumVar2Ref = bufferize(SM, "LocalNumVar2");
15445ffd940aSRaphael Isemann   StringRef LocalNumVar3Ref = bufferize(SM, "LocalNumVar3");
15455ffd940aSRaphael Isemann   StringRef EmptyVarStr = "EmptyVar";
15465ffd940aSRaphael Isemann   StringRef UnknownVarStr = "UnknownVar";
15475ffd940aSRaphael Isemann   Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
15485ffd940aSRaphael Isemann   P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
154994081642SFangrui Song   std::optional<NumericVariable *> DefinedNumericVariable;
15505ffd940aSRaphael Isemann   Expected<std::unique_ptr<Expression>> ExpressionPointer =
15515ffd940aSRaphael Isemann       P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable,
15525ffd940aSRaphael Isemann                                       /*IsLegacyLineExpr=*/false, LineNumber,
15535ffd940aSRaphael Isemann                                       &Cxt, SM);
15545ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(LocalVar, Succeeded());
15555ffd940aSRaphael Isemann   EXPECT_EQ(*LocalVar, "FOO");
15565ffd940aSRaphael Isemann   Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
15575ffd940aSRaphael Isemann   Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
15585ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
1559e15e969aSThomas Preud'homme   Expected<APInt> ExpressionVal = (*ExpressionPointer)->getAST()->eval();
15605ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
1561e15e969aSThomas Preud'homme   EXPECT_EQ(ExpressionVal->getSExtValue(), 18);
15625ffd940aSRaphael Isemann   ExpressionPointer = P.parseNumericSubstitutionBlock(
15635ffd940aSRaphael Isemann       LocalNumVar2Ref, DefinedNumericVariable,
15645ffd940aSRaphael Isemann       /*IsLegacyLineExpr=*/false, LineNumber, &Cxt, SM);
15655ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
15665ffd940aSRaphael Isemann   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
15675ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
1568e15e969aSThomas Preud'homme   EXPECT_EQ(ExpressionVal->getSExtValue(), 20);
15695ffd940aSRaphael Isemann   ExpressionPointer = P.parseNumericSubstitutionBlock(
15705ffd940aSRaphael Isemann       LocalNumVar3Ref, DefinedNumericVariable,
15715ffd940aSRaphael Isemann       /*IsLegacyLineExpr=*/false, LineNumber, &Cxt, SM);
15725ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
15735ffd940aSRaphael Isemann   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
15745ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
1575e15e969aSThomas Preud'homme   EXPECT_EQ(ExpressionVal->getSExtValue(), 12);
15765ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(EmptyVar, Succeeded());
15775ffd940aSRaphael Isemann   EXPECT_EQ(*EmptyVar, "");
15785ffd940aSRaphael Isemann   expectUndefErrors({std::string(UnknownVarStr)}, UnknownVar.takeError());
15795ffd940aSRaphael Isemann 
15805ffd940aSRaphael Isemann   // Clear local variables and check they become absent.
15815ffd940aSRaphael Isemann   Cxt.clearLocalVars();
15825ffd940aSRaphael Isemann   LocalVar = Cxt.getPatternVarValue(LocalVarStr);
15835ffd940aSRaphael Isemann   expectUndefErrors({std::string(LocalVarStr)}, LocalVar.takeError());
15845ffd940aSRaphael Isemann   // Check a numeric expression's evaluation fails if called after clearing of
15855ffd940aSRaphael Isemann   // local variables, if it was created before. This is important because local
15865ffd940aSRaphael Isemann   // variable clearing due to --enable-var-scope happens after numeric
15875ffd940aSRaphael Isemann   // expressions are linked to the numeric variables they use.
15885ffd940aSRaphael Isemann   expectUndefErrors({"LocalNumVar3"},
15895ffd940aSRaphael Isemann                     (*ExpressionPointer)->getAST()->eval().takeError());
15905ffd940aSRaphael Isemann   P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
15915ffd940aSRaphael Isemann   ExpressionPointer = P.parseNumericSubstitutionBlock(
15925ffd940aSRaphael Isemann       LocalNumVar1Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
15935ffd940aSRaphael Isemann       LineNumber, &Cxt, SM);
15945ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
15955ffd940aSRaphael Isemann   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
15965ffd940aSRaphael Isemann   expectUndefErrors({"LocalNumVar1"}, ExpressionVal.takeError());
15975ffd940aSRaphael Isemann   ExpressionPointer = P.parseNumericSubstitutionBlock(
15985ffd940aSRaphael Isemann       LocalNumVar2Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
15995ffd940aSRaphael Isemann       LineNumber, &Cxt, SM);
16005ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
16015ffd940aSRaphael Isemann   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
16025ffd940aSRaphael Isemann   expectUndefErrors({"LocalNumVar2"}, ExpressionVal.takeError());
16035ffd940aSRaphael Isemann   EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
16045ffd940aSRaphael Isemann   expectUndefErrors({"EmptyVar"}, EmptyVar.takeError());
16055ffd940aSRaphael Isemann   // Clear again because parseNumericSubstitutionBlock would have created a
16065ffd940aSRaphael Isemann   // dummy variable and stored it in GlobalNumericVariableTable.
16075ffd940aSRaphael Isemann   Cxt.clearLocalVars();
16085ffd940aSRaphael Isemann 
16095ffd940aSRaphael Isemann   // Redefine global variables and check variables are defined again.
16105ffd940aSRaphael Isemann   GlobalDefines.emplace_back("$GlobalVar=BAR");
16115ffd940aSRaphael Isemann   GlobalDefines.emplace_back("#$GlobalNumVar=36");
16125ffd940aSRaphael Isemann   ASSERT_THAT_ERROR(Cxt.defineCmdlineVariables(GlobalDefines, SM), Succeeded());
16135ffd940aSRaphael Isemann   StringRef GlobalVarStr = "$GlobalVar";
16145ffd940aSRaphael Isemann   StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
16155ffd940aSRaphael Isemann   Expected<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
16165ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(GlobalVar, Succeeded());
16175ffd940aSRaphael Isemann   EXPECT_EQ(*GlobalVar, "BAR");
16185ffd940aSRaphael Isemann   P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
16195ffd940aSRaphael Isemann   ExpressionPointer = P.parseNumericSubstitutionBlock(
16205ffd940aSRaphael Isemann       GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
16215ffd940aSRaphael Isemann       LineNumber, &Cxt, SM);
16225ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
16235ffd940aSRaphael Isemann   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
16245ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
1625e15e969aSThomas Preud'homme   EXPECT_EQ(ExpressionVal->getSExtValue(), 36);
16265ffd940aSRaphael Isemann 
16275ffd940aSRaphael Isemann   // Clear local variables and check global variables remain defined.
16285ffd940aSRaphael Isemann   Cxt.clearLocalVars();
16295ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Cxt.getPatternVarValue(GlobalVarStr), Succeeded());
16305ffd940aSRaphael Isemann   P = Pattern(Check::CheckPlain, &Cxt, ++LineNumber);
16315ffd940aSRaphael Isemann   ExpressionPointer = P.parseNumericSubstitutionBlock(
16325ffd940aSRaphael Isemann       GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
16335ffd940aSRaphael Isemann       LineNumber, &Cxt, SM);
16345ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
16355ffd940aSRaphael Isemann   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
16365ffd940aSRaphael Isemann   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
1637e15e969aSThomas Preud'homme   EXPECT_EQ(ExpressionVal->getSExtValue(), 36);
16385ffd940aSRaphael Isemann }
16395ffd940aSRaphael Isemann 
TEST_F(FileCheckTest,CapturedVarDiags)16405ffd940aSRaphael Isemann TEST_F(FileCheckTest, CapturedVarDiags) {
16415ffd940aSRaphael Isemann   PatternTester Tester;
16425ffd940aSRaphael Isemann   ASSERT_FALSE(Tester.parsePattern("[[STRVAR:[a-z]+]] [[#NUMVAR:@LINE]]"));
16435ffd940aSRaphael Isemann   EXPECT_THAT_EXPECTED(Tester.match("foobar 2"), Succeeded());
16445ffd940aSRaphael Isemann   std::vector<FileCheckDiag> Diags;
16455ffd940aSRaphael Isemann   Tester.printVariableDefs(FileCheckDiag::MatchFoundAndExpected, Diags);
16465ffd940aSRaphael Isemann   EXPECT_EQ(Diags.size(), 2ul);
164740dc8e68SGregory Alfonso   for (const FileCheckDiag &Diag : Diags) {
16485ffd940aSRaphael Isemann     EXPECT_EQ(Diag.CheckTy, Check::CheckPlain);
16495ffd940aSRaphael Isemann     EXPECT_EQ(Diag.MatchTy, FileCheckDiag::MatchFoundAndExpected);
16505ffd940aSRaphael Isemann     EXPECT_EQ(Diag.InputStartLine, 1u);
16515ffd940aSRaphael Isemann     EXPECT_EQ(Diag.InputEndLine, 1u);
16525ffd940aSRaphael Isemann   }
16535ffd940aSRaphael Isemann   EXPECT_EQ(Diags[0].InputStartCol, 1u);
16545ffd940aSRaphael Isemann   EXPECT_EQ(Diags[0].InputEndCol, 7u);
16555ffd940aSRaphael Isemann   EXPECT_EQ(Diags[1].InputStartCol, 8u);
16565ffd940aSRaphael Isemann   EXPECT_EQ(Diags[1].InputEndCol, 9u);
16575ffd940aSRaphael Isemann   EXPECT_EQ(Diags[0].Note, "captured var \"STRVAR\"");
16585ffd940aSRaphael Isemann   EXPECT_EQ(Diags[1].Note, "captured var \"NUMVAR\"");
16595ffd940aSRaphael Isemann }
16605ffd940aSRaphael Isemann } // namespace
1661