1 //===- FileCheck.cpp - Check that File's Contents match what is expected --===//
3 // 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
7 //===----------------------------------------------------------------------===//
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.
12 // This program exits with an exit status of 2 on error, exit status of 0 if
13 // the file matched the expected contents, and exit status of 1 if it did not
14 // contain the expected contents.
16 //===----------------------------------------------------------------------===//
18 #include "llvm/FileCheck/FileCheck.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Support/InitLLVM.h"
21 #include "llvm/Support/Process.h"
22 #include "llvm/Support/WithColor.h"
23 #include "llvm/Support/raw_ostream.h"
28 static cl::extrahelp
FileCheckOptsEnv(
29 "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"
30 "from the command line.\n");
32 static cl::opt
<std::string
>
33 CheckFilename(cl::Positional
, cl::desc("<check-file>"), cl::Optional
);
35 static cl::opt
<std::string
>
36 InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
37 cl::init("-"), cl::value_desc("filename"));
39 static cl::list
<std::string
> CheckPrefixes(
41 cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
42 static cl::alias
CheckPrefixesAlias(
43 "check-prefixes", cl::aliasopt(CheckPrefixes
), cl::CommaSeparated
,
46 "Alias for -check-prefix permitting multiple comma separated values"));
48 static cl::list
<std::string
> CommentPrefixes(
49 "comment-prefixes", cl::CommaSeparated
, cl::Hidden
,
50 cl::desc("Comma-separated list of comment prefixes to use from check file\n"
51 "(defaults to 'COM,RUN'). Please avoid using this feature in\n"
52 "LLVM's LIT-based test suites, which should be easier to\n"
53 "maintain if they all follow a consistent comment style. This\n"
54 "feature is meant for non-LIT test suites using FileCheck."));
56 static cl::opt
<bool> NoCanonicalizeWhiteSpace(
58 cl::desc("Do not treat all horizontal whitespace as equivalent"));
60 static cl::opt
<bool> IgnoreCase(
62 cl::desc("Use case-insensitive matching"));
64 static cl::list
<std::string
> ImplicitCheckNot(
66 cl::desc("Add an implicit negative check with this pattern to every\n"
67 "positive check. This can be used to ensure that no instances of\n"
68 "this pattern occur which are not matched by a positive pattern"),
69 cl::value_desc("pattern"));
71 static cl::list
<std::string
>
72 GlobalDefines("D", cl::AlwaysPrefix
,
73 cl::desc("Define a variable to be used in capture patterns."),
74 cl::value_desc("VAR=VALUE"));
76 static cl::opt
<bool> AllowEmptyInput(
77 "allow-empty", cl::init(false),
78 cl::desc("Allow the input file to be empty. This is useful when making\n"
79 "checks that some error message does not occur, for example."));
81 static cl::opt
<bool> AllowUnusedPrefixes(
82 "allow-unused-prefixes", cl::init(false), cl::ZeroOrMore
,
83 cl::desc("Allow prefixes to be specified but not appear in the test."));
85 static cl::opt
<bool> MatchFullLines(
86 "match-full-lines", cl::init(false),
87 cl::desc("Require all positive matches to cover an entire input line.\n"
88 "Allows leading and trailing whitespace if --strict-whitespace\n"
89 "is not also passed."));
91 static cl::opt
<bool> EnableVarScope(
92 "enable-var-scope", cl::init(false),
93 cl::desc("Enables scope for regex variables. Variables with names that\n"
94 "do not start with '$' will be reset at the beginning of\n"
95 "each CHECK-LABEL block."));
97 static cl::opt
<bool> AllowDeprecatedDagOverlap(
98 "allow-deprecated-dag-overlap", cl::init(false),
99 cl::desc("Enable overlapping among matches in a group of consecutive\n"
100 "CHECK-DAG directives. This option is deprecated and is only\n"
101 "provided for convenience as old tests are migrated to the new\n"
102 "non-overlapping CHECK-DAG implementation.\n"));
104 static cl::opt
<bool> Verbose(
105 "v", cl::init(false), cl::ZeroOrMore
,
106 cl::desc("Print directive pattern matches, or add them to the input dump\n"
109 static cl::opt
<bool> VerboseVerbose(
110 "vv", cl::init(false), cl::ZeroOrMore
,
111 cl::desc("Print information helpful in diagnosing internal FileCheck\n"
112 "issues, or add it to the input dump if enabled. Implies\n"
115 // The order of DumpInputValue members affects their precedence, as documented
116 // for -dump-input below.
117 enum DumpInputValue
{
124 static cl::list
<DumpInputValue
> DumpInputs(
126 cl::desc("Dump input to stderr, adding annotations representing\n"
127 "currently enabled diagnostics. When there are multiple\n"
128 "occurrences of this option, the <value> that appears earliest\n"
129 "in the list below has precedence. The default is 'fail'.\n"),
130 cl::value_desc("mode"),
131 cl::values(clEnumValN(DumpInputHelp
, "help", "Explain input dump and quit"),
132 clEnumValN(DumpInputAlways
, "always", "Always dump input"),
133 clEnumValN(DumpInputFail
, "fail", "Dump input on failure"),
134 clEnumValN(DumpInputNever
, "never", "Never dump input")));
136 // The order of DumpInputFilterValue members affects their precedence, as
137 // documented for -dump-input-filter below.
138 enum DumpInputFilterValue
{
139 DumpInputFilterError
,
140 DumpInputFilterAnnotation
,
141 DumpInputFilterAnnotationFull
,
145 static cl::list
<DumpInputFilterValue
> DumpInputFilters(
147 cl::desc("In the dump requested by -dump-input, print only input lines of\n"
148 "kind <value> plus any context specified by -dump-input-context.\n"
149 "When there are multiple occurrences of this option, the <value>\n"
150 "that appears earliest in the list below has precedence. The\n"
151 "default is 'error' when -dump-input=fail, and it's 'all' when\n"
152 "-dump-input=always.\n"),
153 cl::values(clEnumValN(DumpInputFilterAll
, "all", "All input lines"),
154 clEnumValN(DumpInputFilterAnnotationFull
, "annotation-full",
155 "Input lines with annotations"),
156 clEnumValN(DumpInputFilterAnnotation
, "annotation",
157 "Input lines with starting points of annotations"),
158 clEnumValN(DumpInputFilterError
, "error",
159 "Input lines with starting points of error "
162 static cl::list
<unsigned> DumpInputContexts(
163 "dump-input-context", cl::value_desc("N"),
164 cl::desc("In the dump requested by -dump-input, print <N> input lines\n"
165 "before and <N> input lines after any lines specified by\n"
166 "-dump-input-filter. When there are multiple occurrences of\n"
167 "this option, the largest specified <N> has precedence. The\n"
170 typedef cl::list
<std::string
>::const_iterator prefix_iterator
;
178 static void DumpCommandLine(int argc
, char **argv
) {
179 errs() << "FileCheck command line: ";
180 for (int I
= 0; I
< argc
; I
++)
181 errs() << " " << argv
[I
];
186 /// The starting char (before tildes) for marking the line.
188 /// What color to use for this annotation.
189 raw_ostream::Colors Color
;
190 /// A note to follow the marker, or empty string if none.
192 /// Does this marker indicate inclusion by -dump-input-filter=error?
195 MarkerStyle(char Lead
, raw_ostream::Colors Color
,
196 const std::string
&Note
= "", bool FiltersAsError
= false)
197 : Lead(Lead
), Color(Color
), Note(Note
), FiltersAsError(FiltersAsError
) {
198 assert((!FiltersAsError
|| !Note
.empty()) &&
199 "expected error diagnostic to have note");
203 static MarkerStyle
GetMarker(FileCheckDiag::MatchType MatchTy
) {
205 case FileCheckDiag::MatchFoundAndExpected
:
206 return MarkerStyle('^', raw_ostream::GREEN
);
207 case FileCheckDiag::MatchFoundButExcluded
:
208 return MarkerStyle('!', raw_ostream::RED
, "error: no match expected",
209 /*FiltersAsError=*/true);
210 case FileCheckDiag::MatchFoundButWrongLine
:
211 return MarkerStyle('!', raw_ostream::RED
, "error: match on wrong line",
212 /*FiltersAsError=*/true);
213 case FileCheckDiag::MatchFoundButDiscarded
:
214 return MarkerStyle('!', raw_ostream::CYAN
,
215 "discard: overlaps earlier match");
216 case FileCheckDiag::MatchFoundErrorNote
:
217 // Note should always be overridden within the FileCheckDiag.
218 return MarkerStyle('!', raw_ostream::RED
,
219 "error: unknown error after match",
220 /*FiltersAsError=*/true);
221 case FileCheckDiag::MatchNoneAndExcluded
:
222 return MarkerStyle('X', raw_ostream::GREEN
);
223 case FileCheckDiag::MatchNoneButExpected
:
224 return MarkerStyle('X', raw_ostream::RED
, "error: no match found",
225 /*FiltersAsError=*/true);
226 case FileCheckDiag::MatchNoneForInvalidPattern
:
227 return MarkerStyle('X', raw_ostream::RED
,
228 "error: match failed for invalid pattern",
229 /*FiltersAsError=*/true);
230 case FileCheckDiag::MatchFuzzy
:
231 return MarkerStyle('?', raw_ostream::MAGENTA
, "possible intended match",
232 /*FiltersAsError=*/true);
234 llvm_unreachable_internal("unexpected match type");
237 static void DumpInputAnnotationHelp(raw_ostream
&OS
) {
238 OS
<< "The following description was requested by -dump-input=help to\n"
239 << "explain the input dump printed by FileCheck.\n"
241 << "Related command-line options:\n"
243 << " - -dump-input=<value> enables or disables the input dump\n"
244 << " - -dump-input-filter=<value> filters the input lines\n"
245 << " - -dump-input-context=<N> adjusts the context of filtered lines\n"
246 << " - -v and -vv add more annotations\n"
247 << " - -color forces colors to be enabled both in the dump and below\n"
248 << " - -help documents the above options in more detail\n"
250 << "These options can also be set via FILECHECK_OPTS. For example, for\n"
251 << "maximum debugging output on failures:\n"
253 << " $ FILECHECK_OPTS='-dump-input-filter=all -vv -color' ninja check\n"
255 << "Input dump annotation format:\n"
258 // Labels for input lines.
260 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "L:";
261 OS
<< " labels line number L of the input file\n"
262 << " An extra space is added after each input line to represent"
264 << " newline character\n";
266 // Labels for annotation lines.
268 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "T:L";
269 OS
<< " labels the only match result for either (1) a pattern of type T"
271 << " line L of the check file if L is an integer or (2) the"
272 << " I-th implicit\n"
273 << " pattern if L is \"imp\" followed by an integer "
274 << "I (index origin one)\n";
276 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "T:L'N";
277 OS
<< " labels the Nth match result for such a pattern\n";
279 // Markers on annotation lines.
281 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "^~~";
282 OS
<< " marks good match (reported if -v)\n"
284 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "!~~";
285 OS
<< " marks bad match, such as:\n"
286 << " - CHECK-NEXT on same line as previous match (error)\n"
287 << " - CHECK-NOT found (error)\n"
288 << " - CHECK-DAG overlapping match (discarded, reported if "
291 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "X~~";
292 OS
<< " marks search range when no match is found, such as:\n"
293 << " - CHECK-NEXT not found (error)\n"
294 << " - CHECK-NOT not found (success, reported if -vv)\n"
295 << " - CHECK-DAG not found after discarded matches (error)\n"
297 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "?";
298 OS
<< " marks fuzzy match when no match is found\n";
302 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "...";
303 OS
<< " indicates elided input lines and annotations, as specified by\n"
304 << " -dump-input-filter and -dump-input-context\n";
308 WithColor(OS
, raw_ostream::GREEN
, true) << "success";
310 WithColor(OS
, raw_ostream::RED
, true) << "error";
312 WithColor(OS
, raw_ostream::MAGENTA
, true) << "fuzzy match";
314 WithColor(OS
, raw_ostream::CYAN
, true, false) << "discarded match";
316 WithColor(OS
, raw_ostream::CYAN
, true, true) << "unmatched input";
320 /// An annotation for a single input line.
321 struct InputAnnotation
{
322 /// The index of the match result across all checks
324 /// The label for this annotation.
326 /// Is this the initial fragment of a diagnostic that has been broken across
329 /// What input line (one-origin indexing) this annotation marks. This might
330 /// be different from the starting line of the original diagnostic if
333 /// The column range (one-origin indexing, open end) in which to mark the
334 /// input line. If InputEndCol is UINT_MAX, treat it as the last column
335 /// before the newline.
336 unsigned InputStartCol
, InputEndCol
;
337 /// The marker to use.
339 /// Whether this annotation represents a good match for an expected pattern.
340 bool FoundAndExpectedMatch
;
343 /// Get an abbreviation for the check type.
344 static std::string
GetCheckTypeAbbreviation(Check::FileCheckType Ty
) {
346 case Check::CheckPlain
:
347 if (Ty
.getCount() > 1)
350 case Check::CheckNext
:
352 case Check::CheckSame
:
354 case Check::CheckNot
:
356 case Check::CheckDAG
:
358 case Check::CheckLabel
:
360 case Check::CheckEmpty
:
362 case Check::CheckComment
:
364 case Check::CheckEOF
:
366 case Check::CheckBadNot
:
368 case Check::CheckBadCount
:
370 case Check::CheckNone
:
371 llvm_unreachable("invalid FileCheckType");
373 llvm_unreachable("unknown FileCheckType");
377 BuildInputAnnotations(const SourceMgr
&SM
, unsigned CheckFileBufferID
,
378 const std::pair
<unsigned, unsigned> &ImpPatBufferIDRange
,
379 const std::vector
<FileCheckDiag
> &Diags
,
380 std::vector
<InputAnnotation
> &Annotations
,
381 unsigned &LabelWidth
) {
382 struct CompareSMLoc
{
383 bool operator()(const SMLoc
&LHS
, const SMLoc
&RHS
) const {
384 return LHS
.getPointer() < RHS
.getPointer();
387 // How many diagnostics does each pattern have?
388 std::map
<SMLoc
, unsigned, CompareSMLoc
> DiagCountPerPattern
;
389 for (auto Diag
: Diags
)
390 ++DiagCountPerPattern
[Diag
.CheckLoc
];
391 // How many diagnostics have we seen so far per pattern?
392 std::map
<SMLoc
, unsigned, CompareSMLoc
> DiagIndexPerPattern
;
393 // How many total diagnostics have we seen so far?
394 unsigned DiagIndex
= 0;
395 // What's the widest label?
397 for (auto DiagItr
= Diags
.begin(), DiagEnd
= Diags
.end(); DiagItr
!= DiagEnd
;
400 A
.DiagIndex
= DiagIndex
++;
402 // Build label, which uniquely identifies this check result.
403 unsigned CheckBufferID
= SM
.FindBufferContainingLoc(DiagItr
->CheckLoc
);
404 auto CheckLineAndCol
=
405 SM
.getLineAndColumn(DiagItr
->CheckLoc
, CheckBufferID
);
406 llvm::raw_string_ostream
Label(A
.Label
);
407 Label
<< GetCheckTypeAbbreviation(DiagItr
->CheckTy
) << ":";
408 if (CheckBufferID
== CheckFileBufferID
)
409 Label
<< CheckLineAndCol
.first
;
410 else if (ImpPatBufferIDRange
.first
<= CheckBufferID
&&
411 CheckBufferID
< ImpPatBufferIDRange
.second
)
412 Label
<< "imp" << (CheckBufferID
- ImpPatBufferIDRange
.first
+ 1);
414 llvm_unreachable("expected diagnostic's check location to be either in "
415 "the check file or for an implicit pattern");
416 if (DiagCountPerPattern
[DiagItr
->CheckLoc
] > 1)
417 Label
<< "'" << DiagIndexPerPattern
[DiagItr
->CheckLoc
]++;
419 LabelWidth
= std::max((std::string::size_type
)LabelWidth
, A
.Label
.size());
421 A
.Marker
= GetMarker(DiagItr
->MatchTy
);
422 if (!DiagItr
->Note
.empty()) {
423 A
.Marker
.Note
= DiagItr
->Note
;
424 // It's less confusing if notes that don't actually have ranges don't have
425 // markers. For example, a marker for 'with "VAR" equal to "5"' would
426 // seem to indicate where "VAR" matches, but the location we actually have
427 // for the marker simply points to the start of the match/search range for
428 // the full pattern of which the substitution is potentially just one
430 if (DiagItr
->InputStartLine
== DiagItr
->InputEndLine
&&
431 DiagItr
->InputStartCol
== DiagItr
->InputEndCol
)
434 if (DiagItr
->MatchTy
== FileCheckDiag::MatchFoundErrorNote
) {
435 assert(!DiagItr
->Note
.empty() &&
436 "expected custom note for MatchFoundErrorNote");
437 A
.Marker
.Note
= "error: " + A
.Marker
.Note
;
439 A
.FoundAndExpectedMatch
=
440 DiagItr
->MatchTy
== FileCheckDiag::MatchFoundAndExpected
;
442 // Compute the mark location, and break annotation into multiple
443 // annotations if it spans multiple lines.
444 A
.IsFirstLine
= true;
445 A
.InputLine
= DiagItr
->InputStartLine
;
446 A
.InputStartCol
= DiagItr
->InputStartCol
;
447 if (DiagItr
->InputStartLine
== DiagItr
->InputEndLine
) {
448 // Sometimes ranges are empty in order to indicate a specific point, but
449 // that would mean nothing would be marked, so adjust the range to
450 // include the following character.
452 std::max(DiagItr
->InputStartCol
+ 1, DiagItr
->InputEndCol
);
453 Annotations
.push_back(A
);
455 assert(DiagItr
->InputStartLine
< DiagItr
->InputEndLine
&&
456 "expected input range not to be inverted");
457 A
.InputEndCol
= UINT_MAX
;
458 Annotations
.push_back(A
);
459 for (unsigned L
= DiagItr
->InputStartLine
+ 1, E
= DiagItr
->InputEndLine
;
461 // If a range ends before the first column on a line, then it has no
462 // characters on that line, so there's nothing to render.
463 if (DiagItr
->InputEndCol
== 1 && L
== E
)
466 B
.DiagIndex
= A
.DiagIndex
;
468 B
.IsFirstLine
= false;
475 B
.InputEndCol
= UINT_MAX
;
477 B
.InputEndCol
= DiagItr
->InputEndCol
;
478 B
.FoundAndExpectedMatch
= A
.FoundAndExpectedMatch
;
479 Annotations
.push_back(B
);
485 static unsigned FindInputLineInFilter(
486 DumpInputFilterValue DumpInputFilter
, unsigned CurInputLine
,
487 const std::vector
<InputAnnotation
>::iterator
&AnnotationBeg
,
488 const std::vector
<InputAnnotation
>::iterator
&AnnotationEnd
) {
489 if (DumpInputFilter
== DumpInputFilterAll
)
491 for (auto AnnotationItr
= AnnotationBeg
; AnnotationItr
!= AnnotationEnd
;
493 switch (DumpInputFilter
) {
494 case DumpInputFilterAll
:
495 llvm_unreachable("unexpected DumpInputFilterAll");
497 case DumpInputFilterAnnotationFull
:
498 return AnnotationItr
->InputLine
;
499 case DumpInputFilterAnnotation
:
500 if (AnnotationItr
->IsFirstLine
)
501 return AnnotationItr
->InputLine
;
503 case DumpInputFilterError
:
504 if (AnnotationItr
->IsFirstLine
&& AnnotationItr
->Marker
.FiltersAsError
)
505 return AnnotationItr
->InputLine
;
512 /// To OS, print a vertical ellipsis (right-justified at LabelWidth) if it would
513 /// occupy less lines than ElidedLines, but print ElidedLines otherwise. Either
514 /// way, clear ElidedLines. Thus, if ElidedLines is empty, do nothing.
515 static void DumpEllipsisOrElidedLines(raw_ostream
&OS
, std::string
&ElidedLines
,
516 unsigned LabelWidth
) {
517 if (ElidedLines
.empty())
519 unsigned EllipsisLines
= 3;
520 if (EllipsisLines
< StringRef(ElidedLines
).count('\n')) {
521 for (unsigned i
= 0; i
< EllipsisLines
; ++i
) {
522 WithColor(OS
, raw_ostream::BLACK
, /*Bold=*/true)
523 << right_justify(".", LabelWidth
);
531 static void DumpAnnotatedInput(raw_ostream
&OS
, const FileCheckRequest
&Req
,
532 DumpInputFilterValue DumpInputFilter
,
533 unsigned DumpInputContext
,
534 StringRef InputFileText
,
535 std::vector
<InputAnnotation
> &Annotations
,
536 unsigned LabelWidth
) {
537 OS
<< "Input was:\n<<<<<<\n";
540 llvm::sort(Annotations
,
541 [](const InputAnnotation
&A
, const InputAnnotation
&B
) {
542 // 1. Sort annotations in the order of the input lines.
544 // This makes it easier to find relevant annotations while
545 // iterating input lines in the implementation below. FileCheck
546 // does not always produce diagnostics in the order of input
547 // lines due to, for example, CHECK-DAG and CHECK-NOT.
548 if (A
.InputLine
!= B
.InputLine
)
549 return A
.InputLine
< B
.InputLine
;
550 // 2. Sort annotations in the temporal order FileCheck produced
551 // their associated diagnostics.
553 // This sort offers several benefits:
555 // A. On a single input line, the order of annotations reflects
556 // the FileCheck logic for processing directives/patterns.
557 // This can be helpful in understanding cases in which the
558 // order of the associated directives/patterns in the check
559 // file or on the command line either (i) does not match the
560 // temporal order in which FileCheck looks for matches for the
561 // directives/patterns (due to, for example, CHECK-LABEL,
562 // CHECK-NOT, or `--implicit-check-not`) or (ii) does match
563 // that order but does not match the order of those
564 // diagnostics along an input line (due to, for example,
567 // On the other hand, because our presentation format presents
568 // input lines in order, there's no clear way to offer the
569 // same benefit across input lines. For consistency, it might
570 // then seem worthwhile to have annotations on a single line
571 // also sorted in input order (that is, by input column).
572 // However, in practice, this appears to be more confusing
573 // than helpful. Perhaps it's intuitive to expect annotations
574 // to be listed in the temporal order in which they were
575 // produced except in cases the presentation format obviously
576 // and inherently cannot support it (that is, across input
579 // B. When diagnostics' annotations are split among multiple
580 // input lines, the user must track them from one input line
581 // to the next. One property of the sort chosen here is that
582 // it facilitates the user in this regard by ensuring the
583 // following: when comparing any two input lines, a
584 // diagnostic's annotations are sorted in the same position
585 // relative to all other diagnostics' annotations.
586 return A
.DiagIndex
< B
.DiagIndex
;
589 // Compute the width of the label column.
590 const unsigned char *InputFilePtr
= InputFileText
.bytes_begin(),
591 *InputFileEnd
= InputFileText
.bytes_end();
592 unsigned LineCount
= InputFileText
.count('\n');
593 if (InputFileEnd
[-1] != '\n')
595 unsigned LineNoWidth
= std::log10(LineCount
) + 1;
596 // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
597 // on input lines and (2) to the right of the (left-aligned) labels on
598 // annotation lines so that input lines and annotation lines are more
599 // visually distinct. For example, the spaces on the annotation lines ensure
600 // that input line numbers and check directive line numbers never align
601 // horizontally. Those line numbers might not even be for the same file.
602 // One space would be enough to achieve that, but more makes it even easier
604 LabelWidth
= std::max(LabelWidth
, LineNoWidth
) + 3;
606 // Print annotated input lines.
607 unsigned PrevLineInFilter
= 0; // 0 means none so far
608 unsigned NextLineInFilter
= 0; // 0 means uncomputed, UINT_MAX means none
609 std::string ElidedLines
;
610 raw_string_ostream
ElidedLinesOS(ElidedLines
);
611 ColorMode TheColorMode
=
612 WithColor(OS
).colorsEnabled() ? ColorMode::Enable
: ColorMode::Disable
;
613 if (TheColorMode
== ColorMode::Enable
)
614 ElidedLinesOS
.enable_colors(true);
615 auto AnnotationItr
= Annotations
.begin(), AnnotationEnd
= Annotations
.end();
616 for (unsigned Line
= 1;
617 InputFilePtr
!= InputFileEnd
|| AnnotationItr
!= AnnotationEnd
;
619 const unsigned char *InputFileLine
= InputFilePtr
;
621 // Compute the previous and next line included by the filter.
622 if (NextLineInFilter
< Line
)
623 NextLineInFilter
= FindInputLineInFilter(DumpInputFilter
, Line
,
624 AnnotationItr
, AnnotationEnd
);
625 assert(NextLineInFilter
&& "expected NextLineInFilter to be computed");
626 if (NextLineInFilter
== Line
)
627 PrevLineInFilter
= Line
;
629 // Elide this input line and its annotations if it's not within the
630 // context specified by -dump-input-context of an input line included by
631 // -dump-input-filter. However, in case the resulting ellipsis would occupy
632 // more lines than the input lines and annotations it elides, buffer the
633 // elided lines and annotations so we can print them instead.
634 raw_ostream
*LineOS
= &OS
;
635 if ((!PrevLineInFilter
|| PrevLineInFilter
+ DumpInputContext
< Line
) &&
636 (NextLineInFilter
== UINT_MAX
||
637 Line
+ DumpInputContext
< NextLineInFilter
))
638 LineOS
= &ElidedLinesOS
;
641 DumpEllipsisOrElidedLines(OS
, ElidedLinesOS
.str(), LabelWidth
);
644 // Print right-aligned line number.
645 WithColor(*LineOS
, raw_ostream::BLACK
, /*Bold=*/true, /*BF=*/false,
647 << format_decimal(Line
, LabelWidth
) << ": ";
649 // For the case where -v and colors are enabled, find the annotations for
650 // good matches for expected patterns in order to highlight everything
651 // else in the line. There are no such annotations if -v is disabled.
652 std::vector
<InputAnnotation
> FoundAndExpectedMatches
;
653 if (Req
.Verbose
&& TheColorMode
== ColorMode::Enable
) {
654 for (auto I
= AnnotationItr
; I
!= AnnotationEnd
&& I
->InputLine
== Line
;
656 if (I
->FoundAndExpectedMatch
)
657 FoundAndExpectedMatches
.push_back(*I
);
661 // Print numbered line with highlighting where there are no matches for
662 // expected patterns.
663 bool Newline
= false;
665 WithColor
COS(*LineOS
, raw_ostream::SAVEDCOLOR
, /*Bold=*/false,
666 /*BG=*/false, TheColorMode
);
667 bool InMatch
= false;
669 COS
.changeColor(raw_ostream::CYAN
, true, true);
670 for (unsigned Col
= 1; InputFilePtr
!= InputFileEnd
&& !Newline
; ++Col
) {
671 bool WasInMatch
= InMatch
;
673 for (auto M
: FoundAndExpectedMatches
) {
674 if (M
.InputStartCol
<= Col
&& Col
< M
.InputEndCol
) {
679 if (!WasInMatch
&& InMatch
)
681 else if (WasInMatch
&& !InMatch
)
682 COS
.changeColor(raw_ostream::CYAN
, true, true);
683 if (*InputFilePtr
== '\n') {
687 COS
<< *InputFilePtr
;
692 unsigned InputLineWidth
= InputFilePtr
- InputFileLine
;
694 // Print any annotations.
695 while (AnnotationItr
!= AnnotationEnd
&&
696 AnnotationItr
->InputLine
== Line
) {
697 WithColor
COS(*LineOS
, AnnotationItr
->Marker
.Color
, /*Bold=*/true,
698 /*BG=*/false, TheColorMode
);
699 // The two spaces below are where the ": " appears on input lines.
700 COS
<< left_justify(AnnotationItr
->Label
, LabelWidth
) << " ";
702 for (Col
= 1; Col
< AnnotationItr
->InputStartCol
; ++Col
)
704 COS
<< AnnotationItr
->Marker
.Lead
;
705 // If InputEndCol=UINT_MAX, stop at InputLineWidth.
706 for (++Col
; Col
< AnnotationItr
->InputEndCol
&& Col
<= InputLineWidth
;
709 const std::string
&Note
= AnnotationItr
->Marker
.Note
;
711 // Put the note at the end of the input line. If we were to instead
712 // put the note right after the marker, subsequent annotations for the
713 // same input line might appear to mark this note instead of the input
715 for (; Col
<= InputLineWidth
; ++Col
)
723 DumpEllipsisOrElidedLines(OS
, ElidedLinesOS
.str(), LabelWidth
);
728 int main(int argc
, char **argv
) {
729 // Enable use of ANSI color codes because FileCheck is using them to
731 llvm::sys::Process::UseANSIEscapeCodes(true);
733 InitLLVM
X(argc
, argv
);
734 cl::ParseCommandLineOptions(argc
, argv
, /*Overview*/ "", /*Errs*/ nullptr,
737 // Select -dump-input* values. The -help documentation specifies the default
738 // value and which value to choose if an option is specified multiple times.
739 // In the latter case, the general rule of thumb is to choose the value that
740 // provides the most information.
741 DumpInputValue DumpInput
=
744 : *std::max_element(DumpInputs
.begin(), DumpInputs
.end());
745 DumpInputFilterValue DumpInputFilter
;
746 if (DumpInputFilters
.empty())
747 DumpInputFilter
= DumpInput
== DumpInputAlways
? DumpInputFilterAll
748 : DumpInputFilterError
;
751 *std::max_element(DumpInputFilters
.begin(), DumpInputFilters
.end());
752 unsigned DumpInputContext
= DumpInputContexts
.empty()
754 : *std::max_element(DumpInputContexts
.begin(),
755 DumpInputContexts
.end());
757 if (DumpInput
== DumpInputHelp
) {
758 DumpInputAnnotationHelp(outs());
761 if (CheckFilename
.empty()) {
762 errs() << "<check-file> not specified\n";
766 FileCheckRequest Req
;
767 append_range(Req
.CheckPrefixes
, CheckPrefixes
);
769 append_range(Req
.CommentPrefixes
, CommentPrefixes
);
771 append_range(Req
.ImplicitCheckNot
, ImplicitCheckNot
);
773 bool GlobalDefineError
= false;
774 for (StringRef G
: GlobalDefines
) {
775 size_t EqIdx
= G
.find('=');
776 if (EqIdx
== std::string::npos
) {
777 errs() << "Missing equal sign in command-line definition '-D" << G
779 GlobalDefineError
= true;
783 errs() << "Missing variable name in command-line definition '-D" << G
785 GlobalDefineError
= true;
788 Req
.GlobalDefines
.push_back(G
);
790 if (GlobalDefineError
)
793 Req
.AllowEmptyInput
= AllowEmptyInput
;
794 Req
.AllowUnusedPrefixes
= AllowUnusedPrefixes
;
795 Req
.EnableVarScope
= EnableVarScope
;
796 Req
.AllowDeprecatedDagOverlap
= AllowDeprecatedDagOverlap
;
797 Req
.Verbose
= Verbose
;
798 Req
.VerboseVerbose
= VerboseVerbose
;
799 Req
.NoCanonicalizeWhiteSpace
= NoCanonicalizeWhiteSpace
;
800 Req
.MatchFullLines
= MatchFullLines
;
801 Req
.IgnoreCase
= IgnoreCase
;
807 if (!FC
.ValidateCheckPrefixes())
810 Regex PrefixRE
= FC
.buildCheckPrefixRegex();
812 if (!PrefixRE
.isValid(REError
)) {
813 errs() << "Unable to combine check-prefix strings into a prefix regular "
814 "expression! This is likely a bug in FileCheck's verification of "
815 "the check-prefix strings. Regular expression parsing failed "
816 "with the following error: "
823 // Read the expected strings from the check file.
824 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CheckFileOrErr
=
825 MemoryBuffer::getFileOrSTDIN(CheckFilename
, /*IsText=*/true);
826 if (std::error_code EC
= CheckFileOrErr
.getError()) {
827 errs() << "Could not open check file '" << CheckFilename
828 << "': " << EC
.message() << '\n';
831 MemoryBuffer
&CheckFile
= *CheckFileOrErr
.get();
833 SmallString
<4096> CheckFileBuffer
;
834 StringRef CheckFileText
= FC
.CanonicalizeFile(CheckFile
, CheckFileBuffer
);
836 unsigned CheckFileBufferID
=
837 SM
.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
838 CheckFileText
, CheckFile
.getBufferIdentifier()),
841 std::pair
<unsigned, unsigned> ImpPatBufferIDRange
;
842 if (FC
.readCheckFile(SM
, CheckFileText
, PrefixRE
, &ImpPatBufferIDRange
))
845 // Open the file to check and add it to SourceMgr.
846 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> InputFileOrErr
=
847 MemoryBuffer::getFileOrSTDIN(InputFilename
, /*IsText=*/true);
848 if (InputFilename
== "-")
849 InputFilename
= "<stdin>"; // Overwrite for improved diagnostic messages
850 if (std::error_code EC
= InputFileOrErr
.getError()) {
851 errs() << "Could not open input file '" << InputFilename
852 << "': " << EC
.message() << '\n';
855 MemoryBuffer
&InputFile
= *InputFileOrErr
.get();
857 if (InputFile
.getBufferSize() == 0 && !AllowEmptyInput
) {
858 errs() << "FileCheck error: '" << InputFilename
<< "' is empty.\n";
859 DumpCommandLine(argc
, argv
);
863 SmallString
<4096> InputFileBuffer
;
864 StringRef InputFileText
= FC
.CanonicalizeFile(InputFile
, InputFileBuffer
);
866 SM
.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
867 InputFileText
, InputFile
.getBufferIdentifier()),
870 std::vector
<FileCheckDiag
> Diags
;
871 int ExitCode
= FC
.checkInput(SM
, InputFileText
,
872 DumpInput
== DumpInputNever
? nullptr : &Diags
)
875 if (DumpInput
== DumpInputAlways
||
876 (ExitCode
== 1 && DumpInput
== DumpInputFail
)) {
878 << "Input file: " << InputFilename
<< "\n"
879 << "Check file: " << CheckFilename
<< "\n"
881 << "-dump-input=help explains the following input dump.\n"
883 std::vector
<InputAnnotation
> Annotations
;
885 BuildInputAnnotations(SM
, CheckFileBufferID
, ImpPatBufferIDRange
, Diags
,
886 Annotations
, LabelWidth
);
887 DumpAnnotatedInput(errs(), Req
, DumpInputFilter
, DumpInputContext
,
888 InputFileText
, Annotations
, LabelWidth
);