blob: 39245d2ca8896b676ff8553aaa1697df33f5e89c [file] [log] [blame]
Chris Lattner81cb8ca2009-07-08 18:44:05 +00001//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// FileCheck does a line-by line check of a file that validates whether it
11// contains the expected content. This is useful for regression tests etc.
12//
James Henderson51258d92017-03-14 10:51:14 +000013// This program exits with an exit status of 2 on error, exit status of 0 if
Chris Lattner81cb8ca2009-07-08 18:44:05 +000014// the file matched the expected contents, and exit status of 1 if it did not
15// contain the expected contents.
16//
17//===----------------------------------------------------------------------===//
18
19#include "llvm/Support/CommandLine.h"
Rui Ueyama0b9d56a2018-04-13 18:26:06 +000020#include "llvm/Support/InitLLVM.h"
Joel E. Denny718a7792018-10-24 21:46:42 +000021#include "llvm/Support/Process.h"
Joel E. Dennye1af89a2018-12-18 00:01:39 +000022#include "llvm/Support/WithColor.h"
Chris Lattner81cb8ca2009-07-08 18:44:05 +000023#include "llvm/Support/raw_ostream.h"
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +000024#include "llvm/Support/FileCheck.h"
Chris Lattner81cb8ca2009-07-08 18:44:05 +000025using namespace llvm;
26
27static cl::opt<std::string>
Joel E. Dennye1af89a2018-12-18 00:01:39 +000028 CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
Chris Lattner81cb8ca2009-07-08 18:44:05 +000029
30static cl::opt<std::string>
Chandler Carruthb541b812016-12-11 09:54:36 +000031 InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
32 cl::init("-"), cl::value_desc("filename"));
Chris Lattner81cb8ca2009-07-08 18:44:05 +000033
Chandler Carruthb541b812016-12-11 09:54:36 +000034static cl::list<std::string> CheckPrefixes(
35 "check-prefix",
36 cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
Daniel Sandersded439832016-06-14 14:28:04 +000037static cl::alias CheckPrefixesAlias(
38 "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
39 cl::NotHidden,
40 cl::desc(
41 "Alias for -check-prefix permitting multiple comma separated values"));
Chris Lattner81cb8ca2009-07-08 18:44:05 +000042
Chandler Carruthb541b812016-12-11 09:54:36 +000043static cl::opt<bool> NoCanonicalizeWhiteSpace(
44 "strict-whitespace",
45 cl::desc("Do not treat all horizontal whitespace as equivalent"));
Chris Lattner88a7e9e2009-07-11 18:58:15 +000046
Alexander Kornienkoc58b0792014-07-11 12:39:32 +000047static cl::list<std::string> ImplicitCheckNot(
48 "implicit-check-not",
49 cl::desc("Add an implicit negative check with this pattern to every\n"
50 "positive check. This can be used to ensure that no instances of\n"
51 "this pattern occur which are not matched by a positive pattern"),
52 cl::value_desc("pattern"));
53
Thomas Preud'hommefe0523d2019-01-14 09:29:10 +000054static cl::list<std::string>
55 GlobalDefines("D", cl::AlwaysPrefix,
56 cl::desc("Define a variable to be used in capture patterns."),
57 cl::value_desc("VAR=VALUE"));
Alexander Richardson7c37aa12017-11-07 13:24:44 +000058
Justin Bognerb7c95342014-08-07 18:40:37 +000059static cl::opt<bool> AllowEmptyInput(
60 "allow-empty", cl::init(false),
61 cl::desc("Allow the input file to be empty. This is useful when making\n"
62 "checks that some error message does not occur, for example."));
63
James Y Knight5b06a932016-02-11 16:46:09 +000064static cl::opt<bool> MatchFullLines(
65 "match-full-lines", cl::init(false),
66 cl::desc("Require all positive matches to cover an entire input line.\n"
67 "Allows leading and trailing whitespace if --strict-whitespace\n"
68 "is not also passed."));
69
Artem Belevichbb9779a2017-03-09 17:59:04 +000070static cl::opt<bool> EnableVarScope(
71 "enable-var-scope", cl::init(false),
72 cl::desc("Enables scope for regex variables. Variables with names that\n"
73 "do not start with '$' will be reset at the beginning of\n"
74 "each CHECK-LABEL block."));
75
Joel E. Denny0195c0b2018-07-11 20:27:27 +000076static cl::opt<bool> AllowDeprecatedDagOverlap(
77 "allow-deprecated-dag-overlap", cl::init(false),
78 cl::desc("Enable overlapping among matches in a group of consecutive\n"
79 "CHECK-DAG directives. This option is deprecated and is only\n"
80 "provided for convenience as old tests are migrated to the new\n"
81 "non-overlapping CHECK-DAG implementation.\n"));
82
Joel E. Denny9074a872018-07-13 03:08:23 +000083static cl::opt<bool> Verbose("v", cl::init(false),
84 cl::desc("Print directive pattern matches.\n"));
85
86static cl::opt<bool> VerboseVerbose(
87 "vv", cl::init(false),
88 cl::desc("Print information helpful in diagnosing internal FileCheck\n"
89 "issues. Implies -v.\n"));
George Karpenkov4571da62018-07-20 20:21:57 +000090static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";
91
92static cl::opt<bool> DumpInputOnFailure(
93 "dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)),
94 cl::desc("Dump original input to stderr before failing.\n"
95 "The value can be also controlled using\n"
Joel E. Dennye1af89a2018-12-18 00:01:39 +000096 "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"
97 "This option is deprecated in favor of -dump-input=fail.\n"));
98
99enum DumpInputValue {
100 DumpInputDefault,
101 DumpInputHelp,
102 DumpInputNever,
103 DumpInputFail,
104 DumpInputAlways
105};
106
107static cl::opt<DumpInputValue> DumpInput(
108 "dump-input", cl::init(DumpInputDefault),
109 cl::desc("Dump input to stderr, adding annotations representing\n"
110 " currently enabled diagnostics\n"),
111 cl::value_desc("mode"),
112 cl::values(clEnumValN(DumpInputHelp, "help",
113 "Explain dump format and quit"),
114 clEnumValN(DumpInputNever, "never", "Never dump input"),
115 clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
116 clEnumValN(DumpInputAlways, "always", "Always dump input")));
Joel E. Denny9074a872018-07-13 03:08:23 +0000117
Matt Arsenaultee4f5ea2013-11-10 02:04:09 +0000118typedef cl::list<std::string>::const_iterator prefix_iterator;
119
Matt Arsenaultee4f5ea2013-11-10 02:04:09 +0000120
Matt Arsenaultee4f5ea2013-11-10 02:04:09 +0000121
Chandler Carruthfb888882016-12-11 12:49:05 +0000122
Chandler Carruthfb888882016-12-11 12:49:05 +0000123
Chandler Carruthfb888882016-12-11 12:49:05 +0000124
Rui Ueyamad9a84ef2013-08-12 23:05:59 +0000125
Xinliang David Lia5135a82016-05-27 21:23:25 +0000126static void DumpCommandLine(int argc, char **argv) {
127 errs() << "FileCheck command line: ";
128 for (int I = 0; I < argc; I++)
129 errs() << " " << argv[I];
130 errs() << "\n";
131}
132
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000133struct MarkerStyle {
134 /// The starting char (before tildes) for marking the line.
135 char Lead;
136 /// What color to use for this annotation.
137 raw_ostream::Colors Color;
138 /// A note to follow the marker, or empty string if none.
139 std::string Note;
140 MarkerStyle() {}
Joel E. Dennycf38e312018-12-18 00:03:03 +0000141 MarkerStyle(char Lead, raw_ostream::Colors Color,
142 const std::string &Note = "")
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000143 : Lead(Lead), Color(Color), Note(Note) {}
144};
145
146static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
147 switch (MatchTy) {
Joel E. Denny302fa302018-12-18 00:03:51 +0000148 case FileCheckDiag::MatchFoundAndExpected:
Joel E. Dennycf38e312018-12-18 00:03:03 +0000149 return MarkerStyle('^', raw_ostream::GREEN);
Joel E. Denny302fa302018-12-18 00:03:51 +0000150 case FileCheckDiag::MatchFoundButExcluded:
Joel E. Denny8a1f7d62018-12-18 00:02:47 +0000151 return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
Joel E. Denny302fa302018-12-18 00:03:51 +0000152 case FileCheckDiag::MatchFoundButWrongLine:
Joel E. Denny7e86f822018-12-18 00:02:22 +0000153 return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
Joel E. Denny302fa302018-12-18 00:03:51 +0000154 case FileCheckDiag::MatchFoundButDiscarded:
Joel E. Denny0b0cf262018-12-18 00:03:19 +0000155 return MarkerStyle('!', raw_ostream::CYAN,
156 "discard: overlaps earlier match");
Joel E. Dennyc4c24a82018-12-18 00:03:36 +0000157 case FileCheckDiag::MatchNoneAndExcluded:
158 return MarkerStyle('X', raw_ostream::GREEN);
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000159 case FileCheckDiag::MatchNoneButExpected:
160 return MarkerStyle('X', raw_ostream::RED, "error: no match found");
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000161 case FileCheckDiag::MatchFuzzy:
162 return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000163 }
164 llvm_unreachable_internal("unexpected match type");
165}
166
167static void DumpInputAnnotationHelp(raw_ostream &OS) {
168 OS << "The following description was requested by -dump-input=help to\n"
169 << "explain the input annotations printed by -dump-input=always and\n"
170 << "-dump-input=fail:\n\n";
171
172 // Labels for input lines.
173 OS << " - ";
174 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
175 OS << " labels line number L of the input file\n";
176
177 // Labels for annotation lines.
178 OS << " - ";
179 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000180 OS << " labels the only match result for a pattern of type T from "
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000181 << "line L of\n"
182 << " the check file\n";
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000183 OS << " - ";
184 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
185 OS << " labels the Nth match result for a pattern of type T from line "
186 << "L of\n"
187 << " the check file\n";
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000188
189 // Markers on annotation lines.
190 OS << " - ";
Joel E. Dennycf38e312018-12-18 00:03:03 +0000191 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
192 OS << " marks good match (reported if -v)\n"
193 << " - ";
Joel E. Denny7e86f822018-12-18 00:02:22 +0000194 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
195 OS << " marks bad match, such as:\n"
196 << " - CHECK-NEXT on same line as previous match (error)\n"
Joel E. Denny8a1f7d62018-12-18 00:02:47 +0000197 << " - CHECK-NOT found (error)\n"
Joel E. Denny0b0cf262018-12-18 00:03:19 +0000198 << " - CHECK-DAG overlapping match (discarded, reported if "
199 << "-vv)\n"
Joel E. Denny7e86f822018-12-18 00:02:22 +0000200 << " - ";
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000201 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
Joel E. Denny7e86f822018-12-18 00:02:22 +0000202 OS << " marks search range when no match is found, such as:\n"
203 << " - CHECK-NEXT not found (error)\n"
Joel E. Dennyc4c24a82018-12-18 00:03:36 +0000204 << " - CHECK-NOT not found (success, reported if -vv)\n"
Joel E. Denny0b0cf262018-12-18 00:03:19 +0000205 << " - CHECK-DAG not found after discarded matches (error)\n"
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000206 << " - ";
207 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
208 OS << " marks fuzzy match when no match is found\n";
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000209
210 // Colors.
211 OS << " - colors ";
Joel E. Dennycf38e312018-12-18 00:03:03 +0000212 WithColor(OS, raw_ostream::GREEN, true) << "success";
213 OS << ", ";
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000214 WithColor(OS, raw_ostream::RED, true) << "error";
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000215 OS << ", ";
216 WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
Joel E. Dennycf38e312018-12-18 00:03:03 +0000217 OS << ", ";
Joel E. Denny0b0cf262018-12-18 00:03:19 +0000218 WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
219 OS << ", ";
Joel E. Dennycf38e312018-12-18 00:03:03 +0000220 WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000221 OS << "\n\n"
222 << "If you are not seeing color above or in input dumps, try: -color\n";
223}
224
225/// An annotation for a single input line.
226struct InputAnnotation {
227 /// The check file line (one-origin indexing) where the directive that
228 /// produced this annotation is located.
229 unsigned CheckLine;
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000230 /// The index of the match result for this check.
231 unsigned CheckDiagIndex;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000232 /// The label for this annotation.
233 std::string Label;
234 /// What input line (one-origin indexing) this annotation marks. This might
235 /// be different from the starting line of the original diagnostic if this is
236 /// a non-initial fragment of a diagnostic that has been broken across
237 /// multiple lines.
238 unsigned InputLine;
239 /// The column range (one-origin indexing, open end) in which to to mark the
240 /// input line. If InputEndCol is UINT_MAX, treat it as the last column
241 /// before the newline.
242 unsigned InputStartCol, InputEndCol;
243 /// The marker to use.
244 MarkerStyle Marker;
Joel E. Denny302fa302018-12-18 00:03:51 +0000245 /// Whether this annotation represents a good match for an expected pattern.
246 bool FoundAndExpectedMatch;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000247};
248
249/// Get an abbreviation for the check type.
250std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
251 switch (Ty) {
252 case Check::CheckPlain:
253 if (Ty.getCount() > 1)
254 return "count";
255 return "check";
256 case Check::CheckNext:
257 return "next";
258 case Check::CheckSame:
259 return "same";
260 case Check::CheckNot:
261 return "not";
262 case Check::CheckDAG:
263 return "dag";
264 case Check::CheckLabel:
265 return "label";
266 case Check::CheckEmpty:
267 return "empty";
268 case Check::CheckEOF:
269 return "eof";
270 case Check::CheckBadNot:
271 return "bad-not";
272 case Check::CheckBadCount:
273 return "bad-count";
274 case Check::CheckNone:
275 llvm_unreachable("invalid FileCheckType");
276 }
277 llvm_unreachable("unknown FileCheckType");
278}
279
280static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
281 std::vector<InputAnnotation> &Annotations,
282 unsigned &LabelWidth) {
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000283 // How many diagnostics has the current check seen so far?
284 unsigned CheckDiagCount = 0;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000285 // What's the widest label?
286 LabelWidth = 0;
287 for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
288 ++DiagItr) {
289 InputAnnotation A;
290
291 // Build label, which uniquely identifies this check result.
292 A.CheckLine = DiagItr->CheckLine;
293 llvm::raw_string_ostream Label(A.Label);
294 Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
295 << DiagItr->CheckLine;
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000296 A.CheckDiagIndex = UINT_MAX;
297 auto DiagNext = std::next(DiagItr);
298 if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
299 DiagItr->CheckLine == DiagNext->CheckLine)
300 A.CheckDiagIndex = CheckDiagCount++;
301 else if (CheckDiagCount) {
302 A.CheckDiagIndex = CheckDiagCount;
303 CheckDiagCount = 0;
304 }
305 if (A.CheckDiagIndex != UINT_MAX)
306 Label << "'" << A.CheckDiagIndex;
307 else
308 A.CheckDiagIndex = 0;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000309 Label.flush();
310 LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
311
312 MarkerStyle Marker = GetMarker(DiagItr->MatchTy);
313 A.Marker = Marker;
Joel E. Denny302fa302018-12-18 00:03:51 +0000314 A.FoundAndExpectedMatch =
315 DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000316
317 // Compute the mark location, and break annotation into multiple
318 // annotations if it spans multiple lines.
319 A.InputLine = DiagItr->InputStartLine;
320 A.InputStartCol = DiagItr->InputStartCol;
321 if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
322 // Sometimes ranges are empty in order to indicate a specific point, but
323 // that would mean nothing would be marked, so adjust the range to
324 // include the following character.
325 A.InputEndCol =
326 std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
327 Annotations.push_back(A);
328 } else {
329 assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
330 "expected input range not to be inverted");
331 A.InputEndCol = UINT_MAX;
332 A.Marker.Note = "";
333 Annotations.push_back(A);
334 for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
335 L <= E; ++L) {
336 // If a range ends before the first column on a line, then it has no
337 // characters on that line, so there's nothing to render.
338 if (DiagItr->InputEndCol == 1 && L == E) {
339 Annotations.back().Marker.Note = Marker.Note;
340 break;
341 }
342 InputAnnotation B;
343 B.CheckLine = A.CheckLine;
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000344 B.CheckDiagIndex = A.CheckDiagIndex;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000345 B.Label = A.Label;
346 B.InputLine = L;
347 B.Marker = Marker;
348 B.Marker.Lead = '~';
349 B.InputStartCol = 1;
350 if (L != E) {
351 B.InputEndCol = UINT_MAX;
352 B.Marker.Note = "";
353 } else
354 B.InputEndCol = DiagItr->InputEndCol;
Joel E. Denny302fa302018-12-18 00:03:51 +0000355 B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000356 Annotations.push_back(B);
357 }
358 }
359 }
360}
361
Joel E. Dennycf38e312018-12-18 00:03:03 +0000362static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
363 StringRef InputFileText,
364 std::vector<InputAnnotation> &Annotations,
365 unsigned LabelWidth) {
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000366 OS << "Full input was:\n<<<<<<\n";
367
368 // Sort annotations.
369 //
370 // First, sort in the order of input lines to make it easier to find relevant
371 // annotations while iterating input lines in the implementation below.
372 // FileCheck diagnostics are not always reported and recorded in the order of
373 // input lines due to, for example, CHECK-DAG and CHECK-NOT.
374 //
375 // Second, for annotations for the same input line, sort in the order of the
376 // FileCheck directive's line in the check file (where there's at most one
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000377 // directive per line) and then by the index of the match result for that
378 // directive. The rationale of this choice is that, for any input line, this
379 // sort establishes a total order of annotations that, with respect to match
380 // results, is consistent across multiple lines, thus making match results
381 // easier to track from one line to the next when they span multiple lines.
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000382 std::sort(Annotations.begin(), Annotations.end(),
383 [](const InputAnnotation &A, const InputAnnotation &B) {
384 if (A.InputLine != B.InputLine)
385 return A.InputLine < B.InputLine;
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000386 if (A.CheckLine != B.CheckLine)
387 return A.CheckLine < B.CheckLine;
Joel E. Dennycf38e312018-12-18 00:03:03 +0000388 // FIXME: Sometimes CHECK-LABEL reports its match twice with
389 // other diagnostics in between, and then diag index incrementing
390 // fails to work properly, and then this assert fails. We should
391 // suppress one of those diagnostics or do a better job of
392 // computing this index. For now, we just produce a redundant
393 // CHECK-LABEL annotation.
394 // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
395 // "expected diagnostic indices to be unique within a "
396 // " check line");
Joel E. Denny3fc136c2018-12-18 00:02:04 +0000397 return A.CheckDiagIndex < B.CheckDiagIndex;
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000398 });
399
400 // Compute the width of the label column.
401 const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
402 *InputFileEnd = InputFileText.bytes_end();
403 unsigned LineCount = InputFileText.count('\n');
404 if (InputFileEnd[-1] != '\n')
405 ++LineCount;
406 unsigned LineNoWidth = log10(LineCount) + 1;
407 // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
408 // on input lines and (2) to the right of the (left-aligned) labels on
409 // annotation lines so that input lines and annotation lines are more
410 // visually distinct. For example, the spaces on the annotation lines ensure
411 // that input line numbers and check directive line numbers never align
412 // horizontally. Those line numbers might not even be for the same file.
413 // One space would be enough to achieve that, but more makes it even easier
414 // to see.
415 LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
416
417 // Print annotated input lines.
418 auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
419 for (unsigned Line = 1;
420 InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
421 ++Line) {
422 const unsigned char *InputFileLine = InputFilePtr;
423
424 // Print right-aligned line number.
425 WithColor(OS, raw_ostream::BLACK, true)
426 << format_decimal(Line, LabelWidth) << ": ";
427
Joel E. Denny302fa302018-12-18 00:03:51 +0000428 // For the case where -v and colors are enabled, find the annotations for
429 // good matches for expected patterns in order to highlight everything
430 // else in the line. There are no such annotations if -v is disabled.
431 std::vector<InputAnnotation> FoundAndExpectedMatches;
Joel E. Dennycf38e312018-12-18 00:03:03 +0000432 if (Req.Verbose && WithColor(OS).colorsEnabled()) {
433 for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
434 ++I) {
Joel E. Denny302fa302018-12-18 00:03:51 +0000435 if (I->FoundAndExpectedMatch)
436 FoundAndExpectedMatches.push_back(*I);
Joel E. Dennycf38e312018-12-18 00:03:03 +0000437 }
438 }
439
440 // Print numbered line with highlighting where there are no matches for
441 // expected patterns.
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000442 bool Newline = false;
Joel E. Dennycf38e312018-12-18 00:03:03 +0000443 {
444 WithColor COS(OS);
445 bool InMatch = false;
446 if (Req.Verbose)
447 COS.changeColor(raw_ostream::CYAN, true, true);
448 for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
449 bool WasInMatch = InMatch;
450 InMatch = false;
Joel E. Denny302fa302018-12-18 00:03:51 +0000451 for (auto M : FoundAndExpectedMatches) {
Joel E. Dennycf38e312018-12-18 00:03:03 +0000452 if (M.InputStartCol <= Col && Col < M.InputEndCol) {
453 InMatch = true;
454 break;
455 }
456 }
457 if (!WasInMatch && InMatch)
458 COS.resetColor();
459 else if (WasInMatch && !InMatch)
460 COS.changeColor(raw_ostream::CYAN, true, true);
461 if (*InputFilePtr == '\n')
462 Newline = true;
463 else
464 COS << *InputFilePtr;
465 ++InputFilePtr;
466 }
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000467 }
468 OS << '\n';
469 unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
470
471 // Print any annotations.
472 while (AnnotationItr != AnnotationEnd &&
473 AnnotationItr->InputLine == Line) {
474 WithColor COS(OS, AnnotationItr->Marker.Color, true);
475 // The two spaces below are where the ": " appears on input lines.
476 COS << left_justify(AnnotationItr->Label, LabelWidth) << " ";
477 unsigned Col;
478 for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
479 COS << ' ';
480 COS << AnnotationItr->Marker.Lead;
481 // If InputEndCol=UINT_MAX, stop at InputLineWidth.
482 for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
483 ++Col)
484 COS << '~';
485 const std::string &Note = AnnotationItr->Marker.Note;
486 if (!Note.empty()) {
487 // Put the note at the end of the input line. If we were to instead
488 // put the note right after the marker, subsequent annotations for the
489 // same input line might appear to mark this note instead of the input
490 // line.
491 for (; Col <= InputLineWidth; ++Col)
492 COS << ' ';
493 COS << ' ' << Note;
494 }
495 COS << '\n';
496 ++AnnotationItr;
497 }
498 }
499
500 OS << ">>>>>>\n";
501}
502
Chris Lattner81cb8ca2009-07-08 18:44:05 +0000503int main(int argc, char **argv) {
Joel E. Denny718a7792018-10-24 21:46:42 +0000504 // Enable use of ANSI color codes because FileCheck is using them to
505 // highlight text.
506 llvm::sys::Process::UseANSIEscapeCodes(true);
507
Rui Ueyama0b9d56a2018-04-13 18:26:06 +0000508 InitLLVM X(argc, argv);
Joel E. Dennye8618742018-11-06 22:07:03 +0000509 cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
510 "FILECHECK_OPTS");
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000511 if (DumpInput == DumpInputHelp) {
512 DumpInputAnnotationHelp(outs());
513 return 0;
514 }
515 if (CheckFilename.empty()) {
516 errs() << "<check-file> not specified\n";
517 return 2;
518 }
Chris Lattner81cb8ca2009-07-08 18:44:05 +0000519
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +0000520 FileCheckRequest Req;
521 for (auto Prefix : CheckPrefixes)
522 Req.CheckPrefixes.push_back(Prefix);
523
524 for (auto CheckNot : ImplicitCheckNot)
525 Req.ImplicitCheckNot.push_back(CheckNot);
526
Thomas Preud'hommefe0523d2019-01-14 09:29:10 +0000527 bool GlobalDefineError = false;
528 for (auto G : GlobalDefines) {
529 size_t EqIdx = G.find('=');
530 if (EqIdx == std::string::npos) {
531 errs() << "Missing equal sign in command-line definition '-D" << G
532 << "'\n";
533 GlobalDefineError = true;
534 continue;
535 }
536 if (EqIdx == 0) {
537 errs() << "Missing pattern variable name in command-line definition '-D"
538 << G << "'\n";
539 GlobalDefineError = true;
540 continue;
541 }
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +0000542 Req.GlobalDefines.push_back(G);
Thomas Preud'hommefe0523d2019-01-14 09:29:10 +0000543 }
544 if (GlobalDefineError)
545 return 2;
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +0000546
547 Req.AllowEmptyInput = AllowEmptyInput;
548 Req.EnableVarScope = EnableVarScope;
549 Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
550 Req.Verbose = Verbose;
551 Req.VerboseVerbose = VerboseVerbose;
552 Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
553 Req.MatchFullLines = MatchFullLines;
554
555 if (VerboseVerbose)
556 Req.Verbose = true;
557
558 FileCheck FC(Req);
559 if (!FC.ValidateCheckPrefixes()) {
Matt Arsenaultee4f5ea2013-11-10 02:04:09 +0000560 errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
561 "start with a letter and contain only alphanumeric characters, "
562 "hyphens and underscores\n";
Rui Ueyamad9a84ef2013-08-12 23:05:59 +0000563 return 2;
564 }
565
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +0000566 Regex PrefixRE = FC.buildCheckPrefixRegex();
Chandler Carruthfb888882016-12-11 12:49:05 +0000567 std::string REError;
568 if (!PrefixRE.isValid(REError)) {
569 errs() << "Unable to combine check-prefix strings into a prefix regular "
570 "expression! This is likely a bug in FileCheck's verification of "
571 "the check-prefix strings. Regular expression parsing failed "
572 "with the following error: "
573 << REError << "\n";
574 return 2;
575 }
Matt Arsenaultee4f5ea2013-11-10 02:04:09 +0000576
Chris Lattner81cb8ca2009-07-08 18:44:05 +0000577 SourceMgr SM;
Mikhail Glushenkov7112c862010-08-20 17:38:38 +0000578
Chris Lattner81cb8ca2009-07-08 18:44:05 +0000579 // Read the expected strings from the check file.
Chandler Carruth79aaa0b2016-12-11 09:50:05 +0000580 ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
581 MemoryBuffer::getFileOrSTDIN(CheckFilename);
582 if (std::error_code EC = CheckFileOrErr.getError()) {
583 errs() << "Could not open check file '" << CheckFilename
584 << "': " << EC.message() << '\n';
585 return 2;
586 }
587 MemoryBuffer &CheckFile = *CheckFileOrErr.get();
588
589 SmallString<4096> CheckFileBuffer;
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +0000590 StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
Chandler Carruth79aaa0b2016-12-11 09:50:05 +0000591
592 SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
593 CheckFileText, CheckFile.getBufferIdentifier()),
594 SMLoc());
595
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +0000596 std::vector<FileCheckString> CheckStrings;
597 if (FC.ReadCheckFile(SM, CheckFileText, PrefixRE, CheckStrings))
Chris Lattner81cb8ca2009-07-08 18:44:05 +0000598 return 2;
599
600 // Open the file to check and add it to SourceMgr.
Chandler Carruth79aaa0b2016-12-11 09:50:05 +0000601 ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
Rafael Espindola7cba2a92014-07-06 17:43:13 +0000602 MemoryBuffer::getFileOrSTDIN(InputFilename);
Chandler Carruth79aaa0b2016-12-11 09:50:05 +0000603 if (std::error_code EC = InputFileOrErr.getError()) {
Rafael Espindola7cba2a92014-07-06 17:43:13 +0000604 errs() << "Could not open input file '" << InputFilename
605 << "': " << EC.message() << '\n';
Eli Bendersky7f8e76f2012-11-30 13:51:33 +0000606 return 2;
Chris Lattner81cb8ca2009-07-08 18:44:05 +0000607 }
Chandler Carruth79aaa0b2016-12-11 09:50:05 +0000608 MemoryBuffer &InputFile = *InputFileOrErr.get();
Mikhail Glushenkov7112c862010-08-20 17:38:38 +0000609
Chandler Carruth79aaa0b2016-12-11 09:50:05 +0000610 if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
Chris Lattner1aac1862011-02-09 16:46:02 +0000611 errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
Xinliang David Lia5135a82016-05-27 21:23:25 +0000612 DumpCommandLine(argc, argv);
Eli Bendersky7f8e76f2012-11-30 13:51:33 +0000613 return 2;
Chris Lattner1aac1862011-02-09 16:46:02 +0000614 }
Benjamin Kramer7cdba152013-03-23 13:56:23 +0000615
Chandler Carruth79aaa0b2016-12-11 09:50:05 +0000616 SmallString<4096> InputFileBuffer;
Aditya Nandakumar5718b6f2018-08-07 21:58:49 +0000617 StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
Mikhail Glushenkov7112c862010-08-20 17:38:38 +0000618
Chandler Carruthb541b812016-12-11 09:54:36 +0000619 SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
620 InputFileText, InputFile.getBufferIdentifier()),
621 SMLoc());
Mikhail Glushenkov7112c862010-08-20 17:38:38 +0000622
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000623 if (DumpInput == DumpInputDefault)
624 DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
625
626 std::vector<FileCheckDiag> Diags;
627 int ExitCode = FC.CheckInput(SM, InputFileText, CheckStrings,
628 DumpInput == DumpInputNever ? nullptr : &Diags)
629 ? EXIT_SUCCESS
630 : 1;
631 if (DumpInput == DumpInputAlways ||
632 (ExitCode == 1 && DumpInput == DumpInputFail)) {
633 errs() << "\n"
634 << "Input file: "
635 << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())
636 << "\n"
637 << "Check file: " << CheckFilename << "\n"
638 << "\n"
639 << "-dump-input=help describes the format of the following dump.\n"
640 << "\n";
641 std::vector<InputAnnotation> Annotations;
642 unsigned LabelWidth;
643 BuildInputAnnotations(Diags, Annotations, LabelWidth);
Joel E. Dennycf38e312018-12-18 00:03:03 +0000644 DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
Joel E. Dennye1af89a2018-12-18 00:01:39 +0000645 }
George Karpenkov4571da62018-07-20 20:21:57 +0000646
647 return ExitCode;
Chris Lattner81cb8ca2009-07-08 18:44:05 +0000648}