blob: 1263ec5e028404ff4dab68c481d506ca747e9138 [file] [log] [blame]
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00006//
7//===----------------------------------------------------------------------===//
8//
9// FileCheck does a line-by line check of a file that validates whether it
10// contains the expected content. This is useful for regression tests etc.
11//
12// This file implements most of the API that will be used by the FileCheck utility
13// as well as various unittests.
14//===----------------------------------------------------------------------===//
15
16#include "llvm/Support/FileCheck.h"
17#include "llvm/ADT/StringSet.h"
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +000018#include "llvm/Support/FormatVariadic.h"
19#include <cstdint>
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +000020#include <list>
21#include <map>
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +000022#include <tuple>
23#include <utility>
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +000024
25using namespace llvm;
26
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000027bool FileCheckNumericVariable::setValue(uint64_t NewValue) {
28 if (Value)
29 return true;
30 Value = NewValue;
31 return false;
32}
33
34bool FileCheckNumericVariable::clearValue() {
35 if (!Value)
36 return true;
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000037 Value = None;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000038 return false;
39}
40
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000041Optional<uint64_t> FileCheckNumExpr::eval() const {
42 Optional<uint64_t> LeftOp = this->LeftOp->getValue();
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000043 // Variable is undefined.
44 if (!LeftOp)
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000045 return None;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000046 return EvalBinop(*LeftOp, RightOp);
47}
48
49StringRef FileCheckNumExpr::getUndefVarName() const {
50 if (!LeftOp->getValue())
51 return LeftOp->getName();
52 return StringRef();
53}
54
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000055Optional<std::string> FileCheckNumericSubstitution::getResult() const {
56 Optional<uint64_t> EvaluatedValue = NumExpr->eval();
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +000057 if (!EvaluatedValue)
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000058 return None;
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +000059 return utostr(*EvaluatedValue);
60}
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000061
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000062Optional<std::string> FileCheckStringSubstitution::getResult() const {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000063 // Look up the value and escape it so that we can put it into the regex.
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000064 Optional<StringRef> VarVal = Context->getPatternVarValue(FromStr);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000065 if (!VarVal)
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +000066 return None;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000067 return Regex::escape(*VarVal);
Thomas Preud'homme288ed912019-05-02 00:04:38 +000068}
69
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +000070StringRef FileCheckNumericSubstitution::getUndefVarName() const {
71 // Although a use of an undefined numeric variable is detected at parse
72 // time, a numeric variable can be undefined later by ClearLocalVariables.
73 return NumExpr->getUndefVarName();
74}
Thomas Preud'homme288ed912019-05-02 00:04:38 +000075
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +000076StringRef FileCheckStringSubstitution::getUndefVarName() const {
Thomas Preud'homme288ed912019-05-02 00:04:38 +000077 if (!Context->getPatternVarValue(FromStr))
78 return FromStr;
79
80 return StringRef();
81}
82
Thomas Preud'homme5a330472019-04-29 13:32:36 +000083bool FileCheckPattern::isValidVarNameStart(char C) {
84 return C == '_' || isalpha(C);
85}
86
87bool FileCheckPattern::parseVariable(StringRef Str, bool &IsPseudo,
88 unsigned &TrailIdx) {
89 if (Str.empty())
90 return true;
91
92 bool ParsedOneChar = false;
93 unsigned I = 0;
94 IsPseudo = Str[0] == '@';
95
96 // Global vars start with '$'.
97 if (Str[0] == '$' || IsPseudo)
98 ++I;
99
100 for (unsigned E = Str.size(); I != E; ++I) {
101 if (!ParsedOneChar && !isValidVarNameStart(Str[I]))
102 return true;
103
104 // Variable names are composed of alphanumeric characters and underscores.
105 if (Str[I] != '_' && !isalnum(Str[I]))
106 break;
107 ParsedOneChar = true;
108 }
109
110 TrailIdx = I;
111 return false;
112}
113
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000114// StringRef holding all characters considered as horizontal whitespaces by
115// FileCheck input canonicalization.
116StringRef SpaceChars = " \t";
117
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000118// Parsing helper function that strips the first character in S and returns it.
119static char popFront(StringRef &S) {
120 char C = S.front();
121 S = S.drop_front();
122 return C;
123}
124
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000125static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
126 return LeftOp + RightOp;
127}
128static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
129 return LeftOp - RightOp;
130}
131
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000132FileCheckNumExpr *
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000133FileCheckPattern::parseNumericSubstitution(StringRef Name, bool IsPseudo,
134 StringRef Trailer,
135 const SourceMgr &SM) const {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000136 if (IsPseudo && !Name.equals("@LINE")) {
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000137 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000138 "invalid pseudo numeric variable '" + Name + "'");
139 return nullptr;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000140 }
141
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000142 // This method is indirectly called from ParsePattern for all numeric
143 // variable definitions and uses in the order in which they appear in the
144 // CHECK pattern. For each definition, the pointer to the class instance of
145 // the corresponding numeric variable definition is stored in
146 // GlobalNumericVariableTable. Therefore, the pointer we get below is for the
147 // class instance corresponding to the last definition of this variable use.
148 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
149 if (VarTableIter == Context->GlobalNumericVariableTable.end()) {
150 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
151 "using undefined numeric variable '" + Name + "'");
152 return nullptr;
153 }
154
155 FileCheckNumericVariable *LeftOp = VarTableIter->second;
156
157 // Check if this is a supported operation and select a function to perform
158 // it.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000159 Trailer = Trailer.ltrim(SpaceChars);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000160 if (Trailer.empty()) {
161 return Context->makeNumExpr(add, LeftOp, 0);
162 }
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000163 SMLoc OpLoc = SMLoc::getFromPointer(Trailer.data());
164 char Operator = popFront(Trailer);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000165 binop_eval_t EvalBinop;
166 switch (Operator) {
167 case '+':
168 EvalBinop = add;
169 break;
170 case '-':
171 EvalBinop = sub;
172 break;
173 default:
174 SM.PrintMessage(OpLoc, SourceMgr::DK_Error,
175 Twine("unsupported numeric operation '") + Twine(Operator) +
176 "'");
177 return nullptr;
178 }
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000179
180 // Parse right operand.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000181 Trailer = Trailer.ltrim(SpaceChars);
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000182 if (Trailer.empty()) {
183 SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000184 "missing operand in numeric expression");
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000185 return nullptr;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000186 }
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000187 uint64_t RightOp;
188 if (Trailer.consumeInteger(10, RightOp)) {
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000189 SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
190 "invalid offset in numeric expression '" + Trailer + "'");
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000191 return nullptr;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000192 }
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000193 Trailer = Trailer.ltrim(SpaceChars);
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000194 if (!Trailer.empty()) {
195 SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
196 "unexpected characters at end of numeric expression '" +
197 Trailer + "'");
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000198 return nullptr;
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000199 }
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000200
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000201 return Context->makeNumExpr(EvalBinop, LeftOp, RightOp);
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000202}
203
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000204bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000205 SourceMgr &SM, unsigned LineNumber,
206 const FileCheckRequest &Req) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000207 bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
208
209 this->LineNumber = LineNumber;
210 PatternLoc = SMLoc::getFromPointer(PatternStr.data());
211
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000212 // Create fake @LINE pseudo variable definition.
213 StringRef LinePseudo = "@LINE";
214 uint64_t LineNumber64 = LineNumber;
215 FileCheckNumericVariable *LinePseudoVar =
216 Context->makeNumericVariable(LinePseudo, LineNumber64);
217 Context->GlobalNumericVariableTable[LinePseudo] = LinePseudoVar;
218
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000219 if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
220 // Ignore trailing whitespace.
221 while (!PatternStr.empty() &&
222 (PatternStr.back() == ' ' || PatternStr.back() == '\t'))
223 PatternStr = PatternStr.substr(0, PatternStr.size() - 1);
224
225 // Check that there is something on the line.
226 if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {
227 SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
228 "found empty check string with prefix '" + Prefix + ":'");
229 return true;
230 }
231
232 if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {
233 SM.PrintMessage(
234 PatternLoc, SourceMgr::DK_Error,
235 "found non-empty check string for empty check with prefix '" + Prefix +
236 ":'");
237 return true;
238 }
239
240 if (CheckTy == Check::CheckEmpty) {
241 RegExStr = "(\n$)";
242 return false;
243 }
244
245 // Check to see if this is a fixed string, or if it has regex pieces.
246 if (!MatchFullLinesHere &&
247 (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&
248 PatternStr.find("[[") == StringRef::npos))) {
249 FixedStr = PatternStr;
250 return false;
251 }
252
253 if (MatchFullLinesHere) {
254 RegExStr += '^';
255 if (!Req.NoCanonicalizeWhiteSpace)
256 RegExStr += " *";
257 }
258
259 // Paren value #0 is for the fully matched string. Any new parenthesized
260 // values add from there.
261 unsigned CurParen = 1;
262
263 // Otherwise, there is at least one regex piece. Build up the regex pattern
264 // by escaping scary characters in fixed strings, building up one big regex.
265 while (!PatternStr.empty()) {
266 // RegEx matches.
267 if (PatternStr.startswith("{{")) {
268 // This is the start of a regex match. Scan for the }}.
269 size_t End = PatternStr.find("}}");
270 if (End == StringRef::npos) {
271 SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
272 SourceMgr::DK_Error,
273 "found start of regex string with no end '}}'");
274 return true;
275 }
276
277 // Enclose {{}} patterns in parens just like [[]] even though we're not
278 // capturing the result for any purpose. This is required in case the
279 // expression contains an alternation like: CHECK: abc{{x|z}}def. We
280 // want this to turn into: "abc(x|z)def" not "abcx|zdef".
281 RegExStr += '(';
282 ++CurParen;
283
284 if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM))
285 return true;
286 RegExStr += ')';
287
288 PatternStr = PatternStr.substr(End + 2);
289 continue;
290 }
291
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000292 // String and numeric substitution blocks. String substitution blocks come
293 // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
294 // other regex) and assigns it to the string variable 'foo'. The latter
295 // substitutes foo's value. Numeric substitution blocks start with a
296 // '#' sign after the double brackets and only have the substitution form.
297 // Both string and numeric variables must satisfy the regular expression
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000298 // "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch some common
299 // errors.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000300 if (PatternStr.startswith("[[")) {
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000301 StringRef UnparsedPatternStr = PatternStr.substr(2);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000302 // Find the closing bracket pair ending the match. End is going to be an
303 // offset relative to the beginning of the match string.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000304 size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);
305 StringRef MatchStr = UnparsedPatternStr.substr(0, End);
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000306 bool IsNumBlock = MatchStr.consume_front("#");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000307
308 if (End == StringRef::npos) {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000309 SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
310 SourceMgr::DK_Error,
311 "Invalid substitution block, no ]] found");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000312 return true;
313 }
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000314 // Strip the substitution block we are parsing. End points to the start
315 // of the "]]" closing the expression so account for it in computing the
316 // index of the first unparsed character.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000317 PatternStr = UnparsedPatternStr.substr(End + 2);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000318
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000319 size_t VarEndIdx = MatchStr.find(":");
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000320 if (IsNumBlock)
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000321 MatchStr = MatchStr.ltrim(SpaceChars);
322 else {
323 size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
324 if (SpacePos != StringRef::npos) {
325 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),
326 SourceMgr::DK_Error, "unexpected whitespace");
327 return true;
328 }
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000329 }
330
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000331 // Get the variable name (e.g. "foo") and verify it is well formed.
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000332 bool IsPseudo;
333 unsigned TrailIdx;
334 if (parseVariable(MatchStr, IsPseudo, TrailIdx)) {
335 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000336 SourceMgr::DK_Error, "invalid variable name");
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000337 return true;
338 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000339
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000340 size_t SubstInsertIdx = RegExStr.size();
341 FileCheckNumExpr *NumExpr;
342
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000343 StringRef Name = MatchStr.substr(0, TrailIdx);
344 StringRef Trailer = MatchStr.substr(TrailIdx);
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000345 bool IsVarDef = (VarEndIdx != StringRef::npos);
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000346
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000347 if (IsVarDef) {
348 if (IsPseudo || !Trailer.consume_front(":")) {
349 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
350 SourceMgr::DK_Error,
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000351 "invalid name in string variable definition");
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000352 return true;
353 }
354
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000355 // Detect collisions between string and numeric variables when the
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000356 // former is created later than the latter.
357 if (Context->GlobalNumericVariableTable.find(Name) !=
358 Context->GlobalNumericVariableTable.end()) {
359 SM.PrintMessage(
360 SMLoc::getFromPointer(MatchStr.data()), SourceMgr::DK_Error,
361 "numeric variable with name '" + Name + "' already exists");
362 return true;
363 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000364 }
365
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000366 if (IsNumBlock || (!IsVarDef && IsPseudo)) {
367 NumExpr = parseNumericSubstitution(Name, IsPseudo, Trailer, SM);
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000368 if (NumExpr == nullptr)
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000369 return true;
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000370 IsNumBlock = true;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000371 }
372
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000373 // Handle substitutions: [[foo]] and [[#<foo expr>]].
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000374 if (!IsVarDef) {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000375 // Handle substitution of string variables that were defined earlier on
376 // the same line by emitting a backreference.
377 if (!IsNumBlock && VariableDefs.find(Name) != VariableDefs.end()) {
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000378 unsigned CaptureParen = VariableDefs[Name];
379 if (CaptureParen < 1 || CaptureParen > 9) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000380 SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
381 SourceMgr::DK_Error,
382 "Can't back-reference more than 9 variables");
383 return true;
384 }
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000385 AddBackrefToRegEx(CaptureParen);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000386 } else {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000387 // Handle substitution of string variables ([[<var>]]) defined in
388 // previous CHECK patterns, and substitution of numeric expressions.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000389 FileCheckSubstitution *Substitution =
390 IsNumBlock
391 ? Context->makeNumericSubstitution(MatchStr, NumExpr,
392 SubstInsertIdx)
393 : Context->makeStringSubstitution(MatchStr, SubstInsertIdx);
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000394 Substitutions.push_back(Substitution);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000395 }
396 continue;
397 }
398
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000399 // Handle variable definitions: [[foo:.*]].
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000400 VariableDefs[Name] = CurParen;
401 RegExStr += '(';
402 ++CurParen;
403
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000404 if (AddRegExToRegEx(Trailer, CurParen, SM))
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000405 return true;
406
407 RegExStr += ')';
408 }
409
410 // Handle fixed string matches.
411 // Find the end, which is the start of the next regex.
412 size_t FixedMatchEnd = PatternStr.find("{{");
413 FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));
414 RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd));
415 PatternStr = PatternStr.substr(FixedMatchEnd);
416 }
417
418 if (MatchFullLinesHere) {
419 if (!Req.NoCanonicalizeWhiteSpace)
420 RegExStr += " *";
421 RegExStr += '$';
422 }
423
424 return false;
425}
426
427bool FileCheckPattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {
428 Regex R(RS);
429 std::string Error;
430 if (!R.isValid(Error)) {
431 SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error,
432 "invalid regex: " + Error);
433 return true;
434 }
435
436 RegExStr += RS.str();
437 CurParen += R.getNumMatches();
438 return false;
439}
440
441void FileCheckPattern::AddBackrefToRegEx(unsigned BackrefNum) {
442 assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");
443 std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum);
444 RegExStr += Backref;
445}
446
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000447size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000448 // If this is the EOF pattern, match it immediately.
449 if (CheckTy == Check::CheckEOF) {
450 MatchLen = 0;
451 return Buffer.size();
452 }
453
454 // If this is a fixed string pattern, just match it now.
455 if (!FixedStr.empty()) {
456 MatchLen = FixedStr.size();
457 return Buffer.find(FixedStr);
458 }
459
460 // Regex match.
461
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000462 // If there are substitutions, we need to create a temporary string with the
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000463 // actual value.
464 StringRef RegExToMatch = RegExStr;
465 std::string TmpStr;
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000466 if (!Substitutions.empty()) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000467 TmpStr = RegExStr;
468
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000469 size_t InsertOffset = 0;
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000470 // Substitute all string variables and numeric expressions whose values are
471 // only now known. Use of string variables defined on the same line are
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000472 // handled by back-references.
473 for (const auto &Substitution : Substitutions) {
474 // Substitute and check for failure (e.g. use of undefined variable).
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +0000475 Optional<std::string> Value = Substitution->getResult();
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000476 if (!Value)
477 return StringRef::npos;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000478
479 // Plop it into the regex at the adjusted offset.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000480 TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000481 Value->begin(), Value->end());
482 InsertOffset += Value->size();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000483 }
484
485 // Match the newly constructed regex.
486 RegExToMatch = TmpStr;
487 }
488
489 SmallVector<StringRef, 4> MatchInfo;
490 if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo))
491 return StringRef::npos;
492
493 // Successful regex match.
494 assert(!MatchInfo.empty() && "Didn't get any match");
495 StringRef FullMatch = MatchInfo[0];
496
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000497 // If this defines any string variables, remember their values.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000498 for (const auto &VariableDef : VariableDefs) {
499 assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000500 Context->GlobalVariableTable[VariableDef.first] =
501 MatchInfo[VariableDef.second];
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000502 }
503
504 // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
505 // the required preceding newline, which is consumed by the pattern in the
506 // case of CHECK-EMPTY but not CHECK-NEXT.
507 size_t MatchStartSkip = CheckTy == Check::CheckEmpty;
508 MatchLen = FullMatch.size() - MatchStartSkip;
509 return FullMatch.data() - Buffer.data() + MatchStartSkip;
510}
511
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000512unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000513 // Just compute the number of matching characters. For regular expressions, we
514 // just compare against the regex itself and hope for the best.
515 //
516 // FIXME: One easy improvement here is have the regex lib generate a single
517 // example regular expression which matches, and use that as the example
518 // string.
519 StringRef ExampleString(FixedStr);
520 if (ExampleString.empty())
521 ExampleString = RegExStr;
522
523 // Only compare up to the first line in the buffer, or the string size.
524 StringRef BufferPrefix = Buffer.substr(0, ExampleString.size());
525 BufferPrefix = BufferPrefix.split('\n').first;
526 return BufferPrefix.edit_distance(ExampleString);
527}
528
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000529void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
530 SMRange MatchRange) const {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000531 // Print what we know about substitutions.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000532 if (!Substitutions.empty()) {
533 for (const auto &Substitution : Substitutions) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000534 SmallString<256> Msg;
535 raw_svector_ostream OS(Msg);
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +0000536 Optional<std::string> MatchedValue = Substitution->getResult();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000537
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000538 // Substitution failed or is not known at match time, print the undefined
539 // variable it uses.
540 if (!MatchedValue) {
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000541 StringRef UndefVarName = Substitution->getUndefVarName();
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000542 if (UndefVarName.empty())
543 continue;
544 OS << "uses undefined variable \"";
545 OS.write_escaped(UndefVarName) << "\"";
546 } else {
547 // Substitution succeeded. Print substituted value.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000548 OS << "with \"";
549 OS.write_escaped(Substitution->getFromString()) << "\" equal to \"";
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000550 OS.write_escaped(*MatchedValue) << "\"";
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000551 }
552
553 if (MatchRange.isValid())
554 SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(),
555 {MatchRange});
556 else
557 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
558 SourceMgr::DK_Note, OS.str());
559 }
560 }
561}
562
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000563static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,
564 const SourceMgr &SM, SMLoc Loc,
565 Check::FileCheckType CheckTy,
566 StringRef Buffer, size_t Pos, size_t Len,
Joel E. Denny7df86962018-12-18 00:03:03 +0000567 std::vector<FileCheckDiag> *Diags,
568 bool AdjustPrevDiag = false) {
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000569 SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);
570 SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);
571 SMRange Range(Start, End);
Joel E. Denny96f0e842018-12-18 00:03:36 +0000572 if (Diags) {
Joel E. Denny7df86962018-12-18 00:03:03 +0000573 if (AdjustPrevDiag)
574 Diags->rbegin()->MatchTy = MatchTy;
575 else
576 Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
577 }
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000578 return Range;
579}
580
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000581void FileCheckPattern::printFuzzyMatch(
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000582 const SourceMgr &SM, StringRef Buffer,
Joel E. Denny2c007c82018-12-18 00:02:04 +0000583 std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000584 // Attempt to find the closest/best fuzzy match. Usually an error happens
585 // because some string in the output didn't exactly match. In these cases, we
586 // would like to show the user a best guess at what "should have" matched, to
587 // save them having to actually check the input manually.
588 size_t NumLinesForward = 0;
589 size_t Best = StringRef::npos;
590 double BestQuality = 0;
591
592 // Use an arbitrary 4k limit on how far we will search.
593 for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) {
594 if (Buffer[i] == '\n')
595 ++NumLinesForward;
596
597 // Patterns have leading whitespace stripped, so skip whitespace when
598 // looking for something which looks like a pattern.
599 if (Buffer[i] == ' ' || Buffer[i] == '\t')
600 continue;
601
602 // Compute the "quality" of this match as an arbitrary combination of the
603 // match distance and the number of lines skipped to get to this match.
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000604 unsigned Distance = computeMatchDistance(Buffer.substr(i));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000605 double Quality = Distance + (NumLinesForward / 100.);
606
607 if (Quality < BestQuality || Best == StringRef::npos) {
608 Best = i;
609 BestQuality = Quality;
610 }
611 }
612
613 // Print the "possible intended match here" line if we found something
614 // reasonable and not equal to what we showed in the "scanning from here"
615 // line.
616 if (Best && Best != StringRef::npos && BestQuality < 50) {
Joel E. Denny2c007c82018-12-18 00:02:04 +0000617 SMRange MatchRange =
618 ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(),
619 getCheckTy(), Buffer, Best, 0, Diags);
620 SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note,
621 "possible intended match here");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000622
623 // FIXME: If we wanted to be really friendly we would show why the match
624 // failed, as it can be hard to spot simple one character differences.
625 }
626}
627
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +0000628Optional<StringRef>
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000629FileCheckPatternContext::getPatternVarValue(StringRef VarName) {
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000630 auto VarIter = GlobalVariableTable.find(VarName);
631 if (VarIter == GlobalVariableTable.end())
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +0000632 return None;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000633
634 return VarIter->second;
635}
636
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000637FileCheckNumExpr *
638FileCheckPatternContext::makeNumExpr(binop_eval_t EvalBinop,
639 FileCheckNumericVariable *OperandLeft,
640 uint64_t OperandRight) {
641 NumExprs.push_back(llvm::make_unique<FileCheckNumExpr>(EvalBinop, OperandLeft,
642 OperandRight));
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000643 return NumExprs.back().get();
644}
645
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000646FileCheckNumericVariable *
647FileCheckPatternContext::makeNumericVariable(StringRef Name, uint64_t Value) {
648 NumericVariables.push_back(
649 llvm::make_unique<FileCheckNumericVariable>(Name, Value));
650 return NumericVariables.back().get();
651}
652
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000653FileCheckSubstitution *
654FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
655 size_t InsertIdx) {
656 Substitutions.push_back(
657 llvm::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));
658 return Substitutions.back().get();
659}
660
661FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
662 StringRef Expr, FileCheckNumExpr *NumExpr, size_t InsertIdx) {
663 Substitutions.push_back(llvm::make_unique<FileCheckNumericSubstitution>(
664 this, Expr, NumExpr, InsertIdx));
665 return Substitutions.back().get();
666}
667
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000668size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {
669 // Offset keeps track of the current offset within the input Str
670 size_t Offset = 0;
671 // [...] Nesting depth
672 size_t BracketDepth = 0;
673
674 while (!Str.empty()) {
675 if (Str.startswith("]]") && BracketDepth == 0)
676 return Offset;
677 if (Str[0] == '\\') {
678 // Backslash escapes the next char within regexes, so skip them both.
679 Str = Str.substr(2);
680 Offset += 2;
681 } else {
682 switch (Str[0]) {
683 default:
684 break;
685 case '[':
686 BracketDepth++;
687 break;
688 case ']':
689 if (BracketDepth == 0) {
690 SM.PrintMessage(SMLoc::getFromPointer(Str.data()),
691 SourceMgr::DK_Error,
692 "missing closing \"]\" for regex variable");
693 exit(1);
694 }
695 BracketDepth--;
696 break;
697 }
698 Str = Str.substr(1);
699 Offset++;
700 }
701 }
702
703 return StringRef::npos;
704}
705
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +0000706StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB,
707 SmallVectorImpl<char> &OutputBuffer) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000708 OutputBuffer.reserve(MB.getBufferSize());
709
710 for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd();
711 Ptr != End; ++Ptr) {
712 // Eliminate trailing dosish \r.
713 if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {
714 continue;
715 }
716
717 // If current char is not a horizontal whitespace or if horizontal
718 // whitespace canonicalization is disabled, dump it to output as is.
719 if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) {
720 OutputBuffer.push_back(*Ptr);
721 continue;
722 }
723
724 // Otherwise, add one space and advance over neighboring space.
725 OutputBuffer.push_back(' ');
726 while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t'))
727 ++Ptr;
728 }
729
730 // Add a null byte and then return all but that byte.
731 OutputBuffer.push_back('\0');
732 return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);
733}
734
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000735FileCheckDiag::FileCheckDiag(const SourceMgr &SM,
736 const Check::FileCheckType &CheckTy,
737 SMLoc CheckLoc, MatchType MatchTy,
738 SMRange InputRange)
739 : CheckTy(CheckTy), MatchTy(MatchTy) {
740 auto Start = SM.getLineAndColumn(InputRange.Start);
741 auto End = SM.getLineAndColumn(InputRange.End);
742 InputStartLine = Start.first;
743 InputStartCol = Start.second;
744 InputEndLine = End.first;
745 InputEndCol = End.second;
746 Start = SM.getLineAndColumn(CheckLoc);
747 CheckLine = Start.first;
748 CheckCol = Start.second;
749}
750
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000751static bool IsPartOfWord(char c) {
752 return (isalnum(c) || c == '-' || c == '_');
753}
754
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000755Check::FileCheckType &Check::FileCheckType::setCount(int C) {
Fedor Sergeev8477a3e2018-11-13 01:09:53 +0000756 assert(Count > 0 && "zero and negative counts are not supported");
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000757 assert((C == 1 || Kind == CheckPlain) &&
758 "count supported only for plain CHECK directives");
759 Count = C;
760 return *this;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000761}
762
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000763std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
764 switch (Kind) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000765 case Check::CheckNone:
766 return "invalid";
767 case Check::CheckPlain:
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000768 if (Count > 1)
769 return Prefix.str() + "-COUNT";
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000770 return Prefix;
771 case Check::CheckNext:
772 return Prefix.str() + "-NEXT";
773 case Check::CheckSame:
774 return Prefix.str() + "-SAME";
775 case Check::CheckNot:
776 return Prefix.str() + "-NOT";
777 case Check::CheckDAG:
778 return Prefix.str() + "-DAG";
779 case Check::CheckLabel:
780 return Prefix.str() + "-LABEL";
781 case Check::CheckEmpty:
782 return Prefix.str() + "-EMPTY";
783 case Check::CheckEOF:
784 return "implicit EOF";
785 case Check::CheckBadNot:
786 return "bad NOT";
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000787 case Check::CheckBadCount:
788 return "bad COUNT";
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000789 }
790 llvm_unreachable("unknown FileCheckType");
791}
792
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000793static std::pair<Check::FileCheckType, StringRef>
794FindCheckType(StringRef Buffer, StringRef Prefix) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000795 if (Buffer.size() <= Prefix.size())
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000796 return {Check::CheckNone, StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000797
798 char NextChar = Buffer[Prefix.size()];
799
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000800 StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000801 // Verify that the : is present after the prefix.
802 if (NextChar == ':')
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000803 return {Check::CheckPlain, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000804
805 if (NextChar != '-')
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000806 return {Check::CheckNone, StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000807
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000808 if (Rest.consume_front("COUNT-")) {
809 int64_t Count;
810 if (Rest.consumeInteger(10, Count))
811 // Error happened in parsing integer.
812 return {Check::CheckBadCount, Rest};
813 if (Count <= 0 || Count > INT32_MAX)
814 return {Check::CheckBadCount, Rest};
815 if (!Rest.consume_front(":"))
816 return {Check::CheckBadCount, Rest};
817 return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest};
818 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000819
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000820 if (Rest.consume_front("NEXT:"))
821 return {Check::CheckNext, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000822
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000823 if (Rest.consume_front("SAME:"))
824 return {Check::CheckSame, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000825
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000826 if (Rest.consume_front("NOT:"))
827 return {Check::CheckNot, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000828
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000829 if (Rest.consume_front("DAG:"))
830 return {Check::CheckDAG, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000831
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000832 if (Rest.consume_front("LABEL:"))
833 return {Check::CheckLabel, Rest};
834
835 if (Rest.consume_front("EMPTY:"))
836 return {Check::CheckEmpty, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000837
838 // You can't combine -NOT with another suffix.
839 if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
840 Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
841 Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||
842 Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000843 return {Check::CheckBadNot, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000844
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000845 return {Check::CheckNone, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000846}
847
848// From the given position, find the next character after the word.
849static size_t SkipWord(StringRef Str, size_t Loc) {
850 while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
851 ++Loc;
852 return Loc;
853}
854
Thomas Preud'homme4a8ef112019-05-08 21:47:31 +0000855/// Searches the buffer for the first prefix in the prefix regular expression.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000856///
857/// This searches the buffer using the provided regular expression, however it
858/// enforces constraints beyond that:
859/// 1) The found prefix must not be a suffix of something that looks like
860/// a valid prefix.
861/// 2) The found prefix must be followed by a valid check type suffix using \c
862/// FindCheckType above.
863///
Thomas Preud'homme4a8ef112019-05-08 21:47:31 +0000864/// \returns a pair of StringRefs into the Buffer, which combines:
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000865/// - the first match of the regular expression to satisfy these two is
866/// returned,
867/// otherwise an empty StringRef is returned to indicate failure.
868/// - buffer rewound to the location right after parsed suffix, for parsing
869/// to continue from
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000870///
871/// If this routine returns a valid prefix, it will also shrink \p Buffer to
872/// start at the beginning of the returned prefix, increment \p LineNumber for
873/// each new line consumed from \p Buffer, and set \p CheckTy to the type of
874/// check found by examining the suffix.
875///
876/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy
877/// is unspecified.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000878static std::pair<StringRef, StringRef>
879FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
880 unsigned &LineNumber, Check::FileCheckType &CheckTy) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000881 SmallVector<StringRef, 2> Matches;
882
883 while (!Buffer.empty()) {
884 // Find the first (longest) match using the RE.
885 if (!PrefixRE.match(Buffer, &Matches))
886 // No match at all, bail.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000887 return {StringRef(), StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000888
889 StringRef Prefix = Matches[0];
890 Matches.clear();
891
892 assert(Prefix.data() >= Buffer.data() &&
893 Prefix.data() < Buffer.data() + Buffer.size() &&
894 "Prefix doesn't start inside of buffer!");
895 size_t Loc = Prefix.data() - Buffer.data();
896 StringRef Skipped = Buffer.substr(0, Loc);
897 Buffer = Buffer.drop_front(Loc);
898 LineNumber += Skipped.count('\n');
899
900 // Check that the matched prefix isn't a suffix of some other check-like
901 // word.
902 // FIXME: This is a very ad-hoc check. it would be better handled in some
903 // other way. Among other things it seems hard to distinguish between
904 // intentional and unintentional uses of this feature.
905 if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {
906 // Now extract the type.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000907 StringRef AfterSuffix;
908 std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000909
910 // If we've found a valid check type for this prefix, we're done.
911 if (CheckTy != Check::CheckNone)
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000912 return {Prefix, AfterSuffix};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000913 }
914
915 // If we didn't successfully find a prefix, we need to skip this invalid
916 // prefix and continue scanning. We directly skip the prefix that was
917 // matched and any additional parts of that check-like word.
918 Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size()));
919 }
920
921 // We ran out of buffer while skipping partial matches so give up.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000922 return {StringRef(), StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000923}
924
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +0000925bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
926 std::vector<FileCheckString> &CheckStrings) {
Thomas Preud'homme5a330472019-04-29 13:32:36 +0000927 if (PatternContext.defineCmdlineVariables(Req.GlobalDefines, SM))
928 return true;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000929
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000930 std::vector<FileCheckPattern> ImplicitNegativeChecks;
931 for (const auto &PatternString : Req.ImplicitCheckNot) {
932 // Create a buffer with fake command line content in order to display the
933 // command line option responsible for the specific implicit CHECK-NOT.
934 std::string Prefix = "-implicit-check-not='";
935 std::string Suffix = "'";
936 std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(
937 Prefix + PatternString + Suffix, "command line");
938
939 StringRef PatternInBuffer =
940 CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
941 SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
942
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000943 ImplicitNegativeChecks.push_back(
944 FileCheckPattern(Check::CheckNot, &PatternContext));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000945 ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer,
946 "IMPLICIT-CHECK", SM, 0, Req);
947 }
948
949 std::vector<FileCheckPattern> DagNotMatches = ImplicitNegativeChecks;
950
951 // LineNumber keeps track of the line on which CheckPrefix instances are
952 // found.
953 unsigned LineNumber = 1;
954
955 while (1) {
956 Check::FileCheckType CheckTy;
957
958 // See if a prefix occurs in the memory buffer.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000959 StringRef UsedPrefix;
960 StringRef AfterSuffix;
961 std::tie(UsedPrefix, AfterSuffix) =
962 FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000963 if (UsedPrefix.empty())
964 break;
965 assert(UsedPrefix.data() == Buffer.data() &&
966 "Failed to move Buffer's start forward, or pointed prefix outside "
967 "of the buffer!");
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000968 assert(AfterSuffix.data() >= Buffer.data() &&
969 AfterSuffix.data() < Buffer.data() + Buffer.size() &&
970 "Parsing after suffix doesn't start inside of buffer!");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000971
972 // Location to use for error messages.
973 const char *UsedPrefixStart = UsedPrefix.data();
974
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000975 // Skip the buffer to the end of parsed suffix (or just prefix, if no good
976 // suffix was processed).
977 Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size())
978 : AfterSuffix;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000979
980 // Complain about useful-looking but unsupported suffixes.
981 if (CheckTy == Check::CheckBadNot) {
982 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
983 "unsupported -NOT combo on prefix '" + UsedPrefix + "'");
984 return true;
985 }
986
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000987 // Complain about invalid count specification.
988 if (CheckTy == Check::CheckBadCount) {
989 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
990 "invalid count in -COUNT specification on prefix '" +
991 UsedPrefix + "'");
992 return true;
993 }
994
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000995 // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
996 // leading whitespace.
997 if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
998 Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
999
1000 // Scan ahead to the end of line.
1001 size_t EOL = Buffer.find_first_of("\n\r");
1002
1003 // Remember the location of the start of the pattern, for diagnostics.
1004 SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
1005
1006 // Parse the pattern.
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001007 FileCheckPattern P(CheckTy, &PatternContext);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001008 if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber, Req))
1009 return true;
1010
1011 // Verify that CHECK-LABEL lines do not define or use variables
1012 if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {
1013 SM.PrintMessage(
1014 SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error,
1015 "found '" + UsedPrefix + "-LABEL:'"
1016 " with variable definition or use");
1017 return true;
1018 }
1019
1020 Buffer = Buffer.substr(EOL);
1021
1022 // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
1023 if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
1024 CheckTy == Check::CheckEmpty) &&
1025 CheckStrings.empty()) {
1026 StringRef Type = CheckTy == Check::CheckNext
1027 ? "NEXT"
1028 : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";
1029 SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
1030 SourceMgr::DK_Error,
1031 "found '" + UsedPrefix + "-" + Type +
1032 "' without previous '" + UsedPrefix + ": line");
1033 return true;
1034 }
1035
1036 // Handle CHECK-DAG/-NOT.
1037 if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {
1038 DagNotMatches.push_back(P);
1039 continue;
1040 }
1041
1042 // Okay, add the string we captured to the output vector and move on.
1043 CheckStrings.emplace_back(P, UsedPrefix, PatternLoc);
1044 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
1045 DagNotMatches = ImplicitNegativeChecks;
1046 }
1047
1048 // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
1049 // prefix as a filler for the error message.
1050 if (!DagNotMatches.empty()) {
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001051 CheckStrings.emplace_back(
1052 FileCheckPattern(Check::CheckEOF, &PatternContext),
1053 *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001054 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
1055 }
1056
1057 if (CheckStrings.empty()) {
1058 errs() << "error: no check strings found with prefix"
1059 << (Req.CheckPrefixes.size() > 1 ? "es " : " ");
1060 auto I = Req.CheckPrefixes.begin();
1061 auto E = Req.CheckPrefixes.end();
1062 if (I != E) {
1063 errs() << "\'" << *I << ":'";
1064 ++I;
1065 }
1066 for (; I != E; ++I)
1067 errs() << ", \'" << *I << ":'";
1068
1069 errs() << '\n';
1070 return true;
1071 }
1072
1073 return false;
1074}
1075
1076static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
1077 StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001078 int MatchedCount, StringRef Buffer, size_t MatchPos,
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001079 size_t MatchLen, const FileCheckRequest &Req,
1080 std::vector<FileCheckDiag> *Diags) {
Joel E. Denny352695c2019-01-22 21:41:42 +00001081 bool PrintDiag = true;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001082 if (ExpectedMatch) {
1083 if (!Req.Verbose)
1084 return;
1085 if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)
1086 return;
Joel E. Denny352695c2019-01-22 21:41:42 +00001087 // Due to their verbosity, we don't print verbose diagnostics here if we're
1088 // gathering them for a different rendering, but we always print other
1089 // diagnostics.
1090 PrintDiag = !Diags;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001091 }
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001092 SMRange MatchRange = ProcessMatchResult(
Joel E. Dennye2afb612018-12-18 00:03:51 +00001093 ExpectedMatch ? FileCheckDiag::MatchFoundAndExpected
1094 : FileCheckDiag::MatchFoundButExcluded,
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001095 SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);
Joel E. Denny352695c2019-01-22 21:41:42 +00001096 if (!PrintDiag)
1097 return;
1098
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001099 std::string Message = formatv("{0}: {1} string found in input",
1100 Pat.getCheckTy().getDescription(Prefix),
1101 (ExpectedMatch ? "expected" : "excluded"))
1102 .str();
1103 if (Pat.getCount() > 1)
1104 Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
1105
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001106 SM.PrintMessage(
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001107 Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001108 SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
1109 {MatchRange});
Thomas Preud'homme288ed912019-05-02 00:04:38 +00001110 Pat.printSubstitutions(SM, Buffer, MatchRange);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001111}
1112
1113static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001114 const FileCheckString &CheckStr, int MatchedCount,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001115 StringRef Buffer, size_t MatchPos, size_t MatchLen,
1116 FileCheckRequest &Req,
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001117 std::vector<FileCheckDiag> *Diags) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001118 PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001119 MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001120}
1121
1122static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001123 StringRef Prefix, SMLoc Loc,
1124 const FileCheckPattern &Pat, int MatchedCount,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001125 StringRef Buffer, bool VerboseVerbose,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001126 std::vector<FileCheckDiag> *Diags) {
Joel E. Denny352695c2019-01-22 21:41:42 +00001127 bool PrintDiag = true;
1128 if (!ExpectedMatch) {
1129 if (!VerboseVerbose)
1130 return;
1131 // Due to their verbosity, we don't print verbose diagnostics here if we're
1132 // gathering them for a different rendering, but we always print other
1133 // diagnostics.
1134 PrintDiag = !Diags;
1135 }
1136
1137 // If the current position is at the end of a line, advance to the start of
1138 // the next line.
1139 Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));
1140 SMRange SearchRange = ProcessMatchResult(
1141 ExpectedMatch ? FileCheckDiag::MatchNoneButExpected
1142 : FileCheckDiag::MatchNoneAndExcluded,
1143 SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);
1144 if (!PrintDiag)
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001145 return;
1146
Joel E. Denny352695c2019-01-22 21:41:42 +00001147 // Print "not found" diagnostic.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001148 std::string Message = formatv("{0}: {1} string not found in input",
1149 Pat.getCheckTy().getDescription(Prefix),
1150 (ExpectedMatch ? "expected" : "excluded"))
1151 .str();
1152 if (Pat.getCount() > 1)
1153 Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001154 SM.PrintMessage(
1155 Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001156
Joel E. Denny352695c2019-01-22 21:41:42 +00001157 // Print the "scanning from here" line.
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001158 SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001159
1160 // Allow the pattern to print additional information if desired.
Thomas Preud'homme288ed912019-05-02 00:04:38 +00001161 Pat.printSubstitutions(SM, Buffer);
Joel E. Denny96f0e842018-12-18 00:03:36 +00001162
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001163 if (ExpectedMatch)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001164 Pat.printFuzzyMatch(SM, Buffer, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001165}
1166
1167static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001168 const FileCheckString &CheckStr, int MatchedCount,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001169 StringRef Buffer, bool VerboseVerbose,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001170 std::vector<FileCheckDiag> *Diags) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001171 PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001172 MatchedCount, Buffer, VerboseVerbose, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001173}
1174
Thomas Preud'homme4a8ef112019-05-08 21:47:31 +00001175/// Counts the number of newlines in the specified range.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001176static unsigned CountNumNewlinesBetween(StringRef Range,
1177 const char *&FirstNewLine) {
1178 unsigned NumNewLines = 0;
1179 while (1) {
1180 // Scan for newline.
1181 Range = Range.substr(Range.find_first_of("\n\r"));
1182 if (Range.empty())
1183 return NumNewLines;
1184
1185 ++NumNewLines;
1186
1187 // Handle \n\r and \r\n as a single newline.
1188 if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&
1189 (Range[0] != Range[1]))
1190 Range = Range.substr(1);
1191 Range = Range.substr(1);
1192
1193 if (NumNewLines == 1)
1194 FirstNewLine = Range.begin();
1195 }
1196}
1197
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001198size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001199 bool IsLabelScanMode, size_t &MatchLen,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001200 FileCheckRequest &Req,
1201 std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001202 size_t LastPos = 0;
1203 std::vector<const FileCheckPattern *> NotStrings;
1204
1205 // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL
1206 // bounds; we have not processed variable definitions within the bounded block
1207 // yet so cannot handle any final CHECK-DAG yet; this is handled when going
1208 // over the block again (including the last CHECK-LABEL) in normal mode.
1209 if (!IsLabelScanMode) {
1210 // Match "dag strings" (with mixed "not strings" if any).
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001211 LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001212 if (LastPos == StringRef::npos)
1213 return StringRef::npos;
1214 }
1215
1216 // Match itself from the last position after matching CHECK-DAG.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001217 size_t LastMatchEnd = LastPos;
1218 size_t FirstMatchPos = 0;
1219 // Go match the pattern Count times. Majority of patterns only match with
1220 // count 1 though.
1221 assert(Pat.getCount() != 0 && "pattern count can not be zero");
1222 for (int i = 1; i <= Pat.getCount(); i++) {
1223 StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
1224 size_t CurrentMatchLen;
1225 // get a match at current start point
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001226 size_t MatchPos = Pat.match(MatchBuffer, CurrentMatchLen);
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001227 if (i == 1)
1228 FirstMatchPos = LastPos + MatchPos;
1229
1230 // report
1231 if (MatchPos == StringRef::npos) {
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001232 PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags);
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001233 return StringRef::npos;
1234 }
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001235 PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
1236 Diags);
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001237
1238 // move start point after the match
1239 LastMatchEnd += MatchPos + CurrentMatchLen;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001240 }
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001241 // Full match len counts from first match pos.
1242 MatchLen = LastMatchEnd - FirstMatchPos;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001243
1244 // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
1245 // or CHECK-NOT
1246 if (!IsLabelScanMode) {
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001247 size_t MatchPos = FirstMatchPos - LastPos;
1248 StringRef MatchBuffer = Buffer.substr(LastPos);
1249 StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001250
1251 // If this check is a "CHECK-NEXT", verify that the previous match was on
1252 // the previous line (i.e. that there is one newline between them).
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001253 if (CheckNext(SM, SkippedRegion)) {
Joel E. Dennye2afb612018-12-18 00:03:51 +00001254 ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001255 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
Joel E. Denny7df86962018-12-18 00:03:03 +00001256 Diags, Req.Verbose);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001257 return StringRef::npos;
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001258 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001259
1260 // If this check is a "CHECK-SAME", verify that the previous match was on
1261 // the same line (i.e. that there is no newline between them).
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001262 if (CheckSame(SM, SkippedRegion)) {
Joel E. Dennye2afb612018-12-18 00:03:51 +00001263 ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001264 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
Joel E. Denny7df86962018-12-18 00:03:03 +00001265 Diags, Req.Verbose);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001266 return StringRef::npos;
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001267 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001268
1269 // If this match had "not strings", verify that they don't exist in the
1270 // skipped region.
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001271 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001272 return StringRef::npos;
1273 }
1274
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001275 return FirstMatchPos;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001276}
1277
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001278bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
1279 if (Pat.getCheckTy() != Check::CheckNext &&
1280 Pat.getCheckTy() != Check::CheckEmpty)
1281 return false;
1282
1283 Twine CheckName =
1284 Prefix +
1285 Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");
1286
1287 // Count the number of newlines between the previous match and this one.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001288 const char *FirstNewLine = nullptr;
1289 unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
1290
1291 if (NumNewLines == 0) {
1292 SM.PrintMessage(Loc, SourceMgr::DK_Error,
1293 CheckName + ": is on the same line as previous match");
1294 SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
1295 "'next' match was here");
1296 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
1297 "previous match ended here");
1298 return true;
1299 }
1300
1301 if (NumNewLines != 1) {
1302 SM.PrintMessage(Loc, SourceMgr::DK_Error,
1303 CheckName +
1304 ": is not on the line after the previous match");
1305 SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
1306 "'next' match was here");
1307 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
1308 "previous match ended here");
1309 SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note,
1310 "non-matching line after previous match is here");
1311 return true;
1312 }
1313
1314 return false;
1315}
1316
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001317bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
1318 if (Pat.getCheckTy() != Check::CheckSame)
1319 return false;
1320
1321 // Count the number of newlines between the previous match and this one.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001322 const char *FirstNewLine = nullptr;
1323 unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
1324
1325 if (NumNewLines != 0) {
1326 SM.PrintMessage(Loc, SourceMgr::DK_Error,
1327 Prefix +
1328 "-SAME: is not on the same line as the previous match");
1329 SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
1330 "'next' match was here");
1331 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
1332 "previous match ended here");
1333 return true;
1334 }
1335
1336 return false;
1337}
1338
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001339bool FileCheckString::CheckNot(
1340 const SourceMgr &SM, StringRef Buffer,
1341 const std::vector<const FileCheckPattern *> &NotStrings,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001342 const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001343 for (const FileCheckPattern *Pat : NotStrings) {
1344 assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
1345
1346 size_t MatchLen = 0;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001347 size_t Pos = Pat->match(Buffer, MatchLen);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001348
1349 if (Pos == StringRef::npos) {
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001350 PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001351 Req.VerboseVerbose, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001352 continue;
1353 }
1354
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001355 PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,
1356 Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001357
1358 return true;
1359 }
1360
1361 return false;
1362}
1363
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001364size_t
1365FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
1366 std::vector<const FileCheckPattern *> &NotStrings,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001367 const FileCheckRequest &Req,
1368 std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001369 if (DagNotStrings.empty())
1370 return 0;
1371
1372 // The start of the search range.
1373 size_t StartPos = 0;
1374
1375 struct MatchRange {
1376 size_t Pos;
1377 size_t End;
1378 };
1379 // A sorted list of ranges for non-overlapping CHECK-DAG matches. Match
1380 // ranges are erased from this list once they are no longer in the search
1381 // range.
1382 std::list<MatchRange> MatchRanges;
1383
1384 // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG
1385 // group, so we don't use a range-based for loop here.
1386 for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
1387 PatItr != PatEnd; ++PatItr) {
1388 const FileCheckPattern &Pat = *PatItr;
1389 assert((Pat.getCheckTy() == Check::CheckDAG ||
1390 Pat.getCheckTy() == Check::CheckNot) &&
1391 "Invalid CHECK-DAG or CHECK-NOT!");
1392
1393 if (Pat.getCheckTy() == Check::CheckNot) {
1394 NotStrings.push_back(&Pat);
1395 continue;
1396 }
1397
1398 assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");
1399
1400 // CHECK-DAG always matches from the start.
1401 size_t MatchLen = 0, MatchPos = StartPos;
1402
1403 // Search for a match that doesn't overlap a previous match in this
1404 // CHECK-DAG group.
1405 for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
1406 StringRef MatchBuffer = Buffer.substr(MatchPos);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001407 size_t MatchPosBuf = Pat.match(MatchBuffer, MatchLen);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001408 // With a group of CHECK-DAGs, a single mismatching means the match on
1409 // that group of CHECK-DAGs fails immediately.
1410 if (MatchPosBuf == StringRef::npos) {
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001411 PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001412 Req.VerboseVerbose, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001413 return StringRef::npos;
1414 }
1415 // Re-calc it as the offset relative to the start of the original string.
1416 MatchPos += MatchPosBuf;
1417 if (Req.VerboseVerbose)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001418 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
1419 MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001420 MatchRange M{MatchPos, MatchPos + MatchLen};
1421 if (Req.AllowDeprecatedDagOverlap) {
1422 // We don't need to track all matches in this mode, so we just maintain
1423 // one match range that encompasses the current CHECK-DAG group's
1424 // matches.
1425 if (MatchRanges.empty())
1426 MatchRanges.insert(MatchRanges.end(), M);
1427 else {
1428 auto Block = MatchRanges.begin();
1429 Block->Pos = std::min(Block->Pos, M.Pos);
1430 Block->End = std::max(Block->End, M.End);
1431 }
1432 break;
1433 }
1434 // Iterate previous matches until overlapping match or insertion point.
1435 bool Overlap = false;
1436 for (; MI != ME; ++MI) {
1437 if (M.Pos < MI->End) {
1438 // !Overlap => New match has no overlap and is before this old match.
1439 // Overlap => New match overlaps this old match.
1440 Overlap = MI->Pos < M.End;
1441 break;
1442 }
1443 }
1444 if (!Overlap) {
1445 // Insert non-overlapping match into list.
1446 MatchRanges.insert(MI, M);
1447 break;
1448 }
1449 if (Req.VerboseVerbose) {
Joel E. Denny352695c2019-01-22 21:41:42 +00001450 // Due to their verbosity, we don't print verbose diagnostics here if
1451 // we're gathering them for a different rendering, but we always print
1452 // other diagnostics.
1453 if (!Diags) {
1454 SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);
1455 SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);
1456 SMRange OldRange(OldStart, OldEnd);
1457 SM.PrintMessage(OldStart, SourceMgr::DK_Note,
1458 "match discarded, overlaps earlier DAG match here",
1459 {OldRange});
1460 } else
Joel E. Dennye2afb612018-12-18 00:03:51 +00001461 Diags->rbegin()->MatchTy = FileCheckDiag::MatchFoundButDiscarded;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001462 }
1463 MatchPos = MI->End;
1464 }
1465 if (!Req.VerboseVerbose)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001466 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
1467 MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001468
1469 // Handle the end of a CHECK-DAG group.
1470 if (std::next(PatItr) == PatEnd ||
1471 std::next(PatItr)->getCheckTy() == Check::CheckNot) {
1472 if (!NotStrings.empty()) {
1473 // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
1474 // CHECK-DAG, verify that there are no 'not' strings occurred in that
1475 // region.
1476 StringRef SkippedRegion =
1477 Buffer.slice(StartPos, MatchRanges.begin()->Pos);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001478 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001479 return StringRef::npos;
1480 // Clear "not strings".
1481 NotStrings.clear();
1482 }
1483 // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the
1484 // end of this CHECK-DAG group's match range.
1485 StartPos = MatchRanges.rbegin()->End;
1486 // Don't waste time checking for (impossible) overlaps before that.
1487 MatchRanges.clear();
1488 }
1489 }
1490
1491 return StartPos;
1492}
1493
1494// A check prefix must contain only alphanumeric, hyphens and underscores.
1495static bool ValidateCheckPrefix(StringRef CheckPrefix) {
1496 Regex Validator("^[a-zA-Z0-9_-]*$");
1497 return Validator.match(CheckPrefix);
1498}
1499
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +00001500bool FileCheck::ValidateCheckPrefixes() {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001501 StringSet<> PrefixSet;
1502
1503 for (StringRef Prefix : Req.CheckPrefixes) {
1504 // Reject empty prefixes.
1505 if (Prefix == "")
1506 return false;
1507
1508 if (!PrefixSet.insert(Prefix).second)
1509 return false;
1510
1511 if (!ValidateCheckPrefix(Prefix))
1512 return false;
1513 }
1514
1515 return true;
1516}
1517
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +00001518Regex FileCheck::buildCheckPrefixRegex() {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001519 // I don't think there's a way to specify an initial value for cl::list,
1520 // so if nothing was specified, add the default
1521 if (Req.CheckPrefixes.empty())
1522 Req.CheckPrefixes.push_back("CHECK");
1523
1524 // We already validated the contents of CheckPrefixes so just concatenate
1525 // them as alternatives.
1526 SmallString<32> PrefixRegexStr;
1527 for (StringRef Prefix : Req.CheckPrefixes) {
1528 if (Prefix != Req.CheckPrefixes.front())
1529 PrefixRegexStr.push_back('|');
1530
1531 PrefixRegexStr.append(Prefix);
1532 }
1533
1534 return Regex(PrefixRegexStr);
1535}
1536
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001537bool FileCheckPatternContext::defineCmdlineVariables(
1538 std::vector<std::string> &CmdlineDefines, SourceMgr &SM) {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001539 assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001540 "Overriding defined variable with command-line variable definitions");
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001541
1542 if (CmdlineDefines.empty())
1543 return false;
1544
1545 // Create a string representing the vector of command-line definitions. Each
1546 // definition is on its own line and prefixed with a definition number to
1547 // clarify which definition a given diagnostic corresponds to.
1548 unsigned I = 0;
1549 bool ErrorFound = false;
1550 std::string CmdlineDefsDiag;
1551 StringRef Prefix1 = "Global define #";
1552 StringRef Prefix2 = ": ";
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001553 for (StringRef CmdlineDef : CmdlineDefines)
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001554 CmdlineDefsDiag +=
1555 (Prefix1 + Twine(++I) + Prefix2 + CmdlineDef + "\n").str();
1556
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001557 // Create a buffer with fake command line content in order to display
1558 // parsing diagnostic with location information and point to the
1559 // global definition with invalid syntax.
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001560 std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer =
1561 MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines");
1562 StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
1563 SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
1564
1565 SmallVector<StringRef, 4> CmdlineDefsDiagVec;
1566 CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/,
1567 false /*KeepEmpty*/);
1568 for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001569 unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();
1570 StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);
1571 if (CmdlineDef.find('=') == StringRef::npos) {
1572 SM.PrintMessage(SMLoc::getFromPointer(CmdlineDef.data()),
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001573 SourceMgr::DK_Error,
1574 "Missing equal sign in global definition");
1575 ErrorFound = true;
1576 continue;
1577 }
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001578
1579 // Numeric variable definition.
1580 if (CmdlineDef[0] == '#') {
1581 bool IsPseudo;
1582 unsigned TrailIdx;
1583 size_t EqIdx = CmdlineDef.find('=');
1584 StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
1585 if (FileCheckPattern::parseVariable(CmdlineName, IsPseudo, TrailIdx) ||
1586 IsPseudo || TrailIdx != CmdlineName.size() || CmdlineName.empty()) {
1587 SM.PrintMessage(SMLoc::getFromPointer(CmdlineName.data()),
1588 SourceMgr::DK_Error,
1589 "invalid name in numeric variable definition '" +
1590 CmdlineName + "'");
1591 ErrorFound = true;
1592 continue;
1593 }
1594
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001595 // Detect collisions between string and numeric variables when the latter
1596 // is created later than the former.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001597 if (DefinedVariableTable.find(CmdlineName) !=
1598 DefinedVariableTable.end()) {
1599 SM.PrintMessage(
1600 SMLoc::getFromPointer(CmdlineName.data()), SourceMgr::DK_Error,
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001601 "string variable with name '" + CmdlineName + "' already exists");
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001602 ErrorFound = true;
1603 continue;
1604 }
1605
1606 StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1);
1607 uint64_t Val;
1608 if (CmdlineVal.getAsInteger(10, Val)) {
1609 SM.PrintMessage(SMLoc::getFromPointer(CmdlineVal.data()),
1610 SourceMgr::DK_Error,
1611 "invalid value in numeric variable definition '" +
1612 CmdlineVal + "'");
1613 ErrorFound = true;
1614 continue;
1615 }
1616 auto DefinedNumericVariable = makeNumericVariable(CmdlineName, Val);
1617
1618 // Record this variable definition.
1619 GlobalNumericVariableTable[CmdlineName] = DefinedNumericVariable;
1620 } else {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001621 // String variable definition.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001622 std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
1623 StringRef Name = CmdlineNameVal.first;
1624 bool IsPseudo;
1625 unsigned TrailIdx;
1626 if (FileCheckPattern::parseVariable(Name, IsPseudo, TrailIdx) ||
1627 IsPseudo || TrailIdx != Name.size() || Name.empty()) {
1628 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001629 "invalid name in string variable definition '" + Name +
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001630 "'");
1631 ErrorFound = true;
1632 continue;
1633 }
1634
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001635 // Detect collisions between string and numeric variables when the former
1636 // is created later than the latter.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001637 if (GlobalNumericVariableTable.find(Name) !=
1638 GlobalNumericVariableTable.end()) {
1639 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
1640 "numeric variable with name '" + Name +
1641 "' already exists");
1642 ErrorFound = true;
1643 continue;
1644 }
1645 GlobalVariableTable.insert(CmdlineNameVal);
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001646 // Mark the string variable as defined to detect collisions between
1647 // string and numeric variables in DefineCmdlineVariables when the latter
1648 // is created later than the former. We cannot reuse GlobalVariableTable
1649 // for that by populating it with an empty string since we would then
1650 // lose the ability to detect the use of an undefined variable in
1651 // match().
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001652 DefinedVariableTable[Name] = true;
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001653 }
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001654 }
1655
1656 return ErrorFound;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001657}
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001658
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001659void FileCheckPatternContext::clearLocalVars() {
1660 SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars;
1661 for (const StringMapEntry<StringRef> &Var : GlobalVariableTable)
1662 if (Var.first()[0] != '$')
1663 LocalPatternVars.push_back(Var.first());
1664
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001665 // Numeric substitution reads the value of a variable directly, not via
1666 // GlobalNumericVariableTable. Therefore, we clear local variables by
1667 // clearing their value which will lead to a numeric substitution failure. We
1668 // also mark the variable for removal from GlobalNumericVariableTable since
1669 // this is what defineCmdlineVariables checks to decide that no global
1670 // variable has been defined.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001671 for (const auto &Var : GlobalNumericVariableTable)
1672 if (Var.first()[0] != '$') {
1673 Var.getValue()->clearValue();
1674 LocalNumericVars.push_back(Var.first());
1675 }
1676
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001677 for (const auto &Var : LocalPatternVars)
1678 GlobalVariableTable.erase(Var);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001679 for (const auto &Var : LocalNumericVars)
1680 GlobalNumericVariableTable.erase(Var);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001681}
1682
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +00001683bool FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
1684 ArrayRef<FileCheckString> CheckStrings,
1685 std::vector<FileCheckDiag> *Diags) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001686 bool ChecksFailed = false;
1687
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001688 unsigned i = 0, j = 0, e = CheckStrings.size();
1689 while (true) {
1690 StringRef CheckRegion;
1691 if (j == e) {
1692 CheckRegion = Buffer;
1693 } else {
1694 const FileCheckString &CheckLabelStr = CheckStrings[j];
1695 if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {
1696 ++j;
1697 continue;
1698 }
1699
1700 // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
1701 size_t MatchLabelLen = 0;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001702 size_t MatchLabelPos =
1703 CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001704 if (MatchLabelPos == StringRef::npos)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001705 // Immediately bail if CHECK-LABEL fails, nothing else we can do.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001706 return false;
1707
1708 CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
1709 Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);
1710 ++j;
1711 }
1712
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001713 // Do not clear the first region as it's the one before the first
1714 // CHECK-LABEL and it would clear variables defined on the command-line
1715 // before they get used.
1716 if (i != 0 && Req.EnableVarScope)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001717 PatternContext.clearLocalVars();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001718
1719 for (; i != j; ++i) {
1720 const FileCheckString &CheckStr = CheckStrings[i];
1721
1722 // Check each string within the scanned region, including a second check
1723 // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
1724 size_t MatchLen = 0;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001725 size_t MatchPos =
1726 CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001727
1728 if (MatchPos == StringRef::npos) {
1729 ChecksFailed = true;
1730 i = j;
1731 break;
1732 }
1733
1734 CheckRegion = CheckRegion.substr(MatchPos + MatchLen);
1735 }
1736
1737 if (j == e)
1738 break;
1739 }
1740
1741 // Success if no checks failed.
1742 return !ChecksFailed;
1743}