llvm.org GIT mirror llvm / 7fb4d76
FileCheck [1/12]: Move variable table in new object Summary: This patch is part of a patch series to add support for FileCheck numeric expressions. This specific patch adds a new class to hold pattern matching global state. The table holding the values of FileCheck variable constitutes some sort of global state for the matching phase, yet is passed as parameters of all functions using it. This commit create a new FileCheckPatternContext class pointed at from FileCheckPattern. While it increases the line count, it separates local data from global state. Later commits build on that to add numeric expression global state to that class. Copyright: - Linaro (changes up to diff 183612 of revision D55940) - GraphCore (changes in later versions of revision D55940 and in new revision created off D55940) Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield Tags: #llvm Differential Revision: https://reviews.llvm.org/D60381 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358390 91177308-0d34-0410-b5e6-96231b3b80d8 Thomas Preud'homme 6 months ago
4 changed file(s) with 187 addition(s) and 102 deletion(s). Raw diff Collapse all Expand all
7878
7979 std::string getDescription(StringRef Prefix) const;
8080 };
81 }
81 } // namespace Check
8282
8383 struct FileCheckDiag;
84
85 /// Class holding the FileCheckPattern global state, shared by all patterns:
86 /// tables holding values of variables and whether they are defined or not at
87 /// any given time in the matching process.
88 class FileCheckPatternContext {
89 friend class FileCheckPattern;
90
91 private:
92 /// When matching a given pattern, this holds the value of all the FileCheck
93 /// variables defined in previous patterns. In a pattern only the last
94 /// definition for a given variable is recorded in this table, back-references
95 /// are used for uses after any the other definition.
96 StringMap GlobalVariableTable;
97
98 public:
99 /// Return the value of variable \p VarName or None if no such variable has
100 /// been defined.
101 llvm::Optional getVarValue(StringRef VarName);
102
103 /// Define variables from definitions given on the command line passed as a
104 /// vector of VAR=VAL strings in \p CmdlineDefines.
105 void defineCmdlineVariables(std::vector &CmdlineDefines);
106
107 /// Undefine local variables (variables whose name does not start with a '$'
108 /// sign), i.e. remove them from GlobalVariableTable.
109 void clearLocalVars();
110 };
84111
85112 class FileCheckPattern {
86113 SMLoc PatternLoc;
105132 /// 1.
106133 std::map VariableDefs;
107134
135 /// Pointer to the class instance shared by all patterns holding a table with
136 /// the values of live variables at the start of any given CHECK line.
137 FileCheckPatternContext *Context;
138
108139 Check::FileCheckType CheckTy;
109140
110141 /// Contains the number of line this pattern is in.
111142 unsigned LineNumber;
112143
113144 public:
114 explicit FileCheckPattern(Check::FileCheckType Ty)
115 : CheckTy(Ty) {}
145 explicit FileCheckPattern(Check::FileCheckType Ty,
146 FileCheckPatternContext *Context)
147 : Context(Context), CheckTy(Ty) {}
116148
117149 /// Returns the location in source code.
118150 SMLoc getLoc() const { return PatternLoc; }
119151
152 /// Returns the pointer to the global state for all patterns in this
153 /// FileCheck instance.
154 FileCheckPatternContext *getContext() const { return Context; }
120155 bool ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
121156 unsigned LineNumber, const FileCheckRequest &Req);
122 size_t Match(StringRef Buffer, size_t &MatchLen,
123 StringMap &VariableTable) const;
124 void PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
125 const StringMap &VariableTable,
157 size_t match(StringRef Buffer, size_t &MatchLen) const;
158 /// Print value of successful substitutions or name of undefined pattern
159 /// variables preventing such a successful substitution.
160 void printVariableUses(const SourceMgr &SM, StringRef Buffer,
126161 SMRange MatchRange = None) const;
127 void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
128 const StringMap &VariableTable,
162 void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
129163 std::vector *Diags) const;
130164
131165 bool hasVariable() const {
139173 private:
140174 bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
141175 void AddBackrefToRegEx(unsigned BackrefNum);
142 unsigned
143 ComputeMatchDistance(StringRef Buffer,
144 const StringMap &VariableTable) const;
176 unsigned computeMatchDistance(StringRef Buffer) const;
145177 bool EvaluateExpression(StringRef Expr, std::string &Value) const;
146178 size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
147179 };
222254 : Pat(P), Prefix(S), Loc(L) {}
223255
224256 size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
225 size_t &MatchLen, StringMap &VariableTable,
226 FileCheckRequest &Req, std::vector *Diags) const;
257 size_t &MatchLen, FileCheckRequest &Req,
258 std::vector *Diags) const;
227259
228260 bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
229261 bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
230262 bool CheckNot(const SourceMgr &SM, StringRef Buffer,
231263 const std::vector &NotStrings,
232 StringMap &VariableTable,
233264 const FileCheckRequest &Req,
234265 std::vector *Diags) const;
235266 size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
236267 std::vector &NotStrings,
237 StringMap &VariableTable,
238268 const FileCheckRequest &Req,
239269 std::vector *Diags) const;
240270 };
243273 /// use information from the request.
244274 class FileCheck {
245275 FileCheckRequest Req;
276 FileCheckPatternContext PatternContext;
246277
247278 public:
248279 FileCheck(FileCheckRequest Req) : Req(Req) {}
268268 /// there is a match, the size of the matched string is returned in \p
269269 /// MatchLen.
270270 ///
271 /// The \p VariableTable StringMap provides the current values of filecheck
272 /// variables and is updated if this match defines new values.
273 size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen,
274 StringMap &VariableTable) const {
271 /// The GlobalVariableTable StringMap in the FileCheckPatternContext class
272 /// instance provides the current values of FileCheck variables and is updated
273 /// if this match defines new values.
274 size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen) const {
275275 // If this is the EOF pattern, match it immediately.
276276 if (CheckTy == Check::CheckEOF) {
277277 MatchLen = 0;
301301 if (!EvaluateExpression(VariableUse.first, Value))
302302 return StringRef::npos;
303303 } else {
304 StringMap::iterator it =
305 VariableTable.find(VariableUse.first);
304 llvm::Optional ValueRef =
305 Context->getVarValue(VariableUse.first);
306306 // If the variable is undefined, return an error.
307 if (it == VariableTable.end())
307 if (!ValueRef)
308308 return StringRef::npos;
309309
310310 // Look up the value and escape it so that we can put it into the regex.
311 Value += Regex::escape(it->second);
311 Value += Regex::escape(*ValueRef);
312312 }
313313
314314 // Plop it into the regex at the adjusted offset.
332332 // If this defines any variables, remember their values.
333333 for (const auto &VariableDef : VariableDefs) {
334334 assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
335 VariableTable[VariableDef.first] = MatchInfo[VariableDef.second];
335 Context->GlobalVariableTable[VariableDef.first] =
336 MatchInfo[VariableDef.second];
336337 }
337338
338339 // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
343344 return FullMatch.data() - Buffer.data() + MatchStartSkip;
344345 }
345346
346
347347 /// Computes an arbitrary estimate for the quality of matching this pattern at
348348 /// the start of \p Buffer; a distance of zero should correspond to a perfect
349349 /// match.
350 unsigned
351 FileCheckPattern::ComputeMatchDistance(StringRef Buffer,
352 const StringMap &VariableTable) const {
350 unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {
353351 // Just compute the number of matching characters. For regular expressions, we
354352 // just compare against the regex itself and hope for the best.
355353 //
366364 return BufferPrefix.edit_distance(ExampleString);
367365 }
368366
369 void FileCheckPattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
370 const StringMap &VariableTable,
371 SMRange MatchRange) const {
367 void FileCheckPattern::printVariableUses(const SourceMgr &SM, StringRef Buffer,
368 SMRange MatchRange) const {
372369 // If this was a regular expression using variables, print the current
373370 // variable values.
374371 if (!VariableUses.empty()) {
387384 OS.write_escaped(Var) << "\"";
388385 }
389386 } else {
390 StringMap::const_iterator it = VariableTable.find(Var);
387 llvm::Optional VarValue = Context->getVarValue(Var);
391388
392389 // Check for undefined variable references.
393 if (it == VariableTable.end()) {
390 if (!VarValue) {
394391 OS << "uses undefined variable \"";
395392 OS.write_escaped(Var) << "\"";
396393 } else {
397394 OS << "with variable \"";
398395 OS.write_escaped(Var) << "\" equal to \"";
399 OS.write_escaped(it->second) << "\"";
396 OS.write_escaped(*VarValue) << "\"";
400397 }
401398 }
402399
428425 return Range;
429426 }
430427
431 void FileCheckPattern::PrintFuzzyMatch(
428 void FileCheckPattern::printFuzzyMatch(
432429 const SourceMgr &SM, StringRef Buffer,
433 const StringMap &VariableTable,
434430 std::vector *Diags) const {
435431 // Attempt to find the closest/best fuzzy match. Usually an error happens
436432 // because some string in the output didn't exactly match. In these cases, we
452448
453449 // Compute the "quality" of this match as an arbitrary combination of the
454450 // match distance and the number of lines skipped to get to this match.
455 unsigned Distance = ComputeMatchDistance(Buffer.substr(i), VariableTable);
451 unsigned Distance = computeMatchDistance(Buffer.substr(i));
456452 double Quality = Distance + (NumLinesForward / 100.);
457453
458454 if (Quality < BestQuality || Best == StringRef::npos) {
474470 // FIXME: If we wanted to be really friendly we would show why the match
475471 // failed, as it can be hard to spot simple one character differences.
476472 }
473 }
474
475 llvm::Optional
476 FileCheckPatternContext::getVarValue(StringRef VarName) {
477 auto VarIter = GlobalVariableTable.find(VarName);
478 if (VarIter == GlobalVariableTable.end())
479 return llvm::None;
480
481 return VarIter->second;
477482 }
478483
479484 /// Finds the closing sequence of a regex variable usage or definition.
746751 ///
747752 /// The strings are added to the CheckStrings vector. Returns true in case of
748753 /// an error, false otherwise.
749 bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer,
750 Regex &PrefixRE,
751 std::vector &CheckStrings) {
754 bool llvm::FileCheck::ReadCheckFile(
755 SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
756 std::vector &CheckStrings) {
757 PatternContext.defineCmdlineVariables(Req.GlobalDefines);
758
752759 std::vector ImplicitNegativeChecks;
753760 for (const auto &PatternString : Req.ImplicitCheckNot) {
754761 // Create a buffer with fake command line content in order to display the
762769 CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
763770 SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
764771
765 ImplicitNegativeChecks.push_back(FileCheckPattern(Check::CheckNot));
772 ImplicitNegativeChecks.push_back(
773 FileCheckPattern(Check::CheckNot, &PatternContext));
766774 ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer,
767775 "IMPLICIT-CHECK", SM, 0, Req);
768776 }
825833 SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
826834
827835 // Parse the pattern.
828 FileCheckPattern P(CheckTy);
836 FileCheckPattern P(CheckTy, &PatternContext);
829837 if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber, Req))
830838 return true;
831839
869877 // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
870878 // prefix as a filler for the error message.
871879 if (!DagNotMatches.empty()) {
872 CheckStrings.emplace_back(FileCheckPattern(Check::CheckEOF), *Req.CheckPrefixes.begin(),
873 SMLoc::getFromPointer(Buffer.data()));
880 CheckStrings.emplace_back(
881 FileCheckPattern(Check::CheckEOF, &PatternContext),
882 *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
874883 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
875884 }
876885
895904
896905 static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
897906 StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
898 int MatchedCount, StringRef Buffer,
899 StringMap &VariableTable, size_t MatchPos,
907 int MatchedCount, StringRef Buffer, size_t MatchPos,
900908 size_t MatchLen, const FileCheckRequest &Req,
901909 std::vector *Diags) {
902910 bool PrintDiag = true;
928936 Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
929937 SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
930938 {MatchRange});
931 Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange);
939 Pat.printVariableUses(SM, Buffer, MatchRange);
932940 }
933941
934942 static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
935943 const FileCheckString &CheckStr, int MatchedCount,
936 StringRef Buffer, StringMap &VariableTable,
937 size_t MatchPos, size_t MatchLen, FileCheckRequest &Req,
944 StringRef Buffer, size_t MatchPos, size_t MatchLen,
945 FileCheckRequest &Req,
938946 std::vector *Diags) {
939947 PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
940 MatchedCount, Buffer, VariableTable, MatchPos, MatchLen, Req,
941 Diags);
948 MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags);
942949 }
943950
944951 static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
945952 StringRef Prefix, SMLoc Loc,
946953 const FileCheckPattern &Pat, int MatchedCount,
947 StringRef Buffer, StringMap &VariableTable,
948 bool VerboseVerbose,
954 StringRef Buffer, bool VerboseVerbose,
949955 std::vector *Diags) {
950956 bool PrintDiag = true;
951957 if (!ExpectedMatch) {
981987 SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");
982988
983989 // Allow the pattern to print additional information if desired.
984 Pat.PrintVariableUses(SM, Buffer, VariableTable);
990 Pat.printVariableUses(SM, Buffer);
985991
986992 if (ExpectedMatch)
987 Pat.PrintFuzzyMatch(SM, Buffer, VariableTable, Diags);
993 Pat.printFuzzyMatch(SM, Buffer, Diags);
988994 }
989995
990996 static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
991997 const FileCheckString &CheckStr, int MatchedCount,
992 StringRef Buffer, StringMap &VariableTable,
993 bool VerboseVerbose,
998 StringRef Buffer, bool VerboseVerbose,
994999 std::vector *Diags) {
9951000 PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
996 MatchedCount, Buffer, VariableTable, VerboseVerbose, Diags);
1001 MatchedCount, Buffer, VerboseVerbose, Diags);
9971002 }
9981003
9991004 /// Count the number of newlines in the specified range.
10221027 /// Match check string and its "not strings" and/or "dag strings".
10231028 size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
10241029 bool IsLabelScanMode, size_t &MatchLen,
1025 StringMap &VariableTable,
10261030 FileCheckRequest &Req,
10271031 std::vector *Diags) const {
10281032 size_t LastPos = 0;
10341038 // over the block again (including the last CHECK-LABEL) in normal mode.
10351039 if (!IsLabelScanMode) {
10361040 // Match "dag strings" (with mixed "not strings" if any).
1037 LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable, Req, Diags);
1041 LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);
10381042 if (LastPos == StringRef::npos)
10391043 return StringRef::npos;
10401044 }
10491053 StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
10501054 size_t CurrentMatchLen;
10511055 // get a match at current start point
1052 size_t MatchPos = Pat.Match(MatchBuffer, CurrentMatchLen, VariableTable);
1056 size_t MatchPos = Pat.match(MatchBuffer, CurrentMatchLen);
10531057 if (i == 1)
10541058 FirstMatchPos = LastPos + MatchPos;
10551059
10561060 // report
10571061 if (MatchPos == StringRef::npos) {
1058 PrintNoMatch(true, SM, *this, i, MatchBuffer, VariableTable,
1059 Req.VerboseVerbose, Diags);
1062 PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags);
10601063 return StringRef::npos;
10611064 }
1062 PrintMatch(true, SM, *this, i, MatchBuffer, VariableTable, MatchPos,
1063 CurrentMatchLen, Req, Diags);
1065 PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
1066 Diags);
10641067
10651068 // move start point after the match
10661069 LastMatchEnd += MatchPos + CurrentMatchLen;
10951098
10961099 // If this match had "not strings", verify that they don't exist in the
10971100 // skipped region.
1098 if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags))
1101 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
10991102 return StringRef::npos;
11001103 }
11011104
11691172 bool FileCheckString::CheckNot(
11701173 const SourceMgr &SM, StringRef Buffer,
11711174 const std::vector &NotStrings,
1172 StringMap &VariableTable, const FileCheckRequest &Req,
1173 std::vector *Diags) const {
1175 const FileCheckRequest &Req, std::vector *Diags) const {
11741176 for (const FileCheckPattern *Pat : NotStrings) {
11751177 assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
11761178
11771179 size_t MatchLen = 0;
1178 size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
1180 size_t Pos = Pat->match(Buffer, MatchLen);
11791181
11801182 if (Pos == StringRef::npos) {
11811183 PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
1182 VariableTable, Req.VerboseVerbose, Diags);
1184 Req.VerboseVerbose, Diags);
11831185 continue;
11841186 }
11851187
1186 PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, VariableTable,
1187 Pos, MatchLen, Req, Diags);
1188 PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,
1189 Req, Diags);
11881190
11891191 return true;
11901192 }
11961198 size_t
11971199 FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
11981200 std::vector &NotStrings,
1199 StringMap &VariableTable,
12001201 const FileCheckRequest &Req,
12011202 std::vector *Diags) const {
12021203 if (DagNotStrings.empty())
12371238 // CHECK-DAG group.
12381239 for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
12391240 StringRef MatchBuffer = Buffer.substr(MatchPos);
1240 size_t MatchPosBuf = Pat.Match(MatchBuffer, MatchLen, VariableTable);
1241 size_t MatchPosBuf = Pat.match(MatchBuffer, MatchLen);
12411242 // With a group of CHECK-DAGs, a single mismatching means the match on
12421243 // that group of CHECK-DAGs fails immediately.
12431244 if (MatchPosBuf == StringRef::npos) {
12441245 PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
1245 VariableTable, Req.VerboseVerbose, Diags);
1246 Req.VerboseVerbose, Diags);
12461247 return StringRef::npos;
12471248 }
12481249 // Re-calc it as the offset relative to the start of the original string.
12491250 MatchPos += MatchPosBuf;
12501251 if (Req.VerboseVerbose)
1251 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
1252 VariableTable, MatchPos, MatchLen, Req, Diags);
1252 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
1253 MatchLen, Req, Diags);
12531254 MatchRange M{MatchPos, MatchPos + MatchLen};
12541255 if (Req.AllowDeprecatedDagOverlap) {
12551256 // We don't need to track all matches in this mode, so we just maintain
12961297 MatchPos = MI->End;
12971298 }
12981299 if (!Req.VerboseVerbose)
1299 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, VariableTable,
1300 MatchPos, MatchLen, Req, Diags);
1300 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
1301 MatchLen, Req, Diags);
13011302
13021303 // Handle the end of a CHECK-DAG group.
13031304 if (std::next(PatItr) == PatEnd ||
13081309 // region.
13091310 StringRef SkippedRegion =
13101311 Buffer.slice(StartPos, MatchRanges.begin()->Pos);
1311 if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags))
1312 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
13121313 return StringRef::npos;
13131314 // Clear "not strings".
13141315 NotStrings.clear();
13721373 return Regex(PrefixRegexStr);
13731374 }
13741375
1375 // Remove local variables from \p VariableTable. Global variables
1376 // (start with '$') are preserved.
1377 static void ClearLocalVars(StringMap &VariableTable) {
1378 SmallVector LocalVars;
1379 for (const auto &Var : VariableTable)
1376 void FileCheckPatternContext::defineCmdlineVariables(
1377 std::vector &CmdlineDefines) {
1378 assert(GlobalVariableTable.empty() &&
1379 "Overriding defined variable with command-line variable definitions");
1380 for (StringRef CmdlineDef : CmdlineDefines)
1381 GlobalVariableTable.insert(CmdlineDef.split('='));
1382 }
1383
1384 void FileCheckPatternContext::clearLocalVars() {
1385 SmallVector LocalPatternVars, LocalNumericVars;
1386 for (const StringMapEntry &Var : GlobalVariableTable)
13801387 if (Var.first()[0] != '$')
1381 LocalVars.push_back(Var.first());
1382
1383 for (const auto &Var : LocalVars)
1384 VariableTable.erase(Var);
1388 LocalPatternVars.push_back(Var.first());
1389
1390 for (const auto &Var : LocalPatternVars)
1391 GlobalVariableTable.erase(Var);
13851392 }
13861393
13871394 /// Check the input to FileCheck provided in the \p Buffer against the \p
13921399 ArrayRef CheckStrings,
13931400 std::vector *Diags) {
13941401 bool ChecksFailed = false;
1395
1396 /// VariableTable - This holds all the current filecheck variables.
1397 StringMap VariableTable;
1398
1399 for (const auto& Def : Req.GlobalDefines)
1400 VariableTable.insert(StringRef(Def).split('='));
14011402
14021403 unsigned i = 0, j = 0, e = CheckStrings.size();
14031404 while (true) {
14131414
14141415 // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
14151416 size_t MatchLabelLen = 0;
1416 size_t MatchLabelPos = CheckLabelStr.Check(
1417 SM, Buffer, true, MatchLabelLen, VariableTable, Req, Diags);
1417 size_t MatchLabelPos =
1418 CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);
14181419 if (MatchLabelPos == StringRef::npos)
1419 // Immediately bail of CHECK-LABEL fails, nothing else we can do.
1420 // Immediately bail if CHECK-LABEL fails, nothing else we can do.
14201421 return false;
14211422
14221423 CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
14251426 }
14261427
14271428 if (Req.EnableVarScope)
1428 ClearLocalVars(VariableTable);
1429 PatternContext.clearLocalVars();
14291430
14301431 for (; i != j; ++i) {
14311432 const FileCheckString &CheckStr = CheckStrings[i];
14331434 // Check each string within the scanned region, including a second check
14341435 // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
14351436 size_t MatchLen = 0;
1436 size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen,
1437 VariableTable, Req, Diags);
1437 size_t MatchPos =
1438 CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);
14381439
14391440 if (MatchPos == StringRef::npos) {
14401441 ChecksFailed = true;
2727 ErrnoTest.cpp
2828 ErrorOrTest.cpp
2929 ErrorTest.cpp
30 FileCheckTest.cpp
3031 FileOutputBufferTest.cpp
3132 FormatVariadicTest.cpp
3233 GlobPatternTest.cpp
0 //===- llvm/unittest/Support/FileCheckTest.cpp - FileCheck tests --===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "llvm/Support/FileCheck.h"
9 #include "gtest/gtest.h"
10
11 using namespace llvm;
12 namespace {
13
14 class FileCheckTest : public ::testing::Test {};
15
16 TEST_F(FileCheckTest, FileCheckContext) {
17 FileCheckPatternContext Cxt;
18 std::vector GlobalDefines;
19
20 // Define local and global variables from command-line.
21 GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
22 Cxt.defineCmdlineVariables(GlobalDefines);
23
24 // Check defined variables are present and undefined is absent.
25 StringRef LocalVarStr = "LocalVar";
26 StringRef UnknownVarStr = "UnknownVar";
27 llvm::Optional LocalVar = Cxt.getVarValue(LocalVarStr);
28 llvm::Optional UnknownVar = Cxt.getVarValue(UnknownVarStr);
29 EXPECT_TRUE(LocalVar);
30 EXPECT_EQ(*LocalVar, "FOO");
31 EXPECT_FALSE(UnknownVar);
32
33 // Clear local variables and check they become absent.
34 Cxt.clearLocalVars();
35 LocalVar = Cxt.getVarValue(LocalVarStr);
36 EXPECT_FALSE(LocalVar);
37
38 // Redefine global variables and check variables are defined again.
39 GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
40 Cxt.defineCmdlineVariables(GlobalDefines);
41 StringRef GlobalVarStr = "$GlobalVar";
42 llvm::Optional GlobalVar = Cxt.getVarValue(GlobalVarStr);
43 EXPECT_TRUE(GlobalVar);
44 EXPECT_EQ(*GlobalVar, "BAR");
45
46 // Clear local variables and check global variables remain defined.
47 Cxt.clearLocalVars();
48 GlobalVar = Cxt.getVarValue(GlobalVarStr);
49 EXPECT_TRUE(GlobalVar);
50 }
51 } // namespace