xref: /llvm-project/llvm/utils/FileCheck/FileCheck.cpp (revision d0e7fd6b624b1943f3780a69883690017d2efad2)
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/Support/CommandLine.h"
19 #include "llvm/Support/InitLLVM.h"
20 #include "llvm/Support/Process.h"
21 #include "llvm/Support/WithColor.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "llvm/Support/FileCheck.h"
24 #include <cmath>
25 using namespace llvm;
26 
27 static cl::extrahelp FileCheckOptsEnv(
28     "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"
29     "from the command line.\n");
30 
31 static cl::opt<std::string>
32     CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
33 
34 static cl::opt<std::string>
35     InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
36                   cl::init("-"), cl::value_desc("filename"));
37 
38 static cl::list<std::string> CheckPrefixes(
39     "check-prefix",
40     cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
41 static cl::alias CheckPrefixesAlias(
42     "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
43     cl::NotHidden,
44     cl::desc(
45         "Alias for -check-prefix permitting multiple comma separated values"));
46 
47 static cl::opt<bool> NoCanonicalizeWhiteSpace(
48     "strict-whitespace",
49     cl::desc("Do not treat all horizontal whitespace as equivalent"));
50 
51 static cl::opt<bool> IgnoreCase(
52     "ignore-case",
53     cl::desc("Use case-insensitive matching"));
54 
55 static cl::list<std::string> ImplicitCheckNot(
56     "implicit-check-not",
57     cl::desc("Add an implicit negative check with this pattern to every\n"
58              "positive check. This can be used to ensure that no instances of\n"
59              "this pattern occur which are not matched by a positive pattern"),
60     cl::value_desc("pattern"));
61 
62 static cl::list<std::string>
63     GlobalDefines("D", cl::AlwaysPrefix,
64                   cl::desc("Define a variable to be used in capture patterns."),
65                   cl::value_desc("VAR=VALUE"));
66 
67 static cl::opt<bool> AllowEmptyInput(
68     "allow-empty", cl::init(false),
69     cl::desc("Allow the input file to be empty. This is useful when making\n"
70              "checks that some error message does not occur, for example."));
71 
72 static cl::opt<bool> MatchFullLines(
73     "match-full-lines", cl::init(false),
74     cl::desc("Require all positive matches to cover an entire input line.\n"
75              "Allows leading and trailing whitespace if --strict-whitespace\n"
76              "is not also passed."));
77 
78 static cl::opt<bool> EnableVarScope(
79     "enable-var-scope", cl::init(false),
80     cl::desc("Enables scope for regex variables. Variables with names that\n"
81              "do not start with '$' will be reset at the beginning of\n"
82              "each CHECK-LABEL block."));
83 
84 static cl::opt<bool> AllowDeprecatedDagOverlap(
85     "allow-deprecated-dag-overlap", cl::init(false),
86     cl::desc("Enable overlapping among matches in a group of consecutive\n"
87              "CHECK-DAG directives.  This option is deprecated and is only\n"
88              "provided for convenience as old tests are migrated to the new\n"
89              "non-overlapping CHECK-DAG implementation.\n"));
90 
91 static cl::opt<bool> Verbose(
92     "v", cl::init(false),
93     cl::desc("Print directive pattern matches, or add them to the input dump\n"
94              "if enabled.\n"));
95 
96 static cl::opt<bool> VerboseVerbose(
97     "vv", cl::init(false),
98     cl::desc("Print information helpful in diagnosing internal FileCheck\n"
99              "issues, or add it to the input dump if enabled.  Implies\n"
100              "-v.\n"));
101 static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";
102 
103 static cl::opt<bool> DumpInputOnFailure(
104     "dump-input-on-failure",
105     cl::init(std::getenv(DumpInputEnv) && *std::getenv(DumpInputEnv)),
106     cl::desc("Dump original input to stderr before failing.\n"
107              "The value can be also controlled using\n"
108              "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"
109              "This option is deprecated in favor of -dump-input=fail.\n"));
110 
111 // The order of DumpInputValue members affects their precedence, as documented
112 // for -dump-input below.
113 enum DumpInputValue {
114   DumpInputDefault,
115   DumpInputNever,
116   DumpInputFail,
117   DumpInputAlways,
118   DumpInputHelp
119 };
120 
121 static cl::list<DumpInputValue> DumpInputs(
122     "dump-input",
123     cl::desc("Dump input to stderr, adding annotations representing\n"
124              "currently enabled diagnostics.  When there are multiple\n"
125              "occurrences of this option, the <value> that appears earliest\n"
126              "in the list below has precedence.\n"),
127     cl::value_desc("mode"),
128     cl::values(clEnumValN(DumpInputHelp, "help",
129                           "Explain dump format and quit"),
130                clEnumValN(DumpInputAlways, "always", "Always dump input"),
131                clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
132                clEnumValN(DumpInputNever, "never", "Never dump input")));
133 
134 typedef cl::list<std::string>::const_iterator prefix_iterator;
135 
136 
137 
138 
139 
140 
141 
142 static void DumpCommandLine(int argc, char **argv) {
143   errs() << "FileCheck command line: ";
144   for (int I = 0; I < argc; I++)
145     errs() << " " << argv[I];
146   errs() << "\n";
147 }
148 
149 struct MarkerStyle {
150   /// The starting char (before tildes) for marking the line.
151   char Lead;
152   /// What color to use for this annotation.
153   raw_ostream::Colors Color;
154   /// A note to follow the marker, or empty string if none.
155   std::string Note;
156   MarkerStyle() {}
157   MarkerStyle(char Lead, raw_ostream::Colors Color,
158               const std::string &Note = "")
159       : Lead(Lead), Color(Color), Note(Note) {}
160 };
161 
162 static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
163   switch (MatchTy) {
164   case FileCheckDiag::MatchFoundAndExpected:
165     return MarkerStyle('^', raw_ostream::GREEN);
166   case FileCheckDiag::MatchFoundButExcluded:
167     return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
168   case FileCheckDiag::MatchFoundButWrongLine:
169     return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
170   case FileCheckDiag::MatchFoundButDiscarded:
171     return MarkerStyle('!', raw_ostream::CYAN,
172                        "discard: overlaps earlier match");
173   case FileCheckDiag::MatchNoneAndExcluded:
174     return MarkerStyle('X', raw_ostream::GREEN);
175   case FileCheckDiag::MatchNoneButExpected:
176     return MarkerStyle('X', raw_ostream::RED, "error: no match found");
177   case FileCheckDiag::MatchFuzzy:
178     return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
179   }
180   llvm_unreachable_internal("unexpected match type");
181 }
182 
183 static void DumpInputAnnotationHelp(raw_ostream &OS) {
184   OS << "The following description was requested by -dump-input=help to\n"
185      << "explain the input annotations printed by -dump-input=always and\n"
186      << "-dump-input=fail:\n\n";
187 
188   // Labels for input lines.
189   OS << "  - ";
190   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
191   OS << "     labels line number L of the input file\n";
192 
193   // Labels for annotation lines.
194   OS << "  - ";
195   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
196   OS << "    labels the only match result for either (1) a pattern of type T"
197      << " from\n"
198      << "           line L of the check file if L is an integer or (2) the"
199      << " I-th implicit\n"
200      << "           pattern if L is \"imp\" followed by an integer "
201      << "I (index origin one)\n";
202   OS << "  - ";
203   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
204   OS << "  labels the Nth match result for such a pattern\n";
205 
206   // Markers on annotation lines.
207   OS << "  - ";
208   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
209   OS << "    marks good match (reported if -v)\n"
210      << "  - ";
211   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
212   OS << "    marks bad match, such as:\n"
213      << "           - CHECK-NEXT on same line as previous match (error)\n"
214      << "           - CHECK-NOT found (error)\n"
215      << "           - CHECK-DAG overlapping match (discarded, reported if "
216      << "-vv)\n"
217      << "  - ";
218   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
219   OS << "    marks search range when no match is found, such as:\n"
220      << "           - CHECK-NEXT not found (error)\n"
221      << "           - CHECK-NOT not found (success, reported if -vv)\n"
222      << "           - CHECK-DAG not found after discarded matches (error)\n"
223      << "  - ";
224   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
225   OS << "      marks fuzzy match when no match is found\n";
226 
227   // Colors.
228   OS << "  - colors ";
229   WithColor(OS, raw_ostream::GREEN, true) << "success";
230   OS << ", ";
231   WithColor(OS, raw_ostream::RED, true) << "error";
232   OS << ", ";
233   WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
234   OS << ", ";
235   WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
236   OS << ", ";
237   WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
238   OS << "\n\n"
239      << "If you are not seeing color above or in input dumps, try: -color\n";
240 }
241 
242 /// An annotation for a single input line.
243 struct InputAnnotation {
244   /// The index of the match result across all checks
245   unsigned DiagIndex;
246   /// The label for this annotation.
247   std::string Label;
248   /// What input line (one-origin indexing) this annotation marks.  This might
249   /// be different from the starting line of the original diagnostic if this is
250   /// a non-initial fragment of a diagnostic that has been broken across
251   /// multiple lines.
252   unsigned InputLine;
253   /// The column range (one-origin indexing, open end) in which to mark the
254   /// input line.  If InputEndCol is UINT_MAX, treat it as the last column
255   /// before the newline.
256   unsigned InputStartCol, InputEndCol;
257   /// The marker to use.
258   MarkerStyle Marker;
259   /// Whether this annotation represents a good match for an expected pattern.
260   bool FoundAndExpectedMatch;
261 };
262 
263 /// Get an abbreviation for the check type.
264 std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
265   switch (Ty) {
266   case Check::CheckPlain:
267     if (Ty.getCount() > 1)
268       return "count";
269     return "check";
270   case Check::CheckNext:
271     return "next";
272   case Check::CheckSame:
273     return "same";
274   case Check::CheckNot:
275     return "not";
276   case Check::CheckDAG:
277     return "dag";
278   case Check::CheckLabel:
279     return "label";
280   case Check::CheckEmpty:
281     return "empty";
282   case Check::CheckEOF:
283     return "eof";
284   case Check::CheckBadNot:
285     return "bad-not";
286   case Check::CheckBadCount:
287     return "bad-count";
288   case Check::CheckNone:
289     llvm_unreachable("invalid FileCheckType");
290   }
291   llvm_unreachable("unknown FileCheckType");
292 }
293 
294 static void
295 BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
296                       const std::pair<unsigned, unsigned> &ImpPatBufferIDRange,
297                       const std::vector<FileCheckDiag> &Diags,
298                       std::vector<InputAnnotation> &Annotations,
299                       unsigned &LabelWidth) {
300   // How many diagnostics have we seen so far?
301   unsigned DiagCount = 0;
302   // How many diagnostics has the current check seen so far?
303   unsigned CheckDiagCount = 0;
304   // What's the widest label?
305   LabelWidth = 0;
306   for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
307        ++DiagItr) {
308     InputAnnotation A;
309     A.DiagIndex = DiagCount++;
310 
311     // Build label, which uniquely identifies this check result.
312     unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc);
313     auto CheckLineAndCol =
314         SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID);
315     llvm::raw_string_ostream Label(A.Label);
316     Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":";
317     if (CheckBufferID == CheckFileBufferID)
318       Label << CheckLineAndCol.first;
319     else if (ImpPatBufferIDRange.first <= CheckBufferID &&
320              CheckBufferID < ImpPatBufferIDRange.second)
321       Label << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1);
322     else
323       llvm_unreachable("expected diagnostic's check location to be either in "
324                        "the check file or for an implicit pattern");
325     unsigned CheckDiagIndex = UINT_MAX;
326     auto DiagNext = std::next(DiagItr);
327     if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
328         DiagItr->CheckLoc == DiagNext->CheckLoc)
329       CheckDiagIndex = CheckDiagCount++;
330     else if (CheckDiagCount) {
331       CheckDiagIndex = CheckDiagCount;
332       CheckDiagCount = 0;
333     }
334     if (CheckDiagIndex != UINT_MAX)
335       Label << "'" << CheckDiagIndex;
336     Label.flush();
337     LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
338 
339     A.Marker = GetMarker(DiagItr->MatchTy);
340     A.FoundAndExpectedMatch =
341         DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
342 
343     // Compute the mark location, and break annotation into multiple
344     // annotations if it spans multiple lines.
345     A.InputLine = DiagItr->InputStartLine;
346     A.InputStartCol = DiagItr->InputStartCol;
347     if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
348       // Sometimes ranges are empty in order to indicate a specific point, but
349       // that would mean nothing would be marked, so adjust the range to
350       // include the following character.
351       A.InputEndCol =
352           std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
353       Annotations.push_back(A);
354     } else {
355       assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
356              "expected input range not to be inverted");
357       A.InputEndCol = UINT_MAX;
358       Annotations.push_back(A);
359       for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
360            L <= E; ++L) {
361         // If a range ends before the first column on a line, then it has no
362         // characters on that line, so there's nothing to render.
363         if (DiagItr->InputEndCol == 1 && L == E)
364           break;
365         InputAnnotation B;
366         B.DiagIndex = A.DiagIndex;
367         B.Label = A.Label;
368         B.InputLine = L;
369         B.Marker = A.Marker;
370         B.Marker.Lead = '~';
371         B.Marker.Note = "";
372         B.InputStartCol = 1;
373         if (L != E)
374           B.InputEndCol = UINT_MAX;
375         else
376           B.InputEndCol = DiagItr->InputEndCol;
377         B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
378         Annotations.push_back(B);
379       }
380     }
381   }
382 }
383 
384 static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
385                                StringRef InputFileText,
386                                std::vector<InputAnnotation> &Annotations,
387                                unsigned LabelWidth) {
388   OS << "Full input was:\n<<<<<<\n";
389 
390   // Sort annotations.
391   std::sort(Annotations.begin(), Annotations.end(),
392             [](const InputAnnotation &A, const InputAnnotation &B) {
393               // 1. Sort annotations in the order of the input lines.
394               //
395               // This makes it easier to find relevant annotations while
396               // iterating input lines in the implementation below.  FileCheck
397               // does not always produce diagnostics in the order of input
398               // lines due to, for example, CHECK-DAG and CHECK-NOT.
399               if (A.InputLine != B.InputLine)
400                 return A.InputLine < B.InputLine;
401               // 2. Sort annotations in the temporal order FileCheck produced
402               // their associated diagnostics.
403               //
404               // This sort offers several benefits:
405               //
406               // A. On a single input line, the order of annotations reflects
407               //    the FileCheck logic for processing directives/patterns.
408               //    This can be helpful in understanding cases in which the
409               //    order of the associated directives/patterns in the check
410               //    file or on the command line either (i) does not match the
411               //    temporal order in which FileCheck looks for matches for the
412               //    directives/patterns (due to, for example, CHECK-LABEL,
413               //    CHECK-NOT, or `--implicit-check-not`) or (ii) does match
414               //    that order but does not match the order of those
415               //    diagnostics along an input line (due to, for example,
416               //    CHECK-DAG).
417               //
418               //    On the other hand, because our presentation format presents
419               //    input lines in order, there's no clear way to offer the
420               //    same benefit across input lines.  For consistency, it might
421               //    then seem worthwhile to have annotations on a single line
422               //    also sorted in input order (that is, by input column).
423               //    However, in practice, this appears to be more confusing
424               //    than helpful.  Perhaps it's intuitive to expect annotations
425               //    to be listed in the temporal order in which they were
426               //    produced except in cases the presentation format obviously
427               //    and inherently cannot support it (that is, across input
428               //    lines).
429               //
430               // B. When diagnostics' annotations are split among multiple
431               //    input lines, the user must track them from one input line
432               //    to the next.  One property of the sort chosen here is that
433               //    it facilitates the user in this regard by ensuring the
434               //    following: when comparing any two input lines, a
435               //    diagnostic's annotations are sorted in the same position
436               //    relative to all other diagnostics' annotations.
437               return A.DiagIndex < B.DiagIndex;
438             });
439 
440   // Compute the width of the label column.
441   const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
442                       *InputFileEnd = InputFileText.bytes_end();
443   unsigned LineCount = InputFileText.count('\n');
444   if (InputFileEnd[-1] != '\n')
445     ++LineCount;
446   unsigned LineNoWidth = std::log10(LineCount) + 1;
447   // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
448   // on input lines and (2) to the right of the (left-aligned) labels on
449   // annotation lines so that input lines and annotation lines are more
450   // visually distinct.  For example, the spaces on the annotation lines ensure
451   // that input line numbers and check directive line numbers never align
452   // horizontally.  Those line numbers might not even be for the same file.
453   // One space would be enough to achieve that, but more makes it even easier
454   // to see.
455   LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
456 
457   // Print annotated input lines.
458   auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
459   for (unsigned Line = 1;
460        InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
461        ++Line) {
462     const unsigned char *InputFileLine = InputFilePtr;
463 
464     // Print right-aligned line number.
465     WithColor(OS, raw_ostream::BLACK, true)
466         << format_decimal(Line, LabelWidth) << ": ";
467 
468     // For the case where -v and colors are enabled, find the annotations for
469     // good matches for expected patterns in order to highlight everything
470     // else in the line.  There are no such annotations if -v is disabled.
471     std::vector<InputAnnotation> FoundAndExpectedMatches;
472     if (Req.Verbose && WithColor(OS).colorsEnabled()) {
473       for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
474            ++I) {
475         if (I->FoundAndExpectedMatch)
476           FoundAndExpectedMatches.push_back(*I);
477       }
478     }
479 
480     // Print numbered line with highlighting where there are no matches for
481     // expected patterns.
482     bool Newline = false;
483     {
484       WithColor COS(OS);
485       bool InMatch = false;
486       if (Req.Verbose)
487         COS.changeColor(raw_ostream::CYAN, true, true);
488       for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
489         bool WasInMatch = InMatch;
490         InMatch = false;
491         for (auto M : FoundAndExpectedMatches) {
492           if (M.InputStartCol <= Col && Col < M.InputEndCol) {
493             InMatch = true;
494             break;
495           }
496         }
497         if (!WasInMatch && InMatch)
498           COS.resetColor();
499         else if (WasInMatch && !InMatch)
500           COS.changeColor(raw_ostream::CYAN, true, true);
501         if (*InputFilePtr == '\n')
502           Newline = true;
503         else
504           COS << *InputFilePtr;
505         ++InputFilePtr;
506       }
507     }
508     OS << '\n';
509     unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
510 
511     // Print any annotations.
512     while (AnnotationItr != AnnotationEnd &&
513            AnnotationItr->InputLine == Line) {
514       WithColor COS(OS, AnnotationItr->Marker.Color, true);
515       // The two spaces below are where the ": " appears on input lines.
516       COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";
517       unsigned Col;
518       for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
519         COS << ' ';
520       COS << AnnotationItr->Marker.Lead;
521       // If InputEndCol=UINT_MAX, stop at InputLineWidth.
522       for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
523            ++Col)
524         COS << '~';
525       const std::string &Note = AnnotationItr->Marker.Note;
526       if (!Note.empty()) {
527         // Put the note at the end of the input line.  If we were to instead
528         // put the note right after the marker, subsequent annotations for the
529         // same input line might appear to mark this note instead of the input
530         // line.
531         for (; Col <= InputLineWidth; ++Col)
532           COS << ' ';
533         COS << ' ' << Note;
534       }
535       COS << '\n';
536       ++AnnotationItr;
537     }
538   }
539 
540   OS << ">>>>>>\n";
541 }
542 
543 int main(int argc, char **argv) {
544   // Enable use of ANSI color codes because FileCheck is using them to
545   // highlight text.
546   llvm::sys::Process::UseANSIEscapeCodes(true);
547 
548   InitLLVM X(argc, argv);
549   cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
550                               "FILECHECK_OPTS");
551   DumpInputValue DumpInput =
552       DumpInputs.empty()
553           ? DumpInputDefault
554           : *std::max_element(DumpInputs.begin(), DumpInputs.end());
555   if (DumpInput == DumpInputHelp) {
556     DumpInputAnnotationHelp(outs());
557     return 0;
558   }
559   if (CheckFilename.empty()) {
560     errs() << "<check-file> not specified\n";
561     return 2;
562   }
563 
564   FileCheckRequest Req;
565   for (StringRef Prefix : CheckPrefixes)
566     Req.CheckPrefixes.push_back(Prefix);
567 
568   for (StringRef CheckNot : ImplicitCheckNot)
569     Req.ImplicitCheckNot.push_back(CheckNot);
570 
571   bool GlobalDefineError = false;
572   for (StringRef G : GlobalDefines) {
573     size_t EqIdx = G.find('=');
574     if (EqIdx == std::string::npos) {
575       errs() << "Missing equal sign in command-line definition '-D" << G
576              << "'\n";
577       GlobalDefineError = true;
578       continue;
579     }
580     if (EqIdx == 0) {
581       errs() << "Missing variable name in command-line definition '-D" << G
582              << "'\n";
583       GlobalDefineError = true;
584       continue;
585     }
586     Req.GlobalDefines.push_back(G);
587   }
588   if (GlobalDefineError)
589     return 2;
590 
591   Req.AllowEmptyInput = AllowEmptyInput;
592   Req.EnableVarScope = EnableVarScope;
593   Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
594   Req.Verbose = Verbose;
595   Req.VerboseVerbose = VerboseVerbose;
596   Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
597   Req.MatchFullLines = MatchFullLines;
598   Req.IgnoreCase = IgnoreCase;
599 
600   if (VerboseVerbose)
601     Req.Verbose = true;
602 
603   FileCheck FC(Req);
604   if (!FC.ValidateCheckPrefixes())
605     return 2;
606 
607   Regex PrefixRE = FC.buildCheckPrefixRegex();
608   std::string REError;
609   if (!PrefixRE.isValid(REError)) {
610     errs() << "Unable to combine check-prefix strings into a prefix regular "
611               "expression! This is likely a bug in FileCheck's verification of "
612               "the check-prefix strings. Regular expression parsing failed "
613               "with the following error: "
614            << REError << "\n";
615     return 2;
616   }
617 
618   SourceMgr SM;
619 
620   // Read the expected strings from the check file.
621   ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
622       MemoryBuffer::getFileOrSTDIN(CheckFilename);
623   if (std::error_code EC = CheckFileOrErr.getError()) {
624     errs() << "Could not open check file '" << CheckFilename
625            << "': " << EC.message() << '\n';
626     return 2;
627   }
628   MemoryBuffer &CheckFile = *CheckFileOrErr.get();
629 
630   SmallString<4096> CheckFileBuffer;
631   StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
632 
633   unsigned CheckFileBufferID =
634       SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
635                                 CheckFileText, CheckFile.getBufferIdentifier()),
636                             SMLoc());
637 
638   std::pair<unsigned, unsigned> ImpPatBufferIDRange;
639   if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange))
640     return 2;
641 
642   // Open the file to check and add it to SourceMgr.
643   ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
644       MemoryBuffer::getFileOrSTDIN(InputFilename);
645   if (InputFilename == "-")
646     InputFilename = "<stdin>"; // Overwrite for improved diagnostic messages
647   if (std::error_code EC = InputFileOrErr.getError()) {
648     errs() << "Could not open input file '" << InputFilename
649            << "': " << EC.message() << '\n';
650     return 2;
651   }
652   MemoryBuffer &InputFile = *InputFileOrErr.get();
653 
654   if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
655     errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
656     DumpCommandLine(argc, argv);
657     return 2;
658   }
659 
660   SmallString<4096> InputFileBuffer;
661   StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
662 
663   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
664                             InputFileText, InputFile.getBufferIdentifier()),
665                         SMLoc());
666 
667   if (DumpInput == DumpInputDefault)
668     DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
669 
670   std::vector<FileCheckDiag> Diags;
671   int ExitCode = FC.checkInput(SM, InputFileText,
672                                DumpInput == DumpInputNever ? nullptr : &Diags)
673                      ? EXIT_SUCCESS
674                      : 1;
675   if (DumpInput == DumpInputAlways ||
676       (ExitCode == 1 && DumpInput == DumpInputFail)) {
677     errs() << "\n"
678            << "Input file: "
679            << InputFilename
680            << "\n"
681            << "Check file: " << CheckFilename << "\n"
682            << "\n"
683            << "-dump-input=help describes the format of the following dump.\n"
684            << "\n";
685     std::vector<InputAnnotation> Annotations;
686     unsigned LabelWidth;
687     BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags,
688                           Annotations, LabelWidth);
689     DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
690   }
691 
692   return ExitCode;
693 }
694