blob: 5c05af4c190b9dad2d288c19dd19cb70c721295f [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"
Thomas Preud'hommeb1add2b2019-08-08 13:56:59 +000018#include "llvm/ADT/Twine.h"
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +000019#include "llvm/Support/FormatVariadic.h"
20#include <cstdint>
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +000021#include <list>
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'homme2a7f5202019-07-13 13:24:30 +000027Expected<uint64_t> FileCheckNumericVariableUse::eval() const {
28 Optional<uint64_t> Value = NumericVariable->getValue();
29 if (Value)
30 return *Value;
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +000031
Thomas Preud'hommea291b952019-09-02 14:04:00 +000032 return make_error<FileCheckUndefVarError>(Name);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000033}
34
35Expected<uint64_t> FileCheckASTBinop::eval() const {
36 Expected<uint64_t> LeftOp = LeftOperand->eval();
37 Expected<uint64_t> RightOp = RightOperand->eval();
38
39 // Bubble up any error (e.g. undefined variables) in the recursive
40 // evaluation.
41 if (!LeftOp || !RightOp) {
42 Error Err = Error::success();
43 if (!LeftOp)
44 Err = joinErrors(std::move(Err), LeftOp.takeError());
45 if (!RightOp)
46 Err = joinErrors(std::move(Err), RightOp.takeError());
47 return std::move(Err);
48 }
49
50 return EvalBinop(*LeftOp, *RightOp);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000051}
52
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000053Expected<std::string> FileCheckNumericSubstitution::getResult() const {
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000054 Expected<uint64_t> EvaluatedValue = ExpressionAST->eval();
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +000055 if (!EvaluatedValue)
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000056 return EvaluatedValue.takeError();
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +000057 return utostr(*EvaluatedValue);
58}
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000059
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000060Expected<std::string> FileCheckStringSubstitution::getResult() const {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000061 // Look up the value and escape it so that we can put it into the regex.
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000062 Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000063 if (!VarVal)
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000064 return VarVal.takeError();
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +000065 return Regex::escape(*VarVal);
Thomas Preud'homme288ed912019-05-02 00:04:38 +000066}
67
Thomas Preud'homme5a330472019-04-29 13:32:36 +000068bool FileCheckPattern::isValidVarNameStart(char C) {
69 return C == '_' || isalpha(C);
70}
71
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000072Expected<FileCheckPattern::VariableProperties>
73FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
Thomas Preud'homme5a330472019-04-29 13:32:36 +000074 if (Str.empty())
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000075 return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");
Thomas Preud'homme5a330472019-04-29 13:32:36 +000076
77 bool ParsedOneChar = false;
78 unsigned I = 0;
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000079 bool IsPseudo = Str[0] == '@';
Thomas Preud'homme5a330472019-04-29 13:32:36 +000080
81 // Global vars start with '$'.
82 if (Str[0] == '$' || IsPseudo)
83 ++I;
84
85 for (unsigned E = Str.size(); I != E; ++I) {
86 if (!ParsedOneChar && !isValidVarNameStart(Str[I]))
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000087 return FileCheckErrorDiagnostic::get(SM, Str, "invalid variable name");
Thomas Preud'homme5a330472019-04-29 13:32:36 +000088
89 // Variable names are composed of alphanumeric characters and underscores.
90 if (Str[I] != '_' && !isalnum(Str[I]))
91 break;
92 ParsedOneChar = true;
93 }
94
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +000095 StringRef Name = Str.take_front(I);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +000096 Str = Str.substr(I);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +000097 return VariableProperties {Name, IsPseudo};
Thomas Preud'homme5a330472019-04-29 13:32:36 +000098}
99
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000100// StringRef holding all characters considered as horizontal whitespaces by
101// FileCheck input canonicalization.
Benjamin Kramerdc5f8052019-08-23 19:59:23 +0000102constexpr StringLiteral SpaceChars = " \t";
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000103
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000104// Parsing helper function that strips the first character in S and returns it.
105static char popFront(StringRef &S) {
106 char C = S.front();
107 S = S.drop_front();
108 return C;
109}
110
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000111char FileCheckUndefVarError::ID = 0;
112char FileCheckErrorDiagnostic::ID = 0;
113char FileCheckNotFoundError::ID = 0;
114
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000115Expected<FileCheckNumericVariable *>
116FileCheckPattern::parseNumericVariableDefinition(
Thomas Preud'homme99f2a102019-07-15 19:04:56 +0000117 StringRef &Expr, FileCheckPatternContext *Context,
Thomas Preud'hommea291b952019-09-02 14:04:00 +0000118 Optional<size_t> LineNumber, const SourceMgr &SM) {
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000119 Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000120 if (!ParseVarResult)
121 return ParseVarResult.takeError();
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000122 StringRef Name = ParseVarResult->Name;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000123
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000124 if (ParseVarResult->IsPseudo)
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000125 return FileCheckErrorDiagnostic::get(
126 SM, Name, "definition of pseudo numeric variable unsupported");
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000127
128 // Detect collisions between string and numeric variables when the latter
129 // is created later than the former.
130 if (Context->DefinedVariableTable.find(Name) !=
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000131 Context->DefinedVariableTable.end())
132 return FileCheckErrorDiagnostic::get(
133 SM, Name, "string variable with name '" + Name + "' already exists");
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000134
Thomas Preud'homme28196a52019-07-05 12:01:06 +0000135 Expr = Expr.ltrim(SpaceChars);
136 if (!Expr.empty())
137 return FileCheckErrorDiagnostic::get(
138 SM, Expr, "unexpected characters after numeric variable name");
139
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000140 FileCheckNumericVariable *DefinedNumericVariable;
141 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
142 if (VarTableIter != Context->GlobalNumericVariableTable.end())
143 DefinedNumericVariable = VarTableIter->second;
144 else
Thomas Preud'hommea291b952019-09-02 14:04:00 +0000145 DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000146
147 return DefinedNumericVariable;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000148}
149
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000150Expected<std::unique_ptr<FileCheckNumericVariableUse>>
151FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000152 Optional<size_t> LineNumber,
153 FileCheckPatternContext *Context,
154 const SourceMgr &SM) {
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000155 if (IsPseudo && !Name.equals("@LINE"))
156 return FileCheckErrorDiagnostic::get(
157 SM, Name, "invalid pseudo numeric variable '" + Name + "'");
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000158
Thomas Preud'homme41f2bea2019-07-05 12:01:12 +0000159 // Numeric variable definitions and uses are parsed in the order in which
160 // they appear in the CHECK patterns. For each definition, the pointer to the
161 // class instance of the corresponding numeric variable definition is stored
Thomas Preud'homme56f63082019-07-05 16:25:46 +0000162 // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer
163 // we get below is null, it means no such variable was defined before. When
164 // that happens, we create a dummy variable so that parsing can continue. All
165 // uses of undefined variables, whether string or numeric, are then diagnosed
166 // in printSubstitutions() after failing to match.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000167 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000168 FileCheckNumericVariable *NumericVariable;
169 if (VarTableIter != Context->GlobalNumericVariableTable.end())
170 NumericVariable = VarTableIter->second;
171 else {
Thomas Preud'homme99f2a102019-07-15 19:04:56 +0000172 NumericVariable = Context->makeNumericVariable(Name);
Thomas Preud'hommefe7ac172019-07-05 16:25:33 +0000173 Context->GlobalNumericVariableTable[Name] = NumericVariable;
174 }
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000175
Thomas Preud'homme99f2a102019-07-15 19:04:56 +0000176 Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();
Thomas Preud'hommea291b952019-09-02 14:04:00 +0000177 if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000178 return FileCheckErrorDiagnostic::get(
179 SM, Name,
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000180 "numeric variable '" + Name +
Thomas Preud'hommea291b952019-09-02 14:04:00 +0000181 "' defined earlier in the same CHECK directive");
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000182
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000183 return std::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000184}
185
186Expected<std::unique_ptr<FileCheckExpressionAST>>
187FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000188 Optional<size_t> LineNumber,
189 FileCheckPatternContext *Context,
190 const SourceMgr &SM) {
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000191 if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
192 // Try to parse as a numeric variable use.
193 Expected<FileCheckPattern::VariableProperties> ParseVarResult =
194 parseVariable(Expr, SM);
195 if (ParseVarResult)
196 return parseNumericVariableUse(ParseVarResult->Name,
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000197 ParseVarResult->IsPseudo, LineNumber,
198 Context, SM);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000199 if (AO == AllowedOperand::LineVar)
200 return ParseVarResult.takeError();
201 // Ignore the error and retry parsing as a literal.
202 consumeError(ParseVarResult.takeError());
203 }
204
205 // Otherwise, parse it as a literal.
206 uint64_t LiteralValue;
207 if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000208 return std::make_unique<FileCheckExpressionLiteral>(LiteralValue);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000209
210 return FileCheckErrorDiagnostic::get(SM, Expr,
211 "invalid operand format '" + Expr + "'");
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000212}
213
214static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
215 return LeftOp + RightOp;
216}
217
218static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
219 return LeftOp - RightOp;
220}
221
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000222Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(
223 StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
224 bool IsLegacyLineExpr, Optional<size_t> LineNumber,
225 FileCheckPatternContext *Context, const SourceMgr &SM) {
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000226 Expr = Expr.ltrim(SpaceChars);
227 if (Expr.empty())
228 return std::move(LeftOp);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000229
230 // Check if this is a supported operation and select a function to perform
231 // it.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000232 SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());
233 char Operator = popFront(Expr);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000234 binop_eval_t EvalBinop;
235 switch (Operator) {
236 case '+':
237 EvalBinop = add;
238 break;
239 case '-':
240 EvalBinop = sub;
241 break;
242 default:
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000243 return FileCheckErrorDiagnostic::get(
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000244 SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'");
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000245 }
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000246
247 // Parse right operand.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000248 Expr = Expr.ltrim(SpaceChars);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000249 if (Expr.empty())
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000250 return FileCheckErrorDiagnostic::get(SM, Expr,
251 "missing operand in expression");
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000252 // The second operand in a legacy @LINE expression is always a literal.
253 AllowedOperand AO =
254 IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
255 Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000256 parseNumericOperand(Expr, AO, LineNumber, Context, SM);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000257 if (!RightOpResult)
258 return RightOpResult;
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000259
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000260 Expr = Expr.ltrim(SpaceChars);
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000261 return std::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000262 std::move(*RightOpResult));
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000263}
264
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000265Expected<std::unique_ptr<FileCheckExpressionAST>>
266FileCheckPattern::parseNumericSubstitutionBlock(
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000267 StringRef Expr,
268 Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000269 bool IsLegacyLineExpr, Optional<size_t> LineNumber,
270 FileCheckPatternContext *Context, const SourceMgr &SM) {
271 std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;
272 StringRef DefExpr = StringRef();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000273 DefinedNumericVariable = None;
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000274 // Save variable definition expression if any.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000275 size_t DefEnd = Expr.find(':');
276 if (DefEnd != StringRef::npos) {
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000277 DefExpr = Expr.substr(0, DefEnd);
278 Expr = Expr.substr(DefEnd + 1);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000279 }
280
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000281 // Parse the expression itself.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000282 Expr = Expr.ltrim(SpaceChars);
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000283 if (!Expr.empty()) {
284 // The first operand in a legacy @LINE expression is always the @LINE
285 // pseudo variable.
286 AllowedOperand AO =
287 IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
288 Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
289 parseNumericOperand(Expr, AO, LineNumber, Context, SM);
290 while (ParseResult && !Expr.empty()) {
291 ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,
292 LineNumber, Context, SM);
293 // Legacy @LINE expressions only allow 2 operands.
294 if (ParseResult && IsLegacyLineExpr && !Expr.empty())
295 return FileCheckErrorDiagnostic::get(
296 SM, Expr,
297 "unexpected characters at end of expression '" + Expr + "'");
298 }
299 if (!ParseResult)
300 return ParseResult;
301 ExpressionAST = std::move(*ParseResult);
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000302 }
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000303
304 // Parse the numeric variable definition.
305 if (DefEnd != StringRef::npos) {
306 DefExpr = DefExpr.ltrim(SpaceChars);
307 Expected<FileCheckNumericVariable *> ParseResult =
Thomas Preud'hommea291b952019-09-02 14:04:00 +0000308 parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000309
310 if (!ParseResult)
311 return ParseResult.takeError();
312 DefinedNumericVariable = *ParseResult;
313 }
314
315 return std::move(ExpressionAST);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000316}
317
318bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
319 SourceMgr &SM,
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000320 const FileCheckRequest &Req) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000321 bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
322
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000323 PatternLoc = SMLoc::getFromPointer(PatternStr.data());
324
325 if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
326 // Ignore trailing whitespace.
327 while (!PatternStr.empty() &&
328 (PatternStr.back() == ' ' || PatternStr.back() == '\t'))
329 PatternStr = PatternStr.substr(0, PatternStr.size() - 1);
330
331 // Check that there is something on the line.
332 if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {
333 SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
334 "found empty check string with prefix '" + Prefix + ":'");
335 return true;
336 }
337
338 if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {
339 SM.PrintMessage(
340 PatternLoc, SourceMgr::DK_Error,
341 "found non-empty check string for empty check with prefix '" + Prefix +
342 ":'");
343 return true;
344 }
345
346 if (CheckTy == Check::CheckEmpty) {
347 RegExStr = "(\n$)";
348 return false;
349 }
350
351 // Check to see if this is a fixed string, or if it has regex pieces.
352 if (!MatchFullLinesHere &&
353 (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&
354 PatternStr.find("[[") == StringRef::npos))) {
355 FixedStr = PatternStr;
356 return false;
357 }
358
359 if (MatchFullLinesHere) {
360 RegExStr += '^';
361 if (!Req.NoCanonicalizeWhiteSpace)
362 RegExStr += " *";
363 }
364
365 // Paren value #0 is for the fully matched string. Any new parenthesized
366 // values add from there.
367 unsigned CurParen = 1;
368
369 // Otherwise, there is at least one regex piece. Build up the regex pattern
370 // by escaping scary characters in fixed strings, building up one big regex.
371 while (!PatternStr.empty()) {
372 // RegEx matches.
373 if (PatternStr.startswith("{{")) {
374 // This is the start of a regex match. Scan for the }}.
375 size_t End = PatternStr.find("}}");
376 if (End == StringRef::npos) {
377 SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
378 SourceMgr::DK_Error,
379 "found start of regex string with no end '}}'");
380 return true;
381 }
382
383 // Enclose {{}} patterns in parens just like [[]] even though we're not
384 // capturing the result for any purpose. This is required in case the
385 // expression contains an alternation like: CHECK: abc{{x|z}}def. We
386 // want this to turn into: "abc(x|z)def" not "abcx|zdef".
387 RegExStr += '(';
388 ++CurParen;
389
390 if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM))
391 return true;
392 RegExStr += ')';
393
394 PatternStr = PatternStr.substr(End + 2);
395 continue;
396 }
397
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000398 // String and numeric substitution blocks. Pattern substitution blocks come
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000399 // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
400 // other regex) and assigns it to the string variable 'foo'. The latter
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000401 // substitutes foo's value. Numeric substitution blocks recognize the same
402 // form as string ones, but start with a '#' sign after the double
403 // brackets. They also accept a combined form which sets a numeric variable
404 // to the evaluation of an expression. Both string and numeric variable
405 // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be
406 // valid, as this helps catch some common errors.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000407 if (PatternStr.startswith("[[")) {
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000408 StringRef UnparsedPatternStr = PatternStr.substr(2);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000409 // Find the closing bracket pair ending the match. End is going to be an
410 // offset relative to the beginning of the match string.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000411 size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);
412 StringRef MatchStr = UnparsedPatternStr.substr(0, End);
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000413 bool IsNumBlock = MatchStr.consume_front("#");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000414
415 if (End == StringRef::npos) {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000416 SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
417 SourceMgr::DK_Error,
418 "Invalid substitution block, no ]] found");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000419 return true;
420 }
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000421 // Strip the substitution block we are parsing. End points to the start
422 // of the "]]" closing the expression so account for it in computing the
423 // index of the first unparsed character.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000424 PatternStr = UnparsedPatternStr.substr(End + 2);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000425
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000426 bool IsDefinition = false;
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000427 bool SubstNeeded = false;
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000428 // Whether the substitution block is a legacy use of @LINE with string
429 // substitution block syntax.
430 bool IsLegacyLineExpr = false;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000431 StringRef DefName;
432 StringRef SubstStr;
433 StringRef MatchRegexp;
434 size_t SubstInsertIdx = RegExStr.size();
435
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000436 // Parse string variable or legacy @LINE expression.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000437 if (!IsNumBlock) {
438 size_t VarEndIdx = MatchStr.find(":");
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000439 size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
440 if (SpacePos != StringRef::npos) {
441 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),
442 SourceMgr::DK_Error, "unexpected whitespace");
443 return true;
444 }
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000445
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000446 // Get the name (e.g. "foo") and verify it is well formed.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000447 StringRef OrigMatchStr = MatchStr;
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000448 Expected<FileCheckPattern::VariableProperties> ParseVarResult =
449 parseVariable(MatchStr, SM);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000450 if (!ParseVarResult) {
451 logAllUnhandledErrors(ParseVarResult.takeError(), errs());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000452 return true;
453 }
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000454 StringRef Name = ParseVarResult->Name;
455 bool IsPseudo = ParseVarResult->IsPseudo;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000456
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000457 IsDefinition = (VarEndIdx != StringRef::npos);
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000458 SubstNeeded = !IsDefinition;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000459 if (IsDefinition) {
460 if ((IsPseudo || !MatchStr.consume_front(":"))) {
461 SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
462 SourceMgr::DK_Error,
463 "invalid name in string variable definition");
464 return true;
465 }
466
467 // Detect collisions between string and numeric variables when the
468 // former is created later than the latter.
469 if (Context->GlobalNumericVariableTable.find(Name) !=
470 Context->GlobalNumericVariableTable.end()) {
471 SM.PrintMessage(
472 SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
473 "numeric variable with name '" + Name + "' already exists");
474 return true;
475 }
476 DefName = Name;
477 MatchRegexp = MatchStr;
478 } else {
479 if (IsPseudo) {
480 MatchStr = OrigMatchStr;
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000481 IsLegacyLineExpr = IsNumBlock = true;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000482 } else
483 SubstStr = Name;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000484 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000485 }
486
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000487 // Parse numeric substitution block.
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000488 std::unique_ptr<FileCheckExpressionAST> ExpressionAST;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000489 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000490 if (IsNumBlock) {
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000491 Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
492 parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000493 IsLegacyLineExpr, LineNumber, Context,
494 SM);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000495 if (!ParseResult) {
496 logAllUnhandledErrors(ParseResult.takeError(), errs());
Thomas Preud'homme15cb1f12019-04-29 17:46:26 +0000497 return true;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000498 }
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000499 ExpressionAST = std::move(*ParseResult);
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000500 SubstNeeded = ExpressionAST != nullptr;
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000501 if (DefinedNumericVariable) {
502 IsDefinition = true;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000503 DefName = (*DefinedNumericVariable)->getName();
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000504 }
505 if (SubstNeeded)
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000506 SubstStr = MatchStr;
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000507 else
508 MatchRegexp = "[0-9]+";
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000509 }
510
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000511 // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
512 if (IsDefinition) {
513 RegExStr += '(';
514 ++SubstInsertIdx;
515
516 if (IsNumBlock) {
517 FileCheckNumericVariableMatch NumericVariableDefinition = {
518 *DefinedNumericVariable, CurParen};
519 NumericVariableDefs[DefName] = NumericVariableDefinition;
520 // This store is done here rather than in match() to allow
521 // parseNumericVariableUse() to get the pointer to the class instance
522 // of the right variable definition corresponding to a given numeric
523 // variable use.
524 Context->GlobalNumericVariableTable[DefName] =
525 *DefinedNumericVariable;
526 } else {
527 VariableDefs[DefName] = CurParen;
528 // Mark string variable as defined to detect collisions between
529 // string and numeric variables in parseNumericVariableUse() and
530 // defineCmdlineVariables() when the latter is created later than the
531 // former. We cannot reuse GlobalVariableTable for this by populating
532 // it with an empty string since we would then lose the ability to
533 // detect the use of an undefined variable in match().
534 Context->DefinedVariableTable[DefName] = true;
535 }
536
537 ++CurParen;
538 }
539
540 if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))
541 return true;
542
543 if (IsDefinition)
544 RegExStr += ')';
545
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000546 // Handle substitutions: [[foo]] and [[#<foo expr>]].
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +0000547 if (SubstNeeded) {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000548 // Handle substitution of string variables that were defined earlier on
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000549 // the same line by emitting a backreference. Expressions do not
550 // support substituting a numeric variable defined on the same line.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000551 if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) {
552 unsigned CaptureParenGroup = VariableDefs[SubstStr];
553 if (CaptureParenGroup < 1 || CaptureParenGroup > 9) {
554 SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()),
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000555 SourceMgr::DK_Error,
556 "Can't back-reference more than 9 variables");
557 return true;
558 }
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000559 AddBackrefToRegEx(CaptureParenGroup);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000560 } else {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000561 // Handle substitution of string variables ([[<var>]]) defined in
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000562 // previous CHECK patterns, and substitution of expressions.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000563 FileCheckSubstitution *Substitution =
564 IsNumBlock
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000565 ? Context->makeNumericSubstitution(
566 SubstStr, std::move(ExpressionAST), SubstInsertIdx)
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000567 : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000568 Substitutions.push_back(Substitution);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000569 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000570 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000571 }
572
573 // Handle fixed string matches.
574 // Find the end, which is the start of the next regex.
575 size_t FixedMatchEnd = PatternStr.find("{{");
576 FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));
577 RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd));
578 PatternStr = PatternStr.substr(FixedMatchEnd);
579 }
580
581 if (MatchFullLinesHere) {
582 if (!Req.NoCanonicalizeWhiteSpace)
583 RegExStr += " *";
584 RegExStr += '$';
585 }
586
587 return false;
588}
589
590bool FileCheckPattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {
591 Regex R(RS);
592 std::string Error;
593 if (!R.isValid(Error)) {
594 SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error,
595 "invalid regex: " + Error);
596 return true;
597 }
598
599 RegExStr += RS.str();
600 CurParen += R.getNumMatches();
601 return false;
602}
603
604void FileCheckPattern::AddBackrefToRegEx(unsigned BackrefNum) {
605 assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");
606 std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum);
607 RegExStr += Backref;
608}
609
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000610Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
611 const SourceMgr &SM) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000612 // If this is the EOF pattern, match it immediately.
613 if (CheckTy == Check::CheckEOF) {
614 MatchLen = 0;
615 return Buffer.size();
616 }
617
618 // If this is a fixed string pattern, just match it now.
619 if (!FixedStr.empty()) {
620 MatchLen = FixedStr.size();
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000621 size_t Pos = Buffer.find(FixedStr);
622 if (Pos == StringRef::npos)
623 return make_error<FileCheckNotFoundError>();
624 return Pos;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000625 }
626
627 // Regex match.
628
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000629 // If there are substitutions, we need to create a temporary string with the
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000630 // actual value.
631 StringRef RegExToMatch = RegExStr;
632 std::string TmpStr;
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000633 if (!Substitutions.empty()) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000634 TmpStr = RegExStr;
Thomas Preud'homme99f2a102019-07-15 19:04:56 +0000635 if (LineNumber)
636 Context->LineVariable->setValue(*LineNumber);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000637
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000638 size_t InsertOffset = 0;
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000639 // Substitute all string variables and expressions whose values are only
640 // now known. Use of string variables defined on the same line are handled
641 // by back-references.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000642 for (const auto &Substitution : Substitutions) {
643 // Substitute and check for failure (e.g. use of undefined variable).
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000644 Expected<std::string> Value = Substitution->getResult();
Thomas Preud'homme70494492019-07-18 13:39:04 +0000645 if (!Value)
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000646 return Value.takeError();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000647
648 // Plop it into the regex at the adjusted offset.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000649 TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000650 Value->begin(), Value->end());
651 InsertOffset += Value->size();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000652 }
653
654 // Match the newly constructed regex.
655 RegExToMatch = TmpStr;
656 }
657
658 SmallVector<StringRef, 4> MatchInfo;
659 if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo))
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000660 return make_error<FileCheckNotFoundError>();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000661
662 // Successful regex match.
663 assert(!MatchInfo.empty() && "Didn't get any match");
664 StringRef FullMatch = MatchInfo[0];
665
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000666 // If this defines any string variables, remember their values.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000667 for (const auto &VariableDef : VariableDefs) {
668 assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000669 Context->GlobalVariableTable[VariableDef.first] =
670 MatchInfo[VariableDef.second];
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000671 }
672
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000673 // If this defines any numeric variables, remember their values.
674 for (const auto &NumericVariableDef : NumericVariableDefs) {
Thomas Preud'hommea2ef1ba2019-06-19 23:47:24 +0000675 const FileCheckNumericVariableMatch &NumericVariableMatch =
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000676 NumericVariableDef.getValue();
677 unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;
678 assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error");
679 FileCheckNumericVariable *DefinedNumericVariable =
680 NumericVariableMatch.DefinedNumericVariable;
681
682 StringRef MatchedValue = MatchInfo[CaptureParenGroup];
683 uint64_t Val;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000684 if (MatchedValue.getAsInteger(10, Val))
685 return FileCheckErrorDiagnostic::get(SM, MatchedValue,
686 "Unable to represent numeric value");
Thomas Preud'homme2bf04f22019-07-10 12:49:28 +0000687 DefinedNumericVariable->setValue(Val);
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000688 }
689
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000690 // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
691 // the required preceding newline, which is consumed by the pattern in the
692 // case of CHECK-EMPTY but not CHECK-NEXT.
693 size_t MatchStartSkip = CheckTy == Check::CheckEmpty;
694 MatchLen = FullMatch.size() - MatchStartSkip;
695 return FullMatch.data() - Buffer.data() + MatchStartSkip;
696}
697
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000698unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000699 // Just compute the number of matching characters. For regular expressions, we
700 // just compare against the regex itself and hope for the best.
701 //
702 // FIXME: One easy improvement here is have the regex lib generate a single
703 // example regular expression which matches, and use that as the example
704 // string.
705 StringRef ExampleString(FixedStr);
706 if (ExampleString.empty())
707 ExampleString = RegExStr;
708
709 // Only compare up to the first line in the buffer, or the string size.
710 StringRef BufferPrefix = Buffer.substr(0, ExampleString.size());
711 BufferPrefix = BufferPrefix.split('\n').first;
712 return BufferPrefix.edit_distance(ExampleString);
713}
714
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000715void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
716 SMRange MatchRange) const {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +0000717 // Print what we know about substitutions.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000718 if (!Substitutions.empty()) {
719 for (const auto &Substitution : Substitutions) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000720 SmallString<256> Msg;
721 raw_svector_ostream OS(Msg);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000722 Expected<std::string> MatchedValue = Substitution->getResult();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000723
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000724 // Substitution failed or is not known at match time, print the undefined
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000725 // variables it uses.
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000726 if (!MatchedValue) {
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000727 bool UndefSeen = false;
728 handleAllErrors(MatchedValue.takeError(),
729 [](const FileCheckNotFoundError &E) {},
Thomas Preud'hommea188ad22019-07-05 12:00:56 +0000730 // Handled in PrintNoMatch().
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000731 [](const FileCheckErrorDiagnostic &E) {},
732 [&](const FileCheckUndefVarError &E) {
733 if (!UndefSeen) {
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000734 OS << "uses undefined variable(s):";
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000735 UndefSeen = true;
736 }
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000737 OS << " ";
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000738 E.log(OS);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000739 });
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000740 } else {
741 // Substitution succeeded. Print substituted value.
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000742 OS << "with \"";
743 OS.write_escaped(Substitution->getFromString()) << "\" equal to \"";
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000744 OS.write_escaped(*MatchedValue) << "\"";
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000745 }
746
747 if (MatchRange.isValid())
748 SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(),
749 {MatchRange});
750 else
751 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
752 SourceMgr::DK_Note, OS.str());
753 }
754 }
755}
756
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000757static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,
758 const SourceMgr &SM, SMLoc Loc,
759 Check::FileCheckType CheckTy,
760 StringRef Buffer, size_t Pos, size_t Len,
Joel E. Denny7df86962018-12-18 00:03:03 +0000761 std::vector<FileCheckDiag> *Diags,
762 bool AdjustPrevDiag = false) {
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000763 SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);
764 SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);
765 SMRange Range(Start, End);
Joel E. Denny96f0e842018-12-18 00:03:36 +0000766 if (Diags) {
Joel E. Denny7df86962018-12-18 00:03:03 +0000767 if (AdjustPrevDiag)
768 Diags->rbegin()->MatchTy = MatchTy;
769 else
770 Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
771 }
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000772 return Range;
773}
774
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000775void FileCheckPattern::printFuzzyMatch(
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000776 const SourceMgr &SM, StringRef Buffer,
Joel E. Denny2c007c82018-12-18 00:02:04 +0000777 std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000778 // Attempt to find the closest/best fuzzy match. Usually an error happens
779 // because some string in the output didn't exactly match. In these cases, we
780 // would like to show the user a best guess at what "should have" matched, to
781 // save them having to actually check the input manually.
782 size_t NumLinesForward = 0;
783 size_t Best = StringRef::npos;
784 double BestQuality = 0;
785
786 // Use an arbitrary 4k limit on how far we will search.
787 for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) {
788 if (Buffer[i] == '\n')
789 ++NumLinesForward;
790
791 // Patterns have leading whitespace stripped, so skip whitespace when
792 // looking for something which looks like a pattern.
793 if (Buffer[i] == ' ' || Buffer[i] == '\t')
794 continue;
795
796 // Compute the "quality" of this match as an arbitrary combination of the
797 // match distance and the number of lines skipped to get to this match.
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000798 unsigned Distance = computeMatchDistance(Buffer.substr(i));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000799 double Quality = Distance + (NumLinesForward / 100.);
800
801 if (Quality < BestQuality || Best == StringRef::npos) {
802 Best = i;
803 BestQuality = Quality;
804 }
805 }
806
807 // Print the "possible intended match here" line if we found something
808 // reasonable and not equal to what we showed in the "scanning from here"
809 // line.
810 if (Best && Best != StringRef::npos && BestQuality < 50) {
Joel E. Denny2c007c82018-12-18 00:02:04 +0000811 SMRange MatchRange =
812 ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(),
813 getCheckTy(), Buffer, Best, 0, Diags);
814 SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note,
815 "possible intended match here");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000816
817 // FIXME: If we wanted to be really friendly we would show why the match
818 // failed, as it can be hard to spot simple one character differences.
819 }
820}
821
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000822Expected<StringRef>
Thomas Preud'homme288ed912019-05-02 00:04:38 +0000823FileCheckPatternContext::getPatternVarValue(StringRef VarName) {
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000824 auto VarIter = GlobalVariableTable.find(VarName);
825 if (VarIter == GlobalVariableTable.end())
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +0000826 return make_error<FileCheckUndefVarError>(VarName);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +0000827
828 return VarIter->second;
829}
830
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000831template <class... Types>
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000832FileCheckNumericVariable *
Thomas Preud'homme71d3f222019-06-06 13:21:06 +0000833FileCheckPatternContext::makeNumericVariable(Types... args) {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000834 NumericVariables.push_back(
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000835 std::make_unique<FileCheckNumericVariable>(args...));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +0000836 return NumericVariables.back().get();
837}
838
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000839FileCheckSubstitution *
840FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
841 size_t InsertIdx) {
842 Substitutions.push_back(
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000843 std::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000844 return Substitutions.back().get();
845}
846
847FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000848 StringRef ExpressionStr,
849 std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) {
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000850 Substitutions.push_back(std::make_unique<FileCheckNumericSubstitution>(
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +0000851 this, ExpressionStr, std::move(ExpressionAST), InsertIdx));
Thomas Preud'hommef3b9bb32019-05-23 00:10:29 +0000852 return Substitutions.back().get();
853}
854
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000855size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {
856 // Offset keeps track of the current offset within the input Str
857 size_t Offset = 0;
858 // [...] Nesting depth
859 size_t BracketDepth = 0;
860
861 while (!Str.empty()) {
862 if (Str.startswith("]]") && BracketDepth == 0)
863 return Offset;
864 if (Str[0] == '\\') {
865 // Backslash escapes the next char within regexes, so skip them both.
866 Str = Str.substr(2);
867 Offset += 2;
868 } else {
869 switch (Str[0]) {
870 default:
871 break;
872 case '[':
873 BracketDepth++;
874 break;
875 case ']':
876 if (BracketDepth == 0) {
877 SM.PrintMessage(SMLoc::getFromPointer(Str.data()),
878 SourceMgr::DK_Error,
879 "missing closing \"]\" for regex variable");
880 exit(1);
881 }
882 BracketDepth--;
883 break;
884 }
885 Str = Str.substr(1);
886 Offset++;
887 }
888 }
889
890 return StringRef::npos;
891}
892
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +0000893StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB,
894 SmallVectorImpl<char> &OutputBuffer) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000895 OutputBuffer.reserve(MB.getBufferSize());
896
897 for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd();
898 Ptr != End; ++Ptr) {
899 // Eliminate trailing dosish \r.
900 if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {
901 continue;
902 }
903
904 // If current char is not a horizontal whitespace or if horizontal
905 // whitespace canonicalization is disabled, dump it to output as is.
906 if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) {
907 OutputBuffer.push_back(*Ptr);
908 continue;
909 }
910
911 // Otherwise, add one space and advance over neighboring space.
912 OutputBuffer.push_back(' ');
913 while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t'))
914 ++Ptr;
915 }
916
917 // Add a null byte and then return all but that byte.
918 OutputBuffer.push_back('\0');
919 return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);
920}
921
Joel E. Denny3c5d2672018-12-18 00:01:39 +0000922FileCheckDiag::FileCheckDiag(const SourceMgr &SM,
923 const Check::FileCheckType &CheckTy,
924 SMLoc CheckLoc, MatchType MatchTy,
925 SMRange InputRange)
926 : CheckTy(CheckTy), MatchTy(MatchTy) {
927 auto Start = SM.getLineAndColumn(InputRange.Start);
928 auto End = SM.getLineAndColumn(InputRange.End);
929 InputStartLine = Start.first;
930 InputStartCol = Start.second;
931 InputEndLine = End.first;
932 InputEndCol = End.second;
933 Start = SM.getLineAndColumn(CheckLoc);
934 CheckLine = Start.first;
935 CheckCol = Start.second;
936}
937
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000938static bool IsPartOfWord(char c) {
939 return (isalnum(c) || c == '-' || c == '_');
940}
941
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000942Check::FileCheckType &Check::FileCheckType::setCount(int C) {
Fedor Sergeev8477a3e2018-11-13 01:09:53 +0000943 assert(Count > 0 && "zero and negative counts are not supported");
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000944 assert((C == 1 || Kind == CheckPlain) &&
945 "count supported only for plain CHECK directives");
946 Count = C;
947 return *this;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000948}
949
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000950std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
951 switch (Kind) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000952 case Check::CheckNone:
953 return "invalid";
954 case Check::CheckPlain:
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000955 if (Count > 1)
956 return Prefix.str() + "-COUNT";
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000957 return Prefix;
958 case Check::CheckNext:
959 return Prefix.str() + "-NEXT";
960 case Check::CheckSame:
961 return Prefix.str() + "-SAME";
962 case Check::CheckNot:
963 return Prefix.str() + "-NOT";
964 case Check::CheckDAG:
965 return Prefix.str() + "-DAG";
966 case Check::CheckLabel:
967 return Prefix.str() + "-LABEL";
968 case Check::CheckEmpty:
969 return Prefix.str() + "-EMPTY";
970 case Check::CheckEOF:
971 return "implicit EOF";
972 case Check::CheckBadNot:
973 return "bad NOT";
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000974 case Check::CheckBadCount:
975 return "bad COUNT";
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000976 }
977 llvm_unreachable("unknown FileCheckType");
978}
979
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000980static std::pair<Check::FileCheckType, StringRef>
981FindCheckType(StringRef Buffer, StringRef Prefix) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000982 if (Buffer.size() <= Prefix.size())
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000983 return {Check::CheckNone, StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000984
985 char NextChar = Buffer[Prefix.size()];
986
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000987 StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000988 // Verify that the : is present after the prefix.
989 if (NextChar == ':')
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000990 return {Check::CheckPlain, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000991
992 if (NextChar != '-')
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000993 return {Check::CheckNone, StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +0000994
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +0000995 if (Rest.consume_front("COUNT-")) {
996 int64_t Count;
997 if (Rest.consumeInteger(10, Count))
998 // Error happened in parsing integer.
999 return {Check::CheckBadCount, Rest};
1000 if (Count <= 0 || Count > INT32_MAX)
1001 return {Check::CheckBadCount, Rest};
1002 if (!Rest.consume_front(":"))
1003 return {Check::CheckBadCount, Rest};
1004 return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest};
1005 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001006
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001007 if (Rest.consume_front("NEXT:"))
1008 return {Check::CheckNext, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001009
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001010 if (Rest.consume_front("SAME:"))
1011 return {Check::CheckSame, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001012
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001013 if (Rest.consume_front("NOT:"))
1014 return {Check::CheckNot, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001015
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001016 if (Rest.consume_front("DAG:"))
1017 return {Check::CheckDAG, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001018
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001019 if (Rest.consume_front("LABEL:"))
1020 return {Check::CheckLabel, Rest};
1021
1022 if (Rest.consume_front("EMPTY:"))
1023 return {Check::CheckEmpty, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001024
1025 // You can't combine -NOT with another suffix.
1026 if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
1027 Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
1028 Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||
1029 Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001030 return {Check::CheckBadNot, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001031
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001032 return {Check::CheckNone, Rest};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001033}
1034
1035// From the given position, find the next character after the word.
1036static size_t SkipWord(StringRef Str, size_t Loc) {
1037 while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
1038 ++Loc;
1039 return Loc;
1040}
1041
Thomas Preud'homme4a8ef112019-05-08 21:47:31 +00001042/// Searches the buffer for the first prefix in the prefix regular expression.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001043///
1044/// This searches the buffer using the provided regular expression, however it
1045/// enforces constraints beyond that:
1046/// 1) The found prefix must not be a suffix of something that looks like
1047/// a valid prefix.
1048/// 2) The found prefix must be followed by a valid check type suffix using \c
1049/// FindCheckType above.
1050///
Thomas Preud'homme4a8ef112019-05-08 21:47:31 +00001051/// \returns a pair of StringRefs into the Buffer, which combines:
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001052/// - the first match of the regular expression to satisfy these two is
1053/// returned,
1054/// otherwise an empty StringRef is returned to indicate failure.
1055/// - buffer rewound to the location right after parsed suffix, for parsing
1056/// to continue from
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001057///
1058/// If this routine returns a valid prefix, it will also shrink \p Buffer to
1059/// start at the beginning of the returned prefix, increment \p LineNumber for
1060/// each new line consumed from \p Buffer, and set \p CheckTy to the type of
1061/// check found by examining the suffix.
1062///
1063/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy
1064/// is unspecified.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001065static std::pair<StringRef, StringRef>
1066FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
1067 unsigned &LineNumber, Check::FileCheckType &CheckTy) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001068 SmallVector<StringRef, 2> Matches;
1069
1070 while (!Buffer.empty()) {
1071 // Find the first (longest) match using the RE.
1072 if (!PrefixRE.match(Buffer, &Matches))
1073 // No match at all, bail.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001074 return {StringRef(), StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001075
1076 StringRef Prefix = Matches[0];
1077 Matches.clear();
1078
1079 assert(Prefix.data() >= Buffer.data() &&
1080 Prefix.data() < Buffer.data() + Buffer.size() &&
1081 "Prefix doesn't start inside of buffer!");
1082 size_t Loc = Prefix.data() - Buffer.data();
1083 StringRef Skipped = Buffer.substr(0, Loc);
1084 Buffer = Buffer.drop_front(Loc);
1085 LineNumber += Skipped.count('\n');
1086
1087 // Check that the matched prefix isn't a suffix of some other check-like
1088 // word.
1089 // FIXME: This is a very ad-hoc check. it would be better handled in some
1090 // other way. Among other things it seems hard to distinguish between
1091 // intentional and unintentional uses of this feature.
1092 if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {
1093 // Now extract the type.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001094 StringRef AfterSuffix;
1095 std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001096
1097 // If we've found a valid check type for this prefix, we're done.
1098 if (CheckTy != Check::CheckNone)
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001099 return {Prefix, AfterSuffix};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001100 }
1101
1102 // If we didn't successfully find a prefix, we need to skip this invalid
1103 // prefix and continue scanning. We directly skip the prefix that was
1104 // matched and any additional parts of that check-like word.
1105 Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size()));
1106 }
1107
1108 // We ran out of buffer while skipping partial matches so give up.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001109 return {StringRef(), StringRef()};
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001110}
1111
Thomas Preud'homme56f63082019-07-05 16:25:46 +00001112void FileCheckPatternContext::createLineVariable() {
1113 assert(!LineVariable && "@LINE pseudo numeric variable already created");
1114 StringRef LineName = "@LINE";
Thomas Preud'homme99f2a102019-07-15 19:04:56 +00001115 LineVariable = makeNumericVariable(LineName);
Thomas Preud'homme56f63082019-07-05 16:25:46 +00001116 GlobalNumericVariableTable[LineName] = LineVariable;
1117}
1118
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +00001119bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
1120 std::vector<FileCheckString> &CheckStrings) {
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001121 Error DefineError =
1122 PatternContext.defineCmdlineVariables(Req.GlobalDefines, SM);
1123 if (DefineError) {
1124 logAllUnhandledErrors(std::move(DefineError), errs());
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001125 return true;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001126 }
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001127
Thomas Preud'homme56f63082019-07-05 16:25:46 +00001128 PatternContext.createLineVariable();
1129
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001130 std::vector<FileCheckPattern> ImplicitNegativeChecks;
1131 for (const auto &PatternString : Req.ImplicitCheckNot) {
1132 // Create a buffer with fake command line content in order to display the
1133 // command line option responsible for the specific implicit CHECK-NOT.
1134 std::string Prefix = "-implicit-check-not='";
1135 std::string Suffix = "'";
1136 std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(
1137 Prefix + PatternString + Suffix, "command line");
1138
1139 StringRef PatternInBuffer =
1140 CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
1141 SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
1142
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001143 ImplicitNegativeChecks.push_back(
Thomas Preud'homme99f2a102019-07-15 19:04:56 +00001144 FileCheckPattern(Check::CheckNot, &PatternContext));
Thomas Preud'homme71d3f222019-06-06 13:21:06 +00001145 ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,
1146 "IMPLICIT-CHECK", SM, Req);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001147 }
1148
1149 std::vector<FileCheckPattern> DagNotMatches = ImplicitNegativeChecks;
1150
1151 // LineNumber keeps track of the line on which CheckPrefix instances are
1152 // found.
1153 unsigned LineNumber = 1;
1154
1155 while (1) {
1156 Check::FileCheckType CheckTy;
1157
1158 // See if a prefix occurs in the memory buffer.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001159 StringRef UsedPrefix;
1160 StringRef AfterSuffix;
1161 std::tie(UsedPrefix, AfterSuffix) =
1162 FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001163 if (UsedPrefix.empty())
1164 break;
1165 assert(UsedPrefix.data() == Buffer.data() &&
1166 "Failed to move Buffer's start forward, or pointed prefix outside "
1167 "of the buffer!");
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001168 assert(AfterSuffix.data() >= Buffer.data() &&
1169 AfterSuffix.data() < Buffer.data() + Buffer.size() &&
1170 "Parsing after suffix doesn't start inside of buffer!");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001171
1172 // Location to use for error messages.
1173 const char *UsedPrefixStart = UsedPrefix.data();
1174
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001175 // Skip the buffer to the end of parsed suffix (or just prefix, if no good
1176 // suffix was processed).
1177 Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size())
1178 : AfterSuffix;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001179
1180 // Complain about useful-looking but unsupported suffixes.
1181 if (CheckTy == Check::CheckBadNot) {
1182 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
1183 "unsupported -NOT combo on prefix '" + UsedPrefix + "'");
1184 return true;
1185 }
1186
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001187 // Complain about invalid count specification.
1188 if (CheckTy == Check::CheckBadCount) {
1189 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
1190 "invalid count in -COUNT specification on prefix '" +
1191 UsedPrefix + "'");
1192 return true;
1193 }
1194
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001195 // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
1196 // leading whitespace.
1197 if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
1198 Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
1199
1200 // Scan ahead to the end of line.
1201 size_t EOL = Buffer.find_first_of("\n\r");
1202
1203 // Remember the location of the start of the pattern, for diagnostics.
1204 SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
1205
1206 // Parse the pattern.
Thomas Preud'homme71d3f222019-06-06 13:21:06 +00001207 FileCheckPattern P(CheckTy, &PatternContext, LineNumber);
1208 if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001209 return true;
1210
1211 // Verify that CHECK-LABEL lines do not define or use variables
1212 if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {
1213 SM.PrintMessage(
1214 SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error,
1215 "found '" + UsedPrefix + "-LABEL:'"
1216 " with variable definition or use");
1217 return true;
1218 }
1219
1220 Buffer = Buffer.substr(EOL);
1221
1222 // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
1223 if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
1224 CheckTy == Check::CheckEmpty) &&
1225 CheckStrings.empty()) {
1226 StringRef Type = CheckTy == Check::CheckNext
1227 ? "NEXT"
1228 : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";
1229 SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
1230 SourceMgr::DK_Error,
1231 "found '" + UsedPrefix + "-" + Type +
1232 "' without previous '" + UsedPrefix + ": line");
1233 return true;
1234 }
1235
1236 // Handle CHECK-DAG/-NOT.
1237 if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {
1238 DagNotMatches.push_back(P);
1239 continue;
1240 }
1241
1242 // Okay, add the string we captured to the output vector and move on.
1243 CheckStrings.emplace_back(P, UsedPrefix, PatternLoc);
1244 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
1245 DagNotMatches = ImplicitNegativeChecks;
1246 }
1247
1248 // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
1249 // prefix as a filler for the error message.
1250 if (!DagNotMatches.empty()) {
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001251 CheckStrings.emplace_back(
Thomas Preud'homme71d3f222019-06-06 13:21:06 +00001252 FileCheckPattern(Check::CheckEOF, &PatternContext, LineNumber + 1),
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001253 *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001254 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
1255 }
1256
1257 if (CheckStrings.empty()) {
1258 errs() << "error: no check strings found with prefix"
1259 << (Req.CheckPrefixes.size() > 1 ? "es " : " ");
1260 auto I = Req.CheckPrefixes.begin();
1261 auto E = Req.CheckPrefixes.end();
1262 if (I != E) {
1263 errs() << "\'" << *I << ":'";
1264 ++I;
1265 }
1266 for (; I != E; ++I)
1267 errs() << ", \'" << *I << ":'";
1268
1269 errs() << '\n';
1270 return true;
1271 }
1272
1273 return false;
1274}
1275
1276static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
1277 StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001278 int MatchedCount, StringRef Buffer, size_t MatchPos,
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001279 size_t MatchLen, const FileCheckRequest &Req,
1280 std::vector<FileCheckDiag> *Diags) {
Joel E. Denny352695c2019-01-22 21:41:42 +00001281 bool PrintDiag = true;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001282 if (ExpectedMatch) {
1283 if (!Req.Verbose)
1284 return;
1285 if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)
1286 return;
Joel E. Denny352695c2019-01-22 21:41:42 +00001287 // Due to their verbosity, we don't print verbose diagnostics here if we're
1288 // gathering them for a different rendering, but we always print other
1289 // diagnostics.
1290 PrintDiag = !Diags;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001291 }
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001292 SMRange MatchRange = ProcessMatchResult(
Joel E. Dennye2afb612018-12-18 00:03:51 +00001293 ExpectedMatch ? FileCheckDiag::MatchFoundAndExpected
1294 : FileCheckDiag::MatchFoundButExcluded,
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001295 SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);
Joel E. Denny352695c2019-01-22 21:41:42 +00001296 if (!PrintDiag)
1297 return;
1298
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001299 std::string Message = formatv("{0}: {1} string found in input",
1300 Pat.getCheckTy().getDescription(Prefix),
1301 (ExpectedMatch ? "expected" : "excluded"))
1302 .str();
1303 if (Pat.getCount() > 1)
1304 Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
1305
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001306 SM.PrintMessage(
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001307 Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001308 SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
1309 {MatchRange});
Thomas Preud'homme288ed912019-05-02 00:04:38 +00001310 Pat.printSubstitutions(SM, Buffer, MatchRange);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001311}
1312
1313static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001314 const FileCheckString &CheckStr, int MatchedCount,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001315 StringRef Buffer, size_t MatchPos, size_t MatchLen,
1316 FileCheckRequest &Req,
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001317 std::vector<FileCheckDiag> *Diags) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001318 PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001319 MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001320}
1321
1322static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001323 StringRef Prefix, SMLoc Loc,
1324 const FileCheckPattern &Pat, int MatchedCount,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001325 StringRef Buffer, bool VerboseVerbose,
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001326 std::vector<FileCheckDiag> *Diags, Error MatchErrors) {
1327 assert(MatchErrors && "Called on successful match");
Joel E. Denny352695c2019-01-22 21:41:42 +00001328 bool PrintDiag = true;
1329 if (!ExpectedMatch) {
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001330 if (!VerboseVerbose) {
1331 consumeError(std::move(MatchErrors));
Joel E. Denny352695c2019-01-22 21:41:42 +00001332 return;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001333 }
Joel E. Denny352695c2019-01-22 21:41:42 +00001334 // Due to their verbosity, we don't print verbose diagnostics here if we're
1335 // gathering them for a different rendering, but we always print other
1336 // diagnostics.
1337 PrintDiag = !Diags;
1338 }
1339
1340 // If the current position is at the end of a line, advance to the start of
1341 // the next line.
1342 Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));
1343 SMRange SearchRange = ProcessMatchResult(
1344 ExpectedMatch ? FileCheckDiag::MatchNoneButExpected
1345 : FileCheckDiag::MatchNoneAndExcluded,
1346 SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001347 if (!PrintDiag) {
1348 consumeError(std::move(MatchErrors));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001349 return;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001350 }
1351
1352 MatchErrors =
1353 handleErrors(std::move(MatchErrors),
1354 [](const FileCheckErrorDiagnostic &E) { E.log(errs()); });
1355
1356 // No problem matching the string per se.
1357 if (!MatchErrors)
1358 return;
1359 consumeError(std::move(MatchErrors));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001360
Joel E. Denny352695c2019-01-22 21:41:42 +00001361 // Print "not found" diagnostic.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001362 std::string Message = formatv("{0}: {1} string not found in input",
1363 Pat.getCheckTy().getDescription(Prefix),
1364 (ExpectedMatch ? "expected" : "excluded"))
1365 .str();
1366 if (Pat.getCount() > 1)
1367 Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001368 SM.PrintMessage(
1369 Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001370
Joel E. Denny352695c2019-01-22 21:41:42 +00001371 // Print the "scanning from here" line.
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001372 SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001373
1374 // Allow the pattern to print additional information if desired.
Thomas Preud'homme288ed912019-05-02 00:04:38 +00001375 Pat.printSubstitutions(SM, Buffer);
Joel E. Denny96f0e842018-12-18 00:03:36 +00001376
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001377 if (ExpectedMatch)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001378 Pat.printFuzzyMatch(SM, Buffer, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001379}
1380
1381static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001382 const FileCheckString &CheckStr, int MatchedCount,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001383 StringRef Buffer, bool VerboseVerbose,
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001384 std::vector<FileCheckDiag> *Diags, Error MatchErrors) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001385 PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001386 MatchedCount, Buffer, VerboseVerbose, Diags,
1387 std::move(MatchErrors));
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001388}
1389
Thomas Preud'homme4a8ef112019-05-08 21:47:31 +00001390/// Counts the number of newlines in the specified range.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001391static unsigned CountNumNewlinesBetween(StringRef Range,
1392 const char *&FirstNewLine) {
1393 unsigned NumNewLines = 0;
1394 while (1) {
1395 // Scan for newline.
1396 Range = Range.substr(Range.find_first_of("\n\r"));
1397 if (Range.empty())
1398 return NumNewLines;
1399
1400 ++NumNewLines;
1401
1402 // Handle \n\r and \r\n as a single newline.
1403 if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&
1404 (Range[0] != Range[1]))
1405 Range = Range.substr(1);
1406 Range = Range.substr(1);
1407
1408 if (NumNewLines == 1)
1409 FirstNewLine = Range.begin();
1410 }
1411}
1412
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001413size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001414 bool IsLabelScanMode, size_t &MatchLen,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001415 FileCheckRequest &Req,
1416 std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001417 size_t LastPos = 0;
1418 std::vector<const FileCheckPattern *> NotStrings;
1419
1420 // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL
1421 // bounds; we have not processed variable definitions within the bounded block
1422 // yet so cannot handle any final CHECK-DAG yet; this is handled when going
1423 // over the block again (including the last CHECK-LABEL) in normal mode.
1424 if (!IsLabelScanMode) {
1425 // Match "dag strings" (with mixed "not strings" if any).
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001426 LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001427 if (LastPos == StringRef::npos)
1428 return StringRef::npos;
1429 }
1430
1431 // Match itself from the last position after matching CHECK-DAG.
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001432 size_t LastMatchEnd = LastPos;
1433 size_t FirstMatchPos = 0;
1434 // Go match the pattern Count times. Majority of patterns only match with
1435 // count 1 though.
1436 assert(Pat.getCount() != 0 && "pattern count can not be zero");
1437 for (int i = 1; i <= Pat.getCount(); i++) {
1438 StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
1439 size_t CurrentMatchLen;
1440 // get a match at current start point
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001441 Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM);
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001442
1443 // report
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001444 if (!MatchResult) {
1445 PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags,
1446 MatchResult.takeError());
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001447 return StringRef::npos;
1448 }
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001449 size_t MatchPos = *MatchResult;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001450 PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
1451 Diags);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001452 if (i == 1)
1453 FirstMatchPos = LastPos + MatchPos;
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001454
1455 // move start point after the match
1456 LastMatchEnd += MatchPos + CurrentMatchLen;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001457 }
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001458 // Full match len counts from first match pos.
1459 MatchLen = LastMatchEnd - FirstMatchPos;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001460
1461 // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
1462 // or CHECK-NOT
1463 if (!IsLabelScanMode) {
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001464 size_t MatchPos = FirstMatchPos - LastPos;
1465 StringRef MatchBuffer = Buffer.substr(LastPos);
1466 StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001467
1468 // If this check is a "CHECK-NEXT", verify that the previous match was on
1469 // the previous line (i.e. that there is one newline between them).
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001470 if (CheckNext(SM, SkippedRegion)) {
Joel E. Dennye2afb612018-12-18 00:03:51 +00001471 ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001472 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
Joel E. Denny7df86962018-12-18 00:03:03 +00001473 Diags, Req.Verbose);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001474 return StringRef::npos;
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001475 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001476
1477 // If this check is a "CHECK-SAME", verify that the previous match was on
1478 // the same line (i.e. that there is no newline between them).
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001479 if (CheckSame(SM, SkippedRegion)) {
Joel E. Dennye2afb612018-12-18 00:03:51 +00001480 ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001481 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
Joel E. Denny7df86962018-12-18 00:03:03 +00001482 Diags, Req.Verbose);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001483 return StringRef::npos;
Joel E. Dennycadfcef2018-12-18 00:02:22 +00001484 }
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001485
1486 // If this match had "not strings", verify that they don't exist in the
1487 // skipped region.
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001488 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001489 return StringRef::npos;
1490 }
1491
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001492 return FirstMatchPos;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001493}
1494
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001495bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
1496 if (Pat.getCheckTy() != Check::CheckNext &&
1497 Pat.getCheckTy() != Check::CheckEmpty)
1498 return false;
1499
1500 Twine CheckName =
1501 Prefix +
1502 Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");
1503
1504 // Count the number of newlines between the previous match and this one.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001505 const char *FirstNewLine = nullptr;
1506 unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
1507
1508 if (NumNewLines == 0) {
1509 SM.PrintMessage(Loc, SourceMgr::DK_Error,
1510 CheckName + ": is on the same line as previous match");
1511 SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
1512 "'next' match was here");
1513 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
1514 "previous match ended here");
1515 return true;
1516 }
1517
1518 if (NumNewLines != 1) {
1519 SM.PrintMessage(Loc, SourceMgr::DK_Error,
1520 CheckName +
1521 ": is not on the line after the previous match");
1522 SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
1523 "'next' match was here");
1524 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
1525 "previous match ended here");
1526 SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note,
1527 "non-matching line after previous match is here");
1528 return true;
1529 }
1530
1531 return false;
1532}
1533
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001534bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
1535 if (Pat.getCheckTy() != Check::CheckSame)
1536 return false;
1537
1538 // Count the number of newlines between the previous match and this one.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001539 const char *FirstNewLine = nullptr;
1540 unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
1541
1542 if (NumNewLines != 0) {
1543 SM.PrintMessage(Loc, SourceMgr::DK_Error,
1544 Prefix +
1545 "-SAME: is not on the same line as the previous match");
1546 SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
1547 "'next' match was here");
1548 SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
1549 "previous match ended here");
1550 return true;
1551 }
1552
1553 return false;
1554}
1555
Joel E. Denny0e7e3fa2018-12-18 00:02:47 +00001556bool FileCheckString::CheckNot(
1557 const SourceMgr &SM, StringRef Buffer,
1558 const std::vector<const FileCheckPattern *> &NotStrings,
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001559 const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001560 for (const FileCheckPattern *Pat : NotStrings) {
1561 assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
1562
1563 size_t MatchLen = 0;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001564 Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001565
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001566 if (!MatchResult) {
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001567 PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001568 Req.VerboseVerbose, Diags, MatchResult.takeError());
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001569 continue;
1570 }
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001571 size_t Pos = *MatchResult;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001572
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001573 PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,
1574 Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001575
1576 return true;
1577 }
1578
1579 return false;
1580}
1581
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001582size_t
1583FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
1584 std::vector<const FileCheckPattern *> &NotStrings,
Joel E. Denny3c5d2672018-12-18 00:01:39 +00001585 const FileCheckRequest &Req,
1586 std::vector<FileCheckDiag> *Diags) const {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001587 if (DagNotStrings.empty())
1588 return 0;
1589
1590 // The start of the search range.
1591 size_t StartPos = 0;
1592
1593 struct MatchRange {
1594 size_t Pos;
1595 size_t End;
1596 };
1597 // A sorted list of ranges for non-overlapping CHECK-DAG matches. Match
1598 // ranges are erased from this list once they are no longer in the search
1599 // range.
1600 std::list<MatchRange> MatchRanges;
1601
1602 // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG
1603 // group, so we don't use a range-based for loop here.
1604 for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
1605 PatItr != PatEnd; ++PatItr) {
1606 const FileCheckPattern &Pat = *PatItr;
1607 assert((Pat.getCheckTy() == Check::CheckDAG ||
1608 Pat.getCheckTy() == Check::CheckNot) &&
1609 "Invalid CHECK-DAG or CHECK-NOT!");
1610
1611 if (Pat.getCheckTy() == Check::CheckNot) {
1612 NotStrings.push_back(&Pat);
1613 continue;
1614 }
1615
1616 assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");
1617
1618 // CHECK-DAG always matches from the start.
1619 size_t MatchLen = 0, MatchPos = StartPos;
1620
1621 // Search for a match that doesn't overlap a previous match in this
1622 // CHECK-DAG group.
1623 for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
1624 StringRef MatchBuffer = Buffer.substr(MatchPos);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001625 Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001626 // With a group of CHECK-DAGs, a single mismatching means the match on
1627 // that group of CHECK-DAGs fails immediately.
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001628 if (!MatchResult) {
Fedor Sergeev6c9e19b2018-11-13 00:46:13 +00001629 PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001630 Req.VerboseVerbose, Diags, MatchResult.takeError());
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001631 return StringRef::npos;
1632 }
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001633 size_t MatchPosBuf = *MatchResult;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001634 // Re-calc it as the offset relative to the start of the original string.
1635 MatchPos += MatchPosBuf;
1636 if (Req.VerboseVerbose)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001637 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
1638 MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001639 MatchRange M{MatchPos, MatchPos + MatchLen};
1640 if (Req.AllowDeprecatedDagOverlap) {
1641 // We don't need to track all matches in this mode, so we just maintain
1642 // one match range that encompasses the current CHECK-DAG group's
1643 // matches.
1644 if (MatchRanges.empty())
1645 MatchRanges.insert(MatchRanges.end(), M);
1646 else {
1647 auto Block = MatchRanges.begin();
1648 Block->Pos = std::min(Block->Pos, M.Pos);
1649 Block->End = std::max(Block->End, M.End);
1650 }
1651 break;
1652 }
1653 // Iterate previous matches until overlapping match or insertion point.
1654 bool Overlap = false;
1655 for (; MI != ME; ++MI) {
1656 if (M.Pos < MI->End) {
1657 // !Overlap => New match has no overlap and is before this old match.
1658 // Overlap => New match overlaps this old match.
1659 Overlap = MI->Pos < M.End;
1660 break;
1661 }
1662 }
1663 if (!Overlap) {
1664 // Insert non-overlapping match into list.
1665 MatchRanges.insert(MI, M);
1666 break;
1667 }
1668 if (Req.VerboseVerbose) {
Joel E. Denny352695c2019-01-22 21:41:42 +00001669 // Due to their verbosity, we don't print verbose diagnostics here if
1670 // we're gathering them for a different rendering, but we always print
1671 // other diagnostics.
1672 if (!Diags) {
1673 SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);
1674 SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);
1675 SMRange OldRange(OldStart, OldEnd);
1676 SM.PrintMessage(OldStart, SourceMgr::DK_Note,
1677 "match discarded, overlaps earlier DAG match here",
1678 {OldRange});
1679 } else
Joel E. Dennye2afb612018-12-18 00:03:51 +00001680 Diags->rbegin()->MatchTy = FileCheckDiag::MatchFoundButDiscarded;
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001681 }
1682 MatchPos = MI->End;
1683 }
1684 if (!Req.VerboseVerbose)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001685 PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
1686 MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001687
1688 // Handle the end of a CHECK-DAG group.
1689 if (std::next(PatItr) == PatEnd ||
1690 std::next(PatItr)->getCheckTy() == Check::CheckNot) {
1691 if (!NotStrings.empty()) {
1692 // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
1693 // CHECK-DAG, verify that there are no 'not' strings occurred in that
1694 // region.
1695 StringRef SkippedRegion =
1696 Buffer.slice(StartPos, MatchRanges.begin()->Pos);
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001697 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001698 return StringRef::npos;
1699 // Clear "not strings".
1700 NotStrings.clear();
1701 }
1702 // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the
1703 // end of this CHECK-DAG group's match range.
1704 StartPos = MatchRanges.rbegin()->End;
1705 // Don't waste time checking for (impossible) overlaps before that.
1706 MatchRanges.clear();
1707 }
1708 }
1709
1710 return StartPos;
1711}
1712
1713// A check prefix must contain only alphanumeric, hyphens and underscores.
1714static bool ValidateCheckPrefix(StringRef CheckPrefix) {
1715 Regex Validator("^[a-zA-Z0-9_-]*$");
1716 return Validator.match(CheckPrefix);
1717}
1718
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +00001719bool FileCheck::ValidateCheckPrefixes() {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001720 StringSet<> PrefixSet;
1721
1722 for (StringRef Prefix : Req.CheckPrefixes) {
1723 // Reject empty prefixes.
1724 if (Prefix == "")
1725 return false;
1726
1727 if (!PrefixSet.insert(Prefix).second)
1728 return false;
1729
1730 if (!ValidateCheckPrefix(Prefix))
1731 return false;
1732 }
1733
1734 return true;
1735}
1736
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +00001737Regex FileCheck::buildCheckPrefixRegex() {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001738 // I don't think there's a way to specify an initial value for cl::list,
1739 // so if nothing was specified, add the default
1740 if (Req.CheckPrefixes.empty())
1741 Req.CheckPrefixes.push_back("CHECK");
1742
1743 // We already validated the contents of CheckPrefixes so just concatenate
1744 // them as alternatives.
1745 SmallString<32> PrefixRegexStr;
1746 for (StringRef Prefix : Req.CheckPrefixes) {
1747 if (Prefix != Req.CheckPrefixes.front())
1748 PrefixRegexStr.push_back('|');
1749
1750 PrefixRegexStr.append(Prefix);
1751 }
1752
1753 return Regex(PrefixRegexStr);
1754}
1755
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001756Error FileCheckPatternContext::defineCmdlineVariables(
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001757 std::vector<std::string> &CmdlineDefines, SourceMgr &SM) {
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001758 assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001759 "Overriding defined variable with command-line variable definitions");
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001760
1761 if (CmdlineDefines.empty())
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001762 return Error::success();
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001763
1764 // Create a string representing the vector of command-line definitions. Each
1765 // definition is on its own line and prefixed with a definition number to
1766 // clarify which definition a given diagnostic corresponds to.
1767 unsigned I = 0;
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001768 Error Errs = Error::success();
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001769 std::string CmdlineDefsDiag;
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +00001770 SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;
1771 for (StringRef CmdlineDef : CmdlineDefines) {
1772 std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();
1773 size_t EqIdx = CmdlineDef.find('=');
1774 if (EqIdx == StringRef::npos) {
1775 CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));
1776 continue;
1777 }
1778 // Numeric variable definition.
1779 if (CmdlineDef[0] == '#') {
1780 // Append a copy of the command-line definition adapted to use the same
1781 // format as in the input file to be able to reuse
1782 // parseNumericSubstitutionBlock.
1783 CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();
1784 std::string SubstitutionStr = CmdlineDef;
1785 SubstitutionStr[EqIdx] = ':';
1786 CmdlineDefsIndices.push_back(
1787 std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));
1788 CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();
1789 } else {
1790 CmdlineDefsDiag += DefPrefix;
1791 CmdlineDefsIndices.push_back(
1792 std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));
1793 CmdlineDefsDiag += (CmdlineDef + "\n").str();
1794 }
1795 }
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001796
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001797 // Create a buffer with fake command line content in order to display
1798 // parsing diagnostic with location information and point to the
1799 // global definition with invalid syntax.
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001800 std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer =
1801 MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines");
1802 StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
1803 SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
1804
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +00001805 for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
1806 StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
1807 CmdlineDefIndices.second);
1808 if (CmdlineDef.empty()) {
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001809 Errs = joinErrors(
1810 std::move(Errs),
1811 FileCheckErrorDiagnostic::get(
1812 SM, CmdlineDef, "missing equal sign in global definition"));
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001813 continue;
1814 }
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001815
1816 // Numeric variable definition.
1817 if (CmdlineDef[0] == '#') {
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +00001818 // Now parse the definition both to check that the syntax is correct and
1819 // to create the necessary class instance.
1820 StringRef CmdlineDefExpr = CmdlineDef.substr(1);
1821 Optional<FileCheckNumericVariable *> DefinedNumericVariable;
1822 Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult =
1823 FileCheckPattern::parseNumericSubstitutionBlock(
1824 CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);
1825 if (!ExpressionASTResult) {
1826 Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());
1827 continue;
1828 }
1829 std::unique_ptr<FileCheckExpressionAST> ExpressionAST =
1830 std::move(*ExpressionASTResult);
1831 // Now evaluate the expression whose value this variable should be set
1832 // to, since the expression of a command-line variable definition should
1833 // only use variables defined earlier on the command-line. If not, this
1834 // is an error and we report it.
1835 Expected<uint64_t> Value = ExpressionAST->eval();
1836 if (!Value) {
1837 Errs = joinErrors(std::move(Errs), Value.takeError());
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001838 continue;
1839 }
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001840
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +00001841 assert(DefinedNumericVariable && "No variable defined");
1842 (*DefinedNumericVariable)->setValue(*Value);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001843
1844 // Record this variable definition.
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +00001845 GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =
1846 *DefinedNumericVariable;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001847 } else {
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001848 // String variable definition.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001849 std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
Thomas Preud'homme71d3f222019-06-06 13:21:06 +00001850 StringRef CmdlineName = CmdlineNameVal.first;
1851 StringRef OrigCmdlineName = CmdlineName;
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +00001852 Expected<FileCheckPattern::VariableProperties> ParseVarResult =
1853 FileCheckPattern::parseVariable(CmdlineName, SM);
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001854 if (!ParseVarResult) {
1855 Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001856 continue;
1857 }
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001858 // Check that CmdlineName does not denote a pseudo variable is only
1859 // composed of the parsed numeric variable. This catches cases like
1860 // "FOO+2" in a "FOO+2=10" definition.
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +00001861 if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001862 Errs = joinErrors(std::move(Errs),
1863 FileCheckErrorDiagnostic::get(
1864 SM, OrigCmdlineName,
1865 "invalid name in string variable definition '" +
1866 OrigCmdlineName + "'"));
1867 continue;
1868 }
Thomas Preud'homme2a7f5202019-07-13 13:24:30 +00001869 StringRef Name = ParseVarResult->Name;
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001870
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001871 // Detect collisions between string and numeric variables when the former
1872 // is created later than the latter.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001873 if (GlobalNumericVariableTable.find(Name) !=
1874 GlobalNumericVariableTable.end()) {
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001875 Errs = joinErrors(std::move(Errs), FileCheckErrorDiagnostic::get(
1876 SM, Name,
1877 "numeric variable with name '" +
1878 Name + "' already exists"));
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001879 continue;
1880 }
1881 GlobalVariableTable.insert(CmdlineNameVal);
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001882 // Mark the string variable as defined to detect collisions between
Thomas Preud'homme4cd9b852019-07-24 12:38:22 +00001883 // string and numeric variables in defineCmdlineVariables when the latter
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001884 // is created later than the former. We cannot reuse GlobalVariableTable
Thomas Preud'homme71d3f222019-06-06 13:21:06 +00001885 // for this by populating it with an empty string since we would then
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001886 // lose the ability to detect the use of an undefined variable in
1887 // match().
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001888 DefinedVariableTable[Name] = true;
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001889 }
Thomas Preud'homme5a330472019-04-29 13:32:36 +00001890 }
1891
Thomas Preud'hommebaae41f2019-06-19 23:47:10 +00001892 return Errs;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001893}
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001894
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001895void FileCheckPatternContext::clearLocalVars() {
1896 SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars;
1897 for (const StringMapEntry<StringRef> &Var : GlobalVariableTable)
1898 if (Var.first()[0] != '$')
1899 LocalPatternVars.push_back(Var.first());
1900
Thomas Preud'homme1a944d22019-05-23 00:10:14 +00001901 // Numeric substitution reads the value of a variable directly, not via
1902 // GlobalNumericVariableTable. Therefore, we clear local variables by
1903 // clearing their value which will lead to a numeric substitution failure. We
1904 // also mark the variable for removal from GlobalNumericVariableTable since
1905 // this is what defineCmdlineVariables checks to decide that no global
1906 // variable has been defined.
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001907 for (const auto &Var : GlobalNumericVariableTable)
1908 if (Var.first()[0] != '$') {
1909 Var.getValue()->clearValue();
1910 LocalNumericVars.push_back(Var.first());
1911 }
1912
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001913 for (const auto &Var : LocalPatternVars)
1914 GlobalVariableTable.erase(Var);
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001915 for (const auto &Var : LocalNumericVars)
1916 GlobalNumericVariableTable.erase(Var);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001917}
1918
Thomas Preud'homme7b7683d2019-05-23 17:19:36 +00001919bool FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
1920 ArrayRef<FileCheckString> CheckStrings,
1921 std::vector<FileCheckDiag> *Diags) {
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001922 bool ChecksFailed = false;
1923
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001924 unsigned i = 0, j = 0, e = CheckStrings.size();
1925 while (true) {
1926 StringRef CheckRegion;
1927 if (j == e) {
1928 CheckRegion = Buffer;
1929 } else {
1930 const FileCheckString &CheckLabelStr = CheckStrings[j];
1931 if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {
1932 ++j;
1933 continue;
1934 }
1935
1936 // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
1937 size_t MatchLabelLen = 0;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001938 size_t MatchLabelPos =
1939 CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001940 if (MatchLabelPos == StringRef::npos)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001941 // Immediately bail if CHECK-LABEL fails, nothing else we can do.
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001942 return false;
1943
1944 CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
1945 Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);
1946 ++j;
1947 }
1948
Thomas Preud'homme7b4ecdd2019-05-14 11:58:30 +00001949 // Do not clear the first region as it's the one before the first
1950 // CHECK-LABEL and it would clear variables defined on the command-line
1951 // before they get used.
1952 if (i != 0 && Req.EnableVarScope)
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001953 PatternContext.clearLocalVars();
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001954
1955 for (; i != j; ++i) {
1956 const FileCheckString &CheckStr = CheckStrings[i];
1957
1958 // Check each string within the scanned region, including a second check
1959 // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
1960 size_t MatchLen = 0;
Thomas Preud'hommee038fa72019-04-15 10:10:11 +00001961 size_t MatchPos =
1962 CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);
Aditya Nandakumarffa9d2e2018-08-07 21:58:49 +00001963
1964 if (MatchPos == StringRef::npos) {
1965 ChecksFailed = true;
1966 i = j;
1967 break;
1968 }
1969
1970 CheckRegion = CheckRegion.substr(MatchPos + MatchLen);
1971 }
1972
1973 if (j == e)
1974 break;
1975 }
1976
1977 // Success if no checks failed.
1978 return !ChecksFailed;
1979}