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