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