llvm.org GIT mirror llvm / 2ae8615
FileCheck: Return parse error w/ Error & Expected Summary: Make use of Error and Expected to bubble up diagnostics and force checking of errors in the callers. Reviewers: jhenderson, jdenny, probinson, arichardson Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D63125 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363900 91177308-0d34-0410-b5e6-96231b3b80d8 Thomas Preud'homme 29 days ago
5 changed file(s) with 503 addition(s) and 441 deletion(s). Raw diff Collapse all Expand all
8686 /// Type of functions evaluating a given binary operation.
8787 using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
8888
89 /// Class to represent an undefined variable error which prints that variable's
90 /// name between quotes when printed.
91 class FileCheckUndefVarError : public ErrorInfo {
92 private:
93 StringRef VarName;
94
95 public:
96 static char ID;
97
98 FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}
99
100 StringRef getVarName() const { return VarName; }
101
102 std::error_code convertToErrorCode() const override {
103 return inconvertibleErrorCode();
104 }
105
106 /// Print name of variable associated with this error.
107 void log(raw_ostream &OS) const override {
108 OS << "\"";
109 OS.write_escaped(VarName) << "\"";
110 }
111 };
112
89113 /// Class representing a numeric expression consisting of either a single
90114 /// numeric variable or a binary operation between a numeric variable and an
91115 /// immediate.
106130 : LeftOp(OperandLeft), RightOp(OperandRight), EvalBinop(EvalBinop) {}
107131
108132 /// Evaluates the value of this numeric expression, using EvalBinop to
109 /// perform the binary operation it consists of. \returns None if the numeric
110 /// variable used is undefined, or the expression value otherwise.
111 Optional eval() const;
112
113 /// \returns the name of the undefined variable used in this expression if
114 /// any or an empty string otherwise.
115 StringRef getUndefVarName() const;
133 /// perform the binary operation it consists of. \returns an error if the
134 /// numeric variable used is undefined, or the expression value otherwise.
135 Expected eval() const;
116136 };
117137
118138 class FileCheckPatternContext;
150170 size_t getIndex() const { return InsertIdx; }
151171
152172 /// \returns a string containing the result of the substitution represented
153 /// by this class instance or None if substitution failed.
154 virtual Optional getResult() const = 0;
155
156 /// \returns the name of the variable used in this substitution if undefined,
157 /// or an empty string otherwise.
158 virtual StringRef getUndefVarName() const = 0;
173 /// by this class instance or an error if substitution failed.
174 virtual Expected getResult() const = 0;
159175 };
160176
161177 class FileCheckStringSubstitution : public FileCheckSubstitution {
165181 : FileCheckSubstitution(Context, VarName, InsertIdx) {}
166182
167183 /// \returns the text that the string variable in this substitution matched
168 /// when defined, or None if the variable is undefined.
169 Optional getResult() const override;
170
171 /// \returns the name of the string variable used in this substitution if
172 /// undefined, or an empty string otherwise.
173 StringRef getUndefVarName() const override;
184 /// when defined, or an error if the variable is undefined.
185 Expected getResult() const override;
174186 };
175187
176188 class FileCheckNumericSubstitution : public FileCheckSubstitution {
185197 : FileCheckSubstitution(Context, Expr, InsertIdx), NumExpr(NumExpr) {}
186198
187199 /// \returns a string containing the result of evaluating the numeric
188 /// expression in this substitution, or None if evaluation failed.
189 Optional getResult() const override;
190
191 /// \returns the name of the numeric variable used in this substitution if
192 /// undefined, or an empty string otherwise.
193 StringRef getUndefVarName() const override;
200 /// expression in this substitution, or an error if evaluation failed.
201 Expected getResult() const override;
194202 };
195203
196204 //===----------------------------------------------------------------------===//
281289 std::vector> Substitutions;
282290
283291 public:
284 /// \returns the value of string variable \p VarName or None if no such
292 /// \returns the value of string variable \p VarName or an error if no such
285293 /// variable has been defined.
286 Optional getPatternVarValue(StringRef VarName);
294 Expected getPatternVarValue(StringRef VarName);
287295
288296 /// Defines string and numeric variables from definitions given on the
289297 /// command line, passed as a vector of [#]VAR=VAL strings in
290 /// \p CmdlineDefines. Reports any error to \p SM and \returns whether an
291 /// error occured.
292 bool defineCmdlineVariables(std::vector &CmdlineDefines,
293 SourceMgr &SM);
298 /// \p CmdlineDefines. \returns an error list containing diagnostics against
299 /// \p SM for all definition parsing failures, if any, or Success otherwise.
300 Error defineCmdlineVariables(std::vector &CmdlineDefines,
301 SourceMgr &SM);
294302
295303 /// Undefines local variables (variables whose name does not start with a '$'
296304 /// sign), i.e. removes them from GlobalVariableTable and from
320328 FileCheckSubstitution *makeNumericSubstitution(StringRef Expr,
321329 FileCheckNumExpr *NumExpr,
322330 size_t InsertIdx);
331 };
332
333 /// Class to represent an error holding a diagnostic with location information
334 /// used when printing it.
335 class FileCheckErrorDiagnostic : public ErrorInfo {
336 private:
337 SMDiagnostic Diagnostic;
338
339 public:
340 static char ID;
341
342 FileCheckErrorDiagnostic(SMDiagnostic &&Diag) : Diagnostic(Diag) {}
343
344 std::error_code convertToErrorCode() const override {
345 return inconvertibleErrorCode();
346 }
347
348 /// Print diagnostic associated with this error when printing the error.
349 void log(raw_ostream &OS) const override { Diagnostic.print(nullptr, OS); }
350
351 static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg) {
352 return make_error(
353 SM.GetMessage(Loc, SourceMgr::DK_Error, ErrMsg));
354 }
355
356 static Error get(const SourceMgr &SM, StringRef Buffer, const Twine &ErrMsg) {
357 return get(SM, SMLoc::getFromPointer(Buffer.data()), ErrMsg);
358 }
359 };
360
361 class FileCheckNotFoundError : public ErrorInfo {
362 public:
363 static char ID;
364
365 std::error_code convertToErrorCode() const override {
366 return inconvertibleErrorCode();
367 }
368
369 /// Print diagnostic associated with this error when printing the error.
370 void log(raw_ostream &OS) const override {
371 OS << "String not found in input";
372 }
323373 };
324374
325375 class FileCheckPattern {
402452
403453 /// \returns whether \p C is a valid first character for a variable name.
404454 static bool isValidVarNameStart(char C);
405 /// Parses the string at the start of \p Str for a variable name and \returns
406 /// whether the variable name is ill-formed. If parsing succeeded, sets
407 /// \p IsPseudo to indicate if it is a pseudo variable, sets \p Name to the
408 /// parsed variable name and strips \p Str from the variable name.
409 static bool parseVariable(StringRef &Str, StringRef &Name, bool &IsPseudo);
410 /// Parses \p Expr for the definition of a numeric variable, returning an
411 /// error if \p Context already holds a string variable with the same name.
412 /// \returns whether parsing fails, in which case errors are reported on
413 /// \p SM. Otherwise, sets \p Name to the name of the parsed numeric
414 /// variable.
415 static bool parseNumericVariableDefinition(StringRef &Expr, StringRef &Name,
416 FileCheckPatternContext *Context,
417 const SourceMgr &SM);
455 /// Parses the string at the start of \p Str for a variable name. \returns
456 /// an error holding a diagnostic against \p SM if parsing fail, or the
457 /// name of the variable otherwise. In the latter case, sets \p IsPseudo to
458 /// indicate if it is a pseudo variable and strips \p Str from the variable
459 /// name.
460 static Expected parseVariable(StringRef &Str, bool &IsPseudo,
461 const SourceMgr &SM);
462 /// Parses \p Expr for the name of a numeric variable to be defined. \returns
463 /// an error holding a diagnostic against \p SM should defining such a
464 /// variable be invalid, or Success otherwise. In the latter case, sets
465 /// \p Name to the name of the parsed numeric variable name.
466 static Error parseNumericVariableDefinition(StringRef &Expr, StringRef &Name,
467 FileCheckPatternContext *Context,
468 const SourceMgr &SM);
418469 /// Parses \p Expr for a numeric substitution block. \returns the class
419470 /// representing the AST of the numeric expression whose value must be
420 /// substituted, or nullptr if parsing fails, in which case errors are
421 /// reported on \p SM. Sets \p DefinedNumericVariable to point to the class
422 /// representing the numeric variable defined in this numeric substitution
423 /// block, or nullptr if this block does not define any variable.
424 FileCheckNumExpr *parseNumericSubstitutionBlock(
425 StringRef Expr, FileCheckNumericVariable *&DefinedNumericVariable,
471 /// substituted, or an error holding a diagnostic against \p SM if parsing
472 /// fails. If substitution was successful, sets \p DefinedNumericVariable to
473 /// point to the class representing the numeric variable defined in this
474 /// numeric substitution block, or None if this block does not define any
475 /// variable.
476 Expected parseNumericSubstitutionBlock(
477 StringRef Expr,
478 Optional &DefinedNumericVariable,
426479 const SourceMgr &SM) const;
427480 /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
428481 /// instance accordingly.
435488 const FileCheckRequest &Req);
436489 /// Matches the pattern string against the input buffer \p Buffer
437490 ///
438 /// \returns the position that is matched or npos if there is no match. If
439 /// there is a match, updates \p MatchLen with the size of the matched
440 /// string.
491 /// \returns the position that is matched or an error indicating why matching
492 /// failed. If there is a match, updates \p MatchLen with the size of the
493 /// matched string.
441494 ///
442495 /// The GlobalVariableTable StringMap in the FileCheckPatternContext class
443496 /// instance provides the current values of FileCheck string variables and
445498 /// GlobalNumericVariableTable StringMap in the same class provides the
446499 /// current values of FileCheck numeric variables and is updated if this
447500 /// match defines new numeric values.
448 size_t match(StringRef Buffer, size_t &MatchLen, const SourceMgr &SM) const;
501 Expected match(StringRef Buffer, size_t &MatchLen,
502 const SourceMgr &SM) const;
449503 /// Prints the value of successful substitutions or the name of the undefined
450504 /// string or numeric variable preventing a successful substitution.
451505 void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
477531 size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
478532
479533 /// Parses \p Expr for the use of a numeric variable. \returns the pointer to
480 /// the class instance representing that variable if successful, or nullptr
481 /// otherwise, in which case errors are reported on \p SM.
482 FileCheckNumericVariable *parseNumericVariableUse(StringRef &Expr,
483 const SourceMgr &SM) const;
534 /// the class instance representing that variable if successful, or an error
535 /// holding a diagnostic against \p SM otherwise.
536 Expected
537 parseNumericVariableUse(StringRef &Expr, const SourceMgr &SM) const;
484538 /// Parses \p Expr for a binary operation.
485539 /// \returns the class representing the binary operation of the numeric
486 /// expression, or nullptr if parsing fails, in which case errors are
487 /// reported on \p SM.
488 FileCheckNumExpr *parseBinop(StringRef &Expr, const SourceMgr &SM) const;
540 /// expression, or an error holding a diagnostic against \p SM otherwise.
541 Expected parseBinop(StringRef &Expr,
542 const SourceMgr &SM) const;
489543 };
490544
491545 //===----------------------------------------------------------------------===//
3737 return false;
3838 }
3939
40 Optional FileCheckNumExpr::eval() const {
40 Expected FileCheckNumExpr::eval() const {
4141 assert(LeftOp && "Evaluating an empty numeric expression");
4242 Optional LeftOpValue = LeftOp->getValue();
4343 // Variable is undefined.
4444 if (!LeftOpValue)
45 return None;
45 return make_error(LeftOp->getName());
4646 return EvalBinop(*LeftOpValue, RightOp);
4747 }
4848
49 StringRef FileCheckNumExpr::getUndefVarName() const {
50 if (!LeftOp->getValue())
51 return LeftOp->getName();
52 return StringRef();
53 }
54
55 Optional FileCheckNumericSubstitution::getResult() const {
56 Optional EvaluatedValue = NumExpr->eval();
49 Expected FileCheckNumericSubstitution::getResult() const {
50 Expected EvaluatedValue = NumExpr->eval();
5751 if (!EvaluatedValue)
58 return None;
52 return EvaluatedValue.takeError();
5953 return utostr(*EvaluatedValue);
6054 }
6155
62 Optional FileCheckStringSubstitution::getResult() const {
56 Expected FileCheckStringSubstitution::getResult() const {
6357 // Look up the value and escape it so that we can put it into the regex.
64 Optional VarVal = Context->getPatternVarValue(FromStr);
58 Expected VarVal = Context->getPatternVarValue(FromStr);
6559 if (!VarVal)
66 return None;
60 return VarVal.takeError();
6761 return Regex::escape(*VarVal);
68 }
69
70 StringRef 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 }
75
76 StringRef FileCheckStringSubstitution::getUndefVarName() const {
77 if (!Context->getPatternVarValue(FromStr))
78 return FromStr;
79
80 return StringRef();
8162 }
8263
8364 bool FileCheckPattern::isValidVarNameStart(char C) {
8465 return C == '_' || isalpha(C);
8566 }
8667
87 bool FileCheckPattern::parseVariable(StringRef &Str, StringRef &Name,
88 bool &IsPseudo) {
68 Expected FileCheckPattern::parseVariable(StringRef &Str,
69 bool &IsPseudo,
70 const SourceMgr &SM) {
8971 if (Str.empty())
90 return true;
72 return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");
9173
9274 bool ParsedOneChar = false;
9375 unsigned I = 0;
9981
10082 for (unsigned E = Str.size(); I != E; ++I) {
10183 if (!ParsedOneChar && !isValidVarNameStart(Str[I]))
102 return true;
84 return FileCheckErrorDiagnostic::get(SM, Str, "invalid variable name");
10385
10486 // Variable names are composed of alphanumeric characters and underscores.
10587 if (Str[I] != '_' && !isalnum(Str[I]))
10789 ParsedOneChar = true;
10890 }
10991
110 Name = Str.take_front(I);
92 StringRef Name = Str.take_front(I);
11193 Str = Str.substr(I);
112 return false;
94 return Name;
11395 }
11496
11597 // StringRef holding all characters considered as horizontal whitespaces by
123105 return C;
124106 }
125107
126 bool FileCheckPattern::parseNumericVariableDefinition(
108 char FileCheckUndefVarError::ID = 0;
109 char FileCheckErrorDiagnostic::ID = 0;
110 char FileCheckNotFoundError::ID = 0;
111
112 Error FileCheckPattern::parseNumericVariableDefinition(
127113 StringRef &Expr, StringRef &Name, FileCheckPatternContext *Context,
128114 const SourceMgr &SM) {
129115 bool IsPseudo;
130 if (parseVariable(Expr, Name, IsPseudo)) {
131 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
132 "invalid variable name");
133 return true;
134 }
135
136 if (IsPseudo) {
137 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
138 "definition of pseudo numeric variable unsupported");
139 return true;
140 }
116 Expected ParseVarResult = parseVariable(Expr, IsPseudo, SM);
117 if (!ParseVarResult)
118 return ParseVarResult.takeError();
119 Name = *ParseVarResult;
120
121 if (IsPseudo)
122 return FileCheckErrorDiagnostic::get(
123 SM, Name, "definition of pseudo numeric variable unsupported");
141124
142125 // Detect collisions between string and numeric variables when the latter
143126 // is created later than the former.
144127 if (Context->DefinedVariableTable.find(Name) !=
145 Context->DefinedVariableTable.end()) {
146 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
147 "string variable with name '" + Name + "' already exists");
148 return true;
149 }
150
151 return false;
152 }
153
154 FileCheckNumericVariable *
128 Context->DefinedVariableTable.end())
129 return FileCheckErrorDiagnostic::get(
130 SM, Name, "string variable with name '" + Name + "' already exists");
131
132 return Error::success();
133 }
134
135 Expected
155136 FileCheckPattern::parseNumericVariableUse(StringRef &Expr,
156137 const SourceMgr &SM) const {
157138 bool IsPseudo;
158 StringRef Name;
159 if (parseVariable(Expr, Name, IsPseudo)) {
160 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
161 "invalid variable name");
162 return nullptr;
163 }
164
165 if (IsPseudo && !Name.equals("@LINE")) {
166 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
167 "invalid pseudo numeric variable '" + Name + "'");
168 return nullptr;
169 }
139 Expected ParseVarResult = parseVariable(Expr, IsPseudo, SM);
140 if (!ParseVarResult)
141 return ParseVarResult.takeError();
142 StringRef Name = *ParseVarResult;
143
144 if (IsPseudo && !Name.equals("@LINE"))
145 return FileCheckErrorDiagnostic::get(
146 SM, Name, "invalid pseudo numeric variable '" + Name + "'");
170147
171148 // This method is indirectly called from parsePattern for all numeric
172149 // variable definitions and uses in the order in which they appear in the
175152 // GlobalNumericVariableTable. Therefore, the pointer we get below is for the
176153 // class instance corresponding to the last definition of this variable use.
177154 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
178 if (VarTableIter == Context->GlobalNumericVariableTable.end()) {
179 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
180 "using undefined numeric variable '" + Name + "'");
181 return nullptr;
182 }
155 if (VarTableIter == Context->GlobalNumericVariableTable.end())
156 return FileCheckErrorDiagnostic::get(
157 SM, Name, "using undefined numeric variable '" + Name + "'");
183158
184159 FileCheckNumericVariable *NumericVariable = VarTableIter->second;
185 if (!IsPseudo && NumericVariable->getDefLineNumber() == LineNumber) {
186 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
187 "numeric variable '" + Name +
188 "' defined on the same line as used");
189 return nullptr;
190 }
160 if (!IsPseudo && NumericVariable->getDefLineNumber() == LineNumber)
161 return FileCheckErrorDiagnostic::get(
162 SM, Name,
163 "numeric variable '" + Name + "' defined on the same line as used");
191164
192165 return NumericVariable;
193166 }
200173 return LeftOp - RightOp;
201174 }
202175
203 FileCheckNumExpr *FileCheckPattern::parseBinop(StringRef &Expr,
204 const SourceMgr &SM) const {
205 FileCheckNumericVariable *LeftOp = parseNumericVariableUse(Expr, SM);
206 if (!LeftOp) {
207 // Error reporting done in parseNumericVariableUse().
208 return nullptr;
209 }
176 Expected
177 FileCheckPattern::parseBinop(StringRef &Expr, const SourceMgr &SM) const {
178 Expected LeftParseResult =
179 parseNumericVariableUse(Expr, SM);
180 if (!LeftParseResult) {
181 return LeftParseResult.takeError();
182 }
183 FileCheckNumericVariable *LeftOp = *LeftParseResult;
210184
211185 // Check if this is a supported operation and select a function to perform
212186 // it.
224198 EvalBinop = sub;
225199 break;
226200 default:
227 SM.PrintMessage(OpLoc, SourceMgr::DK_Error,
228 Twine("unsupported numeric operation '") + Twine(Operator) +
229 "'");
230 return nullptr;
201 return FileCheckErrorDiagnostic::get(
202 SM, OpLoc,
203 Twine("unsupported numeric operation '") + Twine(Operator) + "'");
231204 }
232205
233206 // Parse right operand.
234207 Expr = Expr.ltrim(SpaceChars);
235 if (Expr.empty()) {
236 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
237 "missing operand in numeric expression");
238 return nullptr;
239 }
208 if (Expr.empty())
209 return FileCheckErrorDiagnostic::get(
210 SM, Expr, "missing operand in numeric expression");
240211 uint64_t RightOp;
241 if (Expr.consumeInteger(10, RightOp)) {
242 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
243 "invalid offset in numeric expression '" + Expr + "'");
244 return nullptr;
245 }
212 if (Expr.consumeInteger(10, RightOp))
213 return FileCheckErrorDiagnostic::get(
214 SM, Expr, "invalid offset in numeric expression '" + Expr + "'");
246215 Expr = Expr.ltrim(SpaceChars);
247 if (!Expr.empty()) {
248 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
249 "unexpected characters at end of numeric expression '" +
250 Expr + "'");
251 return nullptr;
252 }
216 if (!Expr.empty())
217 return FileCheckErrorDiagnostic::get(
218 SM, Expr,
219 "unexpected characters at end of numeric expression '" + Expr + "'");
253220
254221 return Context->makeNumExpr(EvalBinop, LeftOp, RightOp);
255222 }
256223
257 FileCheckNumExpr *FileCheckPattern::parseNumericSubstitutionBlock(
258 StringRef Expr, FileCheckNumericVariable *&DefinedNumericVariable,
224 Expected FileCheckPattern::parseNumericSubstitutionBlock(
225 StringRef Expr,
226 Optional &DefinedNumericVariable,
259227 const SourceMgr &SM) const {
260228 // Parse the numeric variable definition.
261 DefinedNumericVariable = nullptr;
229 DefinedNumericVariable = None;
262230 size_t DefEnd = Expr.find(':');
263231 if (DefEnd != StringRef::npos) {
264232 StringRef DefExpr = Expr.substr(0, DefEnd);
266234
267235 DefExpr = DefExpr.ltrim(SpaceChars);
268236 StringRef Name;
269 if (parseNumericVariableDefinition(DefExpr, Name, Context, SM)) {
270 // Invalid variable definition. Error reporting done in parsing function.
271 return nullptr;
272 }
237 Error ErrorDiagnostic =
238 parseNumericVariableDefinition(DefExpr, Name, Context, SM);
239 if (ErrorDiagnostic)
240 return std::move(ErrorDiagnostic);
273241
274242 DefinedNumericVariable =
275243 Context->makeNumericVariable(this->LineNumber, Name);
276244
277245 DefExpr = DefExpr.ltrim(SpaceChars);
278 if (!DefExpr.empty()) {
279 SM.PrintMessage(SMLoc::getFromPointer(DefExpr.data()),
280 SourceMgr::DK_Error,
281 "invalid numeric variable definition");
282 return nullptr;
283 }
246 if (!DefExpr.empty())
247 return FileCheckErrorDiagnostic::get(
248 SM, DefExpr, "invalid numeric variable definition");
284249 UseExpr = UseExpr.ltrim(SpaceChars);
285 if (!UseExpr.empty()) {
286 SM.PrintMessage(
287 SMLoc::getFromPointer(UseExpr.data()), SourceMgr::DK_Error,
250 if (!UseExpr.empty())
251 return FileCheckErrorDiagnostic::get(
252 SM, UseExpr,
288253 "unexpected string after variable definition: '" + UseExpr + "'");
289 return nullptr;
290 }
291254 return Context->makeNumExpr(add, nullptr, 0);
292255 }
293256
428391
429392 // Get the name (e.g. "foo") and verify it is well formed.
430393 bool IsPseudo;
431 StringRef Name;
432394 StringRef OrigMatchStr = MatchStr;
433 if (parseVariable(MatchStr, Name, IsPseudo)) {
434 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
435 SourceMgr::DK_Error, "invalid variable name");
395 Expected ParseVarResult =
396 parseVariable(MatchStr, IsPseudo, SM);
397 if (!ParseVarResult) {
398 logAllUnhandledErrors(ParseVarResult.takeError(), errs());
436399 return true;
437400 }
401 StringRef Name = *ParseVarResult;
438402
439403 IsDefinition = (VarEndIdx != StringRef::npos);
440404 if (IsDefinition) {
467431
468432 // Parse numeric substitution block.
469433 FileCheckNumExpr *NumExpr;
470 FileCheckNumericVariable *DefinedNumericVariable;
434 Optional DefinedNumericVariable;
471435 if (IsNumBlock) {
472 NumExpr =
436 Expected ParseResult =
473437 parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, SM);
474 if (NumExpr == nullptr)
438 if (!ParseResult) {
439 logAllUnhandledErrors(ParseResult.takeError(), errs());
475440 return true;
441 }
442 NumExpr = *ParseResult;
476443 if (DefinedNumericVariable) {
477444 IsDefinition = true;
478 DefName = DefinedNumericVariable->getName();
445 DefName = (*DefinedNumericVariable)->getName();
479446 MatchRegexp = StringRef("[0-9]+");
480447 } else
481448 SubstStr = MatchStr;
512479 // Handle variable definitions: [[:(...)]] and
513480 // [[#(...):(...)]].
514481 if (IsNumBlock) {
515 FileCheckNumExprMatch NumExprDef = {DefinedNumericVariable, CurParen};
482 FileCheckNumExprMatch NumExprDef = {*DefinedNumericVariable, CurParen};
516483 NumericVariableDefs[DefName] = NumExprDef;
517484 // This store is done here rather than in match() to allow
518485 // parseNumericVariableUse() to get the pointer to the class instance
519486 // of the right variable definition corresponding to a given numeric
520487 // variable use.
521 Context->GlobalNumericVariableTable[DefName] = DefinedNumericVariable;
488 Context->GlobalNumericVariableTable[DefName] = *DefinedNumericVariable;
522489 } else {
523490 VariableDefs[DefName] = CurParen;
524491 // Mark the string variable as defined to detect collisions between
575542 RegExStr += Backref;
576543 }
577544
578 size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
579 const SourceMgr &SM) const {
545 Expected FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
546 const SourceMgr &SM) const {
580547 // If this is the EOF pattern, match it immediately.
581548 if (CheckTy == Check::CheckEOF) {
582549 MatchLen = 0;
586553 // If this is a fixed string pattern, just match it now.
587554 if (!FixedStr.empty()) {
588555 MatchLen = FixedStr.size();
589 return Buffer.find(FixedStr);
556 size_t Pos = Buffer.find(FixedStr);
557 if (Pos == StringRef::npos)
558 return make_error();
559 return Pos;
590560 }
591561
592562 // Regex match.
604574 // handled by back-references.
605575 for (const auto &Substitution : Substitutions) {
606576 // Substitute and check for failure (e.g. use of undefined variable).
607 Optional Value = Substitution->getResult();
577 Expected Value = Substitution->getResult();
608578 if (!Value)
609 return StringRef::npos;
579 return Value.takeError();
610580
611581 // Plop it into the regex at the adjusted offset.
612582 TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
620590
621591 SmallVector MatchInfo;
622592 if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo))
623 return StringRef::npos;
593 return make_error();
624594
625595 // Successful regex match.
626596 assert(!MatchInfo.empty() && "Didn't get any match");
644614
645615 StringRef MatchedValue = MatchInfo[CaptureParenGroup];
646616 uint64_t Val;
647 if (MatchedValue.getAsInteger(10, Val)) {
648 SM.PrintMessage(SMLoc::getFromPointer(MatchedValue.data()),
649 SourceMgr::DK_Error, "Unable to represent numeric value");
650 }
617 if (MatchedValue.getAsInteger(10, Val))
618 return FileCheckErrorDiagnostic::get(SM, MatchedValue,
619 "Unable to represent numeric value");
651620 if (DefinedNumericVariable->setValue(Val))
652 assert(false && "Numeric variable redefined");
621 llvm_unreachable("Numeric variable redefined");
653622 }
654623
655624 // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
684653 for (const auto &Substitution : Substitutions) {
685654 SmallString<256> Msg;
686655 raw_svector_ostream OS(Msg);
687 Optional MatchedValue = Substitution->getResult();
656 Expected MatchedValue = Substitution->getResult();
688657
689658 // Substitution failed or is not known at match time, print the undefined
690659 // variable it uses.
691660 if (!MatchedValue) {
692 StringRef UndefVarName = Substitution->getUndefVarName();
693 if (UndefVarName.empty())
694 continue;
695 OS << "uses undefined variable \"";
696 OS.write_escaped(UndefVarName) << "\"";
661 bool UndefSeen = false;
662 handleAllErrors(MatchedValue.takeError(),
663 [](const FileCheckNotFoundError &E) {},
664 // Handled in PrintNoMatch()
665 [](const FileCheckErrorDiagnostic &E) {},
666 [&](const FileCheckUndefVarError &E) {
667 if (!UndefSeen) {
668 OS << "uses undefined variable ";
669 UndefSeen = true;
670 }
671 E.log(OS);
672 },
673 [](const ErrorInfoBase &E) {
674 llvm_unreachable("Unexpected error");
675 });
697676 } else {
698677 // Substitution succeeded. Print substituted value.
699678 OS << "with \"";
776755 }
777756 }
778757
779 Optional
758 Expected
780759 FileCheckPatternContext::getPatternVarValue(StringRef VarName) {
781760 auto VarIter = GlobalVariableTable.find(VarName);
782761 if (VarIter == GlobalVariableTable.end())
783 return None;
762 return make_error(VarName);
784763
785764 return VarIter->second;
786765 }
10761055
10771056 bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
10781057 std::vector &CheckStrings) {
1079 if (PatternContext.defineCmdlineVariables(Req.GlobalDefines, SM))
1058 Error DefineError =
1059 PatternContext.defineCmdlineVariables(Req.GlobalDefines, SM);
1060 if (DefineError) {
1061 logAllUnhandledErrors(std::move(DefineError), errs());
10801062 return true;
1063 }
10811064
10821065 std::vector ImplicitNegativeChecks;
10831066 for (const auto &PatternString : Req.ImplicitCheckNot) {
12751258 StringRef Prefix, SMLoc Loc,
12761259 const FileCheckPattern &Pat, int MatchedCount,
12771260 StringRef Buffer, bool VerboseVerbose,
1278 std::vector *Diags) {
1261 std::vector *Diags, Error MatchErrors) {
1262 assert(MatchErrors && "Called on successful match");
12791263 bool PrintDiag = true;
12801264 if (!ExpectedMatch) {
1281 if (!VerboseVerbose)
1265 if (!VerboseVerbose) {
1266 consumeError(std::move(MatchErrors));
12821267 return;
1268 }
12831269 // Due to their verbosity, we don't print verbose diagnostics here if we're
12841270 // gathering them for a different rendering, but we always print other
12851271 // diagnostics.
12931279 ExpectedMatch ? FileCheckDiag::MatchNoneButExpected
12941280 : FileCheckDiag::MatchNoneAndExcluded,
12951281 SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);
1296 if (!PrintDiag)
1282 if (!PrintDiag) {
1283 consumeError(std::move(MatchErrors));
12971284 return;
1285 }
1286
1287 MatchErrors =
1288 handleErrors(std::move(MatchErrors),
1289 [](const FileCheckErrorDiagnostic &E) { E.log(errs()); });
1290
1291 // No problem matching the string per se.
1292 if (!MatchErrors)
1293 return;
1294 consumeError(std::move(MatchErrors));
12981295
12991296 // Print "not found" diagnostic.
13001297 std::string Message = formatv("{0}: {1} string not found in input",
13191316 static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
13201317 const FileCheckString &CheckStr, int MatchedCount,
13211318 StringRef Buffer, bool VerboseVerbose,
1322 std::vector *Diags) {
1319 std::vector *Diags, Error MatchErrors) {
13231320 PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
1324 MatchedCount, Buffer, VerboseVerbose, Diags);
1321 MatchedCount, Buffer, VerboseVerbose, Diags,
1322 std::move(MatchErrors));
13251323 }
13261324
13271325 /// Counts the number of newlines in the specified range.
13751373 StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
13761374 size_t CurrentMatchLen;
13771375 // get a match at current start point
1378 size_t MatchPos = Pat.match(MatchBuffer, CurrentMatchLen, SM);
1376 Expected MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM);
1377
1378 // report
1379 if (!MatchResult) {
1380 PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags,
1381 MatchResult.takeError());
1382 return StringRef::npos;
1383 }
1384 size_t MatchPos = *MatchResult;
1385 PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
1386 Diags);
13791387 if (i == 1)
13801388 FirstMatchPos = LastPos + MatchPos;
1381
1382 // report
1383 if (MatchPos == StringRef::npos) {
1384 PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags);
1385 return StringRef::npos;
1386 }
1387 PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
1388 Diags);
13891389
13901390 // move start point after the match
13911391 LastMatchEnd += MatchPos + CurrentMatchLen;
14961496 assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
14971497
14981498 size_t MatchLen = 0;
1499 size_t Pos = Pat->match(Buffer, MatchLen, SM);
1500
1501 if (Pos == StringRef::npos) {
1499 Expected MatchResult = Pat->match(Buffer, MatchLen, SM);
1500
1501 if (!MatchResult) {
15021502 PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
1503 Req.VerboseVerbose, Diags);
1503 Req.VerboseVerbose, Diags, MatchResult.takeError());
15041504 continue;
15051505 }
1506 size_t Pos = *MatchResult;
15061507
15071508 PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,
15081509 Req, Diags);
15561557 // CHECK-DAG group.
15571558 for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
15581559 StringRef MatchBuffer = Buffer.substr(MatchPos);
1559 size_t MatchPosBuf = Pat.match(MatchBuffer, MatchLen, SM);
1560 Expected MatchResult = Pat.match(MatchBuffer, MatchLen, SM);
15601561 // With a group of CHECK-DAGs, a single mismatching means the match on
15611562 // that group of CHECK-DAGs fails immediately.
1562 if (MatchPosBuf == StringRef::npos) {
1563 if (!MatchResult) {
15631564 PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
1564 Req.VerboseVerbose, Diags);
1565 Req.VerboseVerbose, Diags, MatchResult.takeError());
15651566 return StringRef::npos;
15661567 }
1568 size_t MatchPosBuf = *MatchResult;
15671569 // Re-calc it as the offset relative to the start of the original string.
15681570 MatchPos += MatchPosBuf;
15691571 if (Req.VerboseVerbose)
16861688 return Regex(PrefixRegexStr);
16871689 }
16881690
1689 bool FileCheckPatternContext::defineCmdlineVariables(
1691 Error FileCheckPatternContext::defineCmdlineVariables(
16901692 std::vector &CmdlineDefines, SourceMgr &SM) {
16911693 assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
16921694 "Overriding defined variable with command-line variable definitions");
16931695
16941696 if (CmdlineDefines.empty())
1695 return false;
1697 return Error::success();
16961698
16971699 // Create a string representing the vector of command-line definitions. Each
16981700 // definition is on its own line and prefixed with a definition number to
16991701 // clarify which definition a given diagnostic corresponds to.
17001702 unsigned I = 0;
1701 bool ErrorFound = false;
1703 Error Errs = Error::success();
17021704 std::string CmdlineDefsDiag;
17031705 StringRef Prefix1 = "Global define #";
17041706 StringRef Prefix2 = ": ";
17221724 StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);
17231725 size_t EqIdx = CmdlineDef.find('=');
17241726 if (EqIdx == StringRef::npos) {
1725 SM.PrintMessage(SMLoc::getFromPointer(CmdlineDef.data()),
1726 SourceMgr::DK_Error,
1727 "Missing equal sign in global definition");
1728 ErrorFound = true;
1727 Errs = joinErrors(
1728 std::move(Errs),
1729 FileCheckErrorDiagnostic::get(
1730 SM, CmdlineDef, "missing equal sign in global definition"));
17291731 continue;
17301732 }
17311733
17341736 StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
17351737 StringRef VarName;
17361738 SMLoc CmdlineNameLoc = SMLoc::getFromPointer(CmdlineName.data());
1737 bool ParseError = FileCheckPattern::parseNumericVariableDefinition(
1739 Error ErrorDiagnostic = FileCheckPattern::parseNumericVariableDefinition(
17381740 CmdlineName, VarName, this, SM);
1739 // Check that CmdlineName starts with a valid numeric variable to be
1740 // defined and that it is not followed that anything. That second check
1741 // detects cases like "FOO+2" in a "FOO+2=10" definition.
1742 if (ParseError || !CmdlineName.empty()) {
1743 if (!ParseError)
1744 SM.PrintMessage(CmdlineNameLoc, SourceMgr::DK_Error,
1745 "invalid variable name");
1746 ErrorFound = true;
1741 if (ErrorDiagnostic) {
1742 Errs = joinErrors(std::move(Errs), std::move(ErrorDiagnostic));
1743 continue;
1744 }
1745 // Check that CmdlineName is only composed of the parsed numeric
1746 // variable. This catches cases like "FOO+2" in a "FOO+2=10" definition.
1747 if (!CmdlineName.empty()) {
1748 Errs = joinErrors(std::move(Errs),
1749 FileCheckErrorDiagnostic::get(
1750 SM, CmdlineNameLoc, "invalid variable name"));
17471751 continue;
17481752 }
17491753
17501754 // Detect collisions between string and numeric variables when the latter
17511755 // is created later than the former.
17521756 if (DefinedVariableTable.find(VarName) != DefinedVariableTable.end()) {
1753 SM.PrintMessage(
1754 SMLoc::getFromPointer(VarName.data()), SourceMgr::DK_Error,
1755 "string variable with name '" + VarName + "' already exists");
1756 ErrorFound = true;
1757 Errs = joinErrors(
1758 std::move(Errs),
1759 FileCheckErrorDiagnostic::get(SM, VarName,
1760 "string variable with name '" +
1761 VarName + "' already exists"));
17571762 continue;
17581763 }
17591764
17601765 StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1);
17611766 uint64_t Val;
17621767 if (CmdlineVal.getAsInteger(10, Val)) {
1763 SM.PrintMessage(SMLoc::getFromPointer(CmdlineVal.data()),
1764 SourceMgr::DK_Error,
1765 "invalid value in numeric variable definition '" +
1766 CmdlineVal + "'");
1767 ErrorFound = true;
1768 Errs = joinErrors(std::move(Errs),
1769 FileCheckErrorDiagnostic::get(
1770 SM, CmdlineVal,
1771 "invalid value in numeric variable definition '" +
1772 CmdlineVal + "'"));
17681773 continue;
17691774 }
17701775 auto DefinedNumericVariable = makeNumericVariable(0, VarName);
17781783 std::pair CmdlineNameVal = CmdlineDef.split('=');
17791784 StringRef CmdlineName = CmdlineNameVal.first;
17801785 StringRef OrigCmdlineName = CmdlineName;
1781 StringRef Name;
17821786 bool IsPseudo;
1783 if (FileCheckPattern::parseVariable(CmdlineName, Name, IsPseudo) ||
1784 IsPseudo || !CmdlineName.empty()) {
1785 SM.PrintMessage(SMLoc::getFromPointer(OrigCmdlineName.data()),
1786 SourceMgr::DK_Error,
1787 "invalid name in string variable definition '" +
1788 OrigCmdlineName + "'");
1789 ErrorFound = true;
1787 Expected ParseVarResult =
1788 FileCheckPattern::parseVariable(CmdlineName, IsPseudo, SM);
1789 if (!ParseVarResult) {
1790 Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());
17901791 continue;
17911792 }
1793 // Check that CmdlineName does not denote a pseudo variable is only
1794 // composed of the parsed numeric variable. This catches cases like
1795 // "FOO+2" in a "FOO+2=10" definition.
1796 if (IsPseudo || !CmdlineName.empty()) {
1797 Errs = joinErrors(std::move(Errs),
1798 FileCheckErrorDiagnostic::get(
1799 SM, OrigCmdlineName,
1800 "invalid name in string variable definition '" +
1801 OrigCmdlineName + "'"));
1802 continue;
1803 }
1804 StringRef Name = *ParseVarResult;
17921805
17931806 // Detect collisions between string and numeric variables when the former
17941807 // is created later than the latter.
17951808 if (GlobalNumericVariableTable.find(Name) !=
17961809 GlobalNumericVariableTable.end()) {
1797 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
1798 "numeric variable with name '" + Name +
1799 "' already exists");
1800 ErrorFound = true;
1810 Errs = joinErrors(std::move(Errs), FileCheckErrorDiagnostic::get(
1811 SM, Name,
1812 "numeric variable with name '" +
1813 Name + "' already exists"));
18011814 continue;
18021815 }
18031816 GlobalVariableTable.insert(CmdlineNameVal);
18111824 }
18121825 }
18131826
1814 return ErrorFound;
1827 return Errs;
18151828 }
18161829
18171830 void FileCheckPatternContext::clearLocalVars() {
127127 CLI-NUM-CONFLICT: Global defines:2:20: error: string variable with name 'STRVAR' already exists
128128 CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42
129129 CLI-NUM-CONFLICT-NEXT: {{^ \^$}}
130
131 ; Numeric variable definition with too big value.
132 RUN: not FileCheck --check-prefix BIGVAL --input-file %s %s 2>&1 \
133 RUN: | FileCheck --strict-whitespace --check-prefix BIGVAL-MSG %s
134
135 BIG VALUE
136 NUMVAR: 10000000000000000000000
137 BIGVAL-LABEL: BIG VALUE
138 BIGVAL-NEXT: NUMVAR: [[#NUMVAR:]]
139 BIGVAL-MSG: numeric-expression.txt:[[#@LINE-3]]:9: error: Unable to represent numeric value
140 BIGVAL-MSG-NEXT: {{N}}UMVAR: 10000000000000000000000
141 BIGVAL-MSG-NEXT: {{^ \^$}}
2727 RUN: not FileCheck -D10VALUE=10 --input-file %s %s 2>&1 \
2828 RUN: | FileCheck %s --strict-whitespace --check-prefix ERRCLIFMT
2929
30 ERRCLIFMT: Global defines:1:19: error: invalid name in string variable definition '10VALUE'
30 ERRCLIFMT: Global defines:1:19: error: invalid variable name
3131 ERRCLIFMT-NEXT: Global define #1: 10VALUE=10
3232 ERRCLIFMT-NEXT: {{^ \^$}}
3333
4040
4141 uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
4242
43 static void expectUndefError(const Twine &ExpectedStr, Error Err) {
44 handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
45 EXPECT_EQ(ExpectedStr.str(), E.getVarName());
46 });
47 }
48
4349 TEST_F(FileCheckTest, NumExpr) {
4450 FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
4551 FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &FooVar, 18);
4652
47 // Defined variable: eval returns right value, no undefined variable
48 // returned.
49 llvm::Optional Value = NumExpr.eval();
50 EXPECT_TRUE(Value);
53 // Defined variable: eval returns right value.
54 Expected Value = NumExpr.eval();
55 EXPECT_TRUE(static_cast(Value));
5156 EXPECT_EQ(60U, *Value);
52 StringRef UndefVar = NumExpr.getUndefVarName();
53 EXPECT_EQ("", UndefVar);
5457
5558 // Undefined variable: eval fails, undefined variable returned. We call
5659 // getUndefVarName first to check that it can be called without calling
5760 // eval() first.
5861 FooVar.clearValue();
59 UndefVar = NumExpr.getUndefVarName();
60 EXPECT_EQ("FOO", UndefVar);
61 Value = NumExpr.eval();
62 EXPECT_FALSE(Value);
62 Error EvalError = NumExpr.eval().takeError();
63 EXPECT_TRUE(errorToBool(std::move(EvalError)));
64 expectUndefError("FOO", std::move(EvalError));
6365 }
6466
6567 TEST_F(FileCheckTest, ValidVarNameStart) {
7476 EXPECT_FALSE(FileCheckPattern::isValidVarNameStart(':'));
7577 }
7678
77 TEST_F(FileCheckTest, ParseVar) {
78 StringRef OrigVarName = "GoodVar42";
79 StringRef VarName = OrigVarName;
80 StringRef ParsedName;
81 bool IsPseudo = true;
82 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
83 EXPECT_EQ(ParsedName, OrigVarName);
84 EXPECT_TRUE(VarName.empty());
85 EXPECT_FALSE(IsPseudo);
86
87 VarName = OrigVarName = "$GoodGlobalVar";
88 IsPseudo = true;
89 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
90 EXPECT_EQ(ParsedName, OrigVarName);
91 EXPECT_TRUE(VarName.empty());
92 EXPECT_FALSE(IsPseudo);
93
94 VarName = OrigVarName = "@GoodPseudoVar";
95 IsPseudo = true;
96 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
97 EXPECT_EQ(ParsedName, OrigVarName);
98 EXPECT_TRUE(VarName.empty());
99 EXPECT_TRUE(IsPseudo);
100
101 VarName = "42BadVar";
102 EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
103
104 VarName = "$@";
105 EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
106
107 VarName = OrigVarName = "B@dVar";
108 IsPseudo = true;
109 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
110 EXPECT_EQ(VarName, OrigVarName.substr(1));
111 EXPECT_EQ(ParsedName, "B");
112 EXPECT_FALSE(IsPseudo);
113
114 VarName = OrigVarName = "B$dVar";
115 IsPseudo = true;
116 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
117 EXPECT_EQ(VarName, OrigVarName.substr(1));
118 EXPECT_EQ(ParsedName, "B");
119 EXPECT_FALSE(IsPseudo);
120
121 VarName = "BadVar+";
122 IsPseudo = true;
123 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
124 EXPECT_EQ(VarName, "+");
125 EXPECT_EQ(ParsedName, "BadVar");
126 EXPECT_FALSE(IsPseudo);
127
128 VarName = "BadVar-";
129 IsPseudo = true;
130 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
131 EXPECT_EQ(VarName, "-");
132 EXPECT_EQ(ParsedName, "BadVar");
133 EXPECT_FALSE(IsPseudo);
134
135 VarName = "BadVar:";
136 IsPseudo = true;
137 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
138 EXPECT_EQ(VarName, ":");
139 EXPECT_EQ(ParsedName, "BadVar");
140 EXPECT_FALSE(IsPseudo);
141 }
142
14379 static StringRef bufferize(SourceMgr &SM, StringRef Str) {
14480 std::unique_ptr Buffer =
14581 MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
14682 StringRef StrBufferRef = Buffer->getBuffer();
14783 SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
14884 return StrBufferRef;
85 }
86
87 TEST_F(FileCheckTest, ParseVar) {
88 SourceMgr SM;
89 StringRef OrigVarName = bufferize(SM, "GoodVar42");
90 StringRef VarName = OrigVarName;
91 bool IsPseudo = true;
92 Expected ParsedName =
93 FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
94 EXPECT_TRUE(static_cast(ParsedName));
95 EXPECT_EQ(*ParsedName, OrigVarName);
96 EXPECT_TRUE(VarName.empty());
97 EXPECT_FALSE(IsPseudo);
98
99 VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
100 IsPseudo = true;
101 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
102 EXPECT_TRUE(static_cast(ParsedName));
103 EXPECT_EQ(*ParsedName, OrigVarName);
104 EXPECT_TRUE(VarName.empty());
105 EXPECT_FALSE(IsPseudo);
106
107 VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
108 IsPseudo = true;
109 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
110 EXPECT_TRUE(static_cast(ParsedName));
111 EXPECT_EQ(*ParsedName, OrigVarName);
112 EXPECT_TRUE(VarName.empty());
113 EXPECT_TRUE(IsPseudo);
114
115 VarName = bufferize(SM, "42BadVar");
116 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
117 EXPECT_TRUE(errorToBool(ParsedName.takeError()));
118
119 VarName = bufferize(SM, "$@");
120 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
121 EXPECT_TRUE(errorToBool(ParsedName.takeError()));
122
123 VarName = OrigVarName = bufferize(SM, "B@dVar");
124 IsPseudo = true;
125 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
126 EXPECT_TRUE(static_cast(ParsedName));
127 EXPECT_EQ(VarName, OrigVarName.substr(1));
128 EXPECT_EQ(*ParsedName, "B");
129 EXPECT_FALSE(IsPseudo);
130
131 VarName = OrigVarName = bufferize(SM, "B$dVar");
132 IsPseudo = true;
133 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
134 EXPECT_TRUE(static_cast(ParsedName));
135 EXPECT_EQ(VarName, OrigVarName.substr(1));
136 EXPECT_EQ(*ParsedName, "B");
137 EXPECT_FALSE(IsPseudo);
138
139 VarName = bufferize(SM, "BadVar+");
140 IsPseudo = true;
141 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
142 EXPECT_TRUE(static_cast(ParsedName));
143 EXPECT_EQ(VarName, "+");
144 EXPECT_EQ(*ParsedName, "BadVar");
145 EXPECT_FALSE(IsPseudo);
146
147 VarName = bufferize(SM, "BadVar-");
148 IsPseudo = true;
149 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
150 EXPECT_TRUE(static_cast(ParsedName));
151 EXPECT_EQ(VarName, "-");
152 EXPECT_EQ(*ParsedName, "BadVar");
153 EXPECT_FALSE(IsPseudo);
154
155 VarName = bufferize(SM, "BadVar:");
156 IsPseudo = true;
157 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
158 EXPECT_TRUE(static_cast(ParsedName));
159 EXPECT_EQ(VarName, ":");
160 EXPECT_EQ(*ParsedName, "BadVar");
161 EXPECT_FALSE(IsPseudo);
149162 }
150163
151164 class PatternTester {
162175 std::vector GlobalDefines;
163176 GlobalDefines.emplace_back(std::string("#FOO=42"));
164177 GlobalDefines.emplace_back(std::string("BAR=BAZ"));
165 Context.defineCmdlineVariables(GlobalDefines, SM);
178 EXPECT_FALSE(
179 errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
166180 // Call parsePattern to have @LINE defined.
167181 P.parsePattern("N/A", "CHECK", SM, Req);
168182 // parsePattern does not expect to be called twice for the same line and
178192 bool parseNumVarDefExpect(StringRef Expr) {
179193 StringRef ExprBufferRef = bufferize(SM, Expr);
180194 StringRef Name;
181 return FileCheckPattern::parseNumericVariableDefinition(ExprBufferRef, Name,
182 &Context, SM);
195 return errorToBool(FileCheckPattern::parseNumericVariableDefinition(
196 ExprBufferRef, Name, &Context, SM));
183197 }
184198
185199 bool parseSubstExpect(StringRef Expr) {
186200 StringRef ExprBufferRef = bufferize(SM, Expr);
187 FileCheckNumericVariable *DefinedNumericVariable;
188 return P.parseNumericSubstitutionBlock(
189 ExprBufferRef, DefinedNumericVariable, SM) == nullptr;
201 Optional DefinedNumericVariable;
202 return errorToBool(P.parseNumericSubstitutionBlock(
203 ExprBufferRef, DefinedNumericVariable, SM)
204 .takeError());
190205 }
191206
192207 bool parsePatternExpect(StringRef Pattern) {
197212 bool matchExpect(StringRef Buffer) {
198213 StringRef BufferRef = bufferize(SM, Buffer);
199214 size_t MatchLen;
200 return P.match(BufferRef, MatchLen, SM);
215 return errorToBool(P.match(BufferRef, MatchLen, SM).takeError());
201216 }
202217 };
203218
324339 FileCheckPatternContext Context;
325340 std::vector GlobalDefines;
326341 GlobalDefines.emplace_back(std::string("FOO=BAR"));
327 Context.defineCmdlineVariables(GlobalDefines, SM);
328
329 // Substitution of an undefined string variable fails.
342 EXPECT_FALSE(errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
343
344 // Substitution of an undefined string variable fails and error holds that
345 // variable's name.
330346 FileCheckStringSubstitution StringSubstitution =
331347 FileCheckStringSubstitution(&Context, "VAR404", 42);
332 EXPECT_FALSE(StringSubstitution.getResult());
348 Expected SubstValue = StringSubstitution.getResult();
349 EXPECT_FALSE(static_cast(SubstValue));
350 expectUndefError("VAR404", SubstValue.takeError());
333351
334352 // Substitutions of defined pseudo and non-pseudo numeric variables return
335353 // the right value.
341359 FileCheckNumericSubstitution(&Context, "@LINE", &NumExprLine, 12);
342360 FileCheckNumericSubstitution SubstitutionN =
343361 FileCheckNumericSubstitution(&Context, "N", &NumExprN, 30);
344 llvm::Optional Value = SubstitutionLine.getResult();
345 EXPECT_TRUE(Value);
362 Expected Value = SubstitutionLine.getResult();
363 EXPECT_TRUE(static_cast(Value));
346364 EXPECT_EQ("42", *Value);
347365 Value = SubstitutionN.getResult();
348 EXPECT_TRUE(Value);
366 EXPECT_TRUE(static_cast(Value));
349367 EXPECT_EQ("13", *Value);
350368
351369 // Substitution of an undefined numeric variable fails.
352370 LineVar.clearValue();
353 EXPECT_FALSE(SubstitutionLine.getResult());
371 SubstValue = SubstitutionLine.getResult().takeError();
372 EXPECT_FALSE(static_cast(SubstValue));
373 expectUndefError("@LINE", SubstValue.takeError());
354374 NVar.clearValue();
355 EXPECT_FALSE(SubstitutionN.getResult());
375 SubstValue = SubstitutionN.getResult().takeError();
376 EXPECT_FALSE(static_cast(SubstValue));
377 expectUndefError("N", SubstValue.takeError());
356378
357379 // Substitution of a defined string variable returns the right value.
358380 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
359381 StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
360382 Value = StringSubstitution.getResult();
361 EXPECT_TRUE(Value);
383 EXPECT_TRUE(static_cast(Value));
362384 EXPECT_EQ("BAR", *Value);
363 }
364
365 TEST_F(FileCheckTest, UndefVars) {
366 SourceMgr SM;
367 FileCheckPatternContext Context;
368 std::vector GlobalDefines;
369 GlobalDefines.emplace_back(std::string("FOO=BAR"));
370 Context.defineCmdlineVariables(GlobalDefines, SM);
371
372 // getUndefVarName() on a string substitution with an undefined variable
373 // returns that variable.
374 FileCheckStringSubstitution StringSubstitution =
375 FileCheckStringSubstitution(&Context, "VAR404", 42);
376 StringRef UndefVar = StringSubstitution.getUndefVarName();
377 EXPECT_EQ("VAR404", UndefVar);
378
379 // getUndefVarName() on a string substitution with a defined variable returns
380 // an empty string.
381 StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
382 UndefVar = StringSubstitution.getUndefVarName();
383 EXPECT_EQ("", UndefVar);
384
385 // getUndefVarName() on a numeric substitution with a defined variable
386 // returns an empty string.
387 FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
388 FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &LineVar, 0);
389 FileCheckNumericSubstitution NumericSubstitution =
390 FileCheckNumericSubstitution(&Context, "@LINE", &NumExpr, 12);
391 UndefVar = NumericSubstitution.getUndefVarName();
392 EXPECT_EQ("", UndefVar);
393
394 // getUndefVarName() on a numeric substitution with an undefined variable
395 // returns that variable.
396 LineVar.clearValue();
397 UndefVar = NumericSubstitution.getUndefVarName();
398 EXPECT_EQ("@LINE", UndefVar);
399385 }
400386
401387 TEST_F(FileCheckTest, FileCheckContext) {
405391
406392 // Missing equal sign.
407393 GlobalDefines.emplace_back(std::string("LocalVar"));
408 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
394 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
409395 GlobalDefines.clear();
410396 GlobalDefines.emplace_back(std::string("#LocalNumVar"));
411 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
397 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
412398
413399 // Empty variable name.
414400 GlobalDefines.clear();
415401 GlobalDefines.emplace_back(std::string("=18"));
416 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
402 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
417403 GlobalDefines.clear();
418404 GlobalDefines.emplace_back(std::string("#=18"));
419 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
405 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
420406
421407 // Invalid variable name.
422408 GlobalDefines.clear();
423409 GlobalDefines.emplace_back(std::string("18LocalVar=18"));
424 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
410 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
425411 GlobalDefines.clear();
426412 GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
427 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
413 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
428414
429415 // Name conflict between pattern and numeric variable.
430416 GlobalDefines.clear();
431417 GlobalDefines.emplace_back(std::string("LocalVar=18"));
432418 GlobalDefines.emplace_back(std::string("#LocalVar=36"));
433 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
419 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
434420 Cxt = FileCheckPatternContext();
435421 GlobalDefines.clear();
436422 GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
437423 GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
438 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
424 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
439425 Cxt = FileCheckPatternContext();
440426
441427 // Invalid numeric value for numeric variable.
442428 GlobalDefines.clear();
443429 GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
444 EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
430 EXPECT_TRUE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
445431
446432 // Define local variables from command-line.
447433 GlobalDefines.clear();
448434 GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
449435 GlobalDefines.emplace_back(std::string("EmptyVar="));
450436 GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
451 bool GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
452 EXPECT_FALSE(GotError);
437 EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
453438
454439 // Check defined variables are present and undefined is absent.
455440 StringRef LocalVarStr = "LocalVar";
456441 StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");
457442 StringRef EmptyVarStr = "EmptyVar";
458443 StringRef UnknownVarStr = "UnknownVar";
459 llvm::Optional LocalVar = Cxt.getPatternVarValue(LocalVarStr);
444 Expected LocalVar = Cxt.getPatternVarValue(LocalVarStr);
460445 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
461 FileCheckNumericVariable *DefinedNumericVariable;
462 FileCheckNumExpr *NumExpr = P.parseNumericSubstitutionBlock(
446 Optional DefinedNumericVariable;
447 Expected NumExpr = P.parseNumericSubstitutionBlock(
463448 LocalNumVarRef, DefinedNumericVariable, SM);
464 llvm::Optional EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
465 llvm::Optional UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
466 EXPECT_TRUE(LocalVar);
449 Expected EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
450 Expected UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
451 EXPECT_TRUE(static_cast(LocalVar));
467452 EXPECT_EQ(*LocalVar, "FOO");
468 EXPECT_TRUE(NumExpr);
469 llvm::Optional NumExprVal = NumExpr->eval();
470 EXPECT_TRUE(NumExprVal);
453 EXPECT_TRUE(static_cast(NumExpr));
454 Expected NumExprVal = (*NumExpr)->eval();
455 EXPECT_TRUE(static_cast(NumExprVal));
471456 EXPECT_EQ(*NumExprVal, 18U);
472 EXPECT_TRUE(EmptyVar);
457 EXPECT_TRUE(static_cast(EmptyVar));
473458 EXPECT_EQ(*EmptyVar, "");
474 EXPECT_FALSE(UnknownVar);
459 EXPECT_TRUE(errorToBool(UnknownVar.takeError()));
475460
476461 // Clear local variables and check they become absent.
477462 Cxt.clearLocalVars();
478463 LocalVar = Cxt.getPatternVarValue(LocalVarStr);
479 EXPECT_FALSE(LocalVar);
464 EXPECT_TRUE(errorToBool(LocalVar.takeError()));
480465 // Check a numeric expression's evaluation fails if called after clearing of
481466 // local variables, if it was created before. This is important because local
482467 // variable clearing due to --enable-var-scope happens after numeric
483468 // expressions are linked to the numeric variables they use.
484 EXPECT_FALSE(NumExpr->eval());
469 EXPECT_TRUE(errorToBool((*NumExpr)->eval().takeError()));
485470 P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
486471 NumExpr = P.parseNumericSubstitutionBlock(LocalNumVarRef,
487472 DefinedNumericVariable, SM);
488 EXPECT_FALSE(NumExpr);
473 EXPECT_TRUE(errorToBool(NumExpr.takeError()));
489474 EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
490 EXPECT_FALSE(EmptyVar);
475 EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
491476
492477 // Redefine global variables and check variables are defined again.
493478 GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
494479 GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
495 GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
496 EXPECT_FALSE(GotError);
480 EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
497481 StringRef GlobalVarStr = "$GlobalVar";
498482 StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
499 llvm::Optional GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
500 EXPECT_TRUE(GlobalVar);
483 Expected GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
484 EXPECT_TRUE(static_cast(GlobalVar));
501485 EXPECT_EQ(*GlobalVar, "BAR");
502486 P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
503487 NumExpr = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
504488 DefinedNumericVariable, SM);
505 EXPECT_TRUE(NumExpr);
506 NumExprVal = NumExpr->eval();
507 EXPECT_TRUE(NumExprVal);
489 EXPECT_TRUE(static_cast(NumExpr));
490 NumExprVal = (*NumExpr)->eval();
491 EXPECT_TRUE(static_cast(NumExprVal));
508492 EXPECT_EQ(*NumExprVal, 36U);
509493
510494 // Clear local variables and check global variables remain defined.
511495 Cxt.clearLocalVars();
512 GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
513 EXPECT_TRUE(GlobalVar);
496 EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
514497 P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
515498 NumExpr = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
516499 DefinedNumericVariable, SM);
517 EXPECT_TRUE(NumExpr);
518 NumExprVal = NumExpr->eval();
519 EXPECT_TRUE(NumExprVal);
500 EXPECT_TRUE(static_cast(NumExpr));
501 NumExprVal = (*NumExpr)->eval();
502 EXPECT_TRUE(static_cast(NumExprVal));
520503 EXPECT_EQ(*NumExprVal, 36U);
521504 }
522505 } // namespace