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), cl::ZeroOrMore,
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), cl::ZeroOrMore,
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   DumpInputNever,
114   DumpInputFail,
115   DumpInputAlways,
116   DumpInputHelp
117 };
118 
119 static cl::list<DumpInputValue> DumpInputs(
120     "dump-input",
121     cl::desc("Dump input to stderr, adding annotations representing\n"
122              "currently enabled diagnostics.  When there are multiple\n"
123              "occurrences of this option, the <value> that appears earliest\n"
124              "in the list below has precedence.\n"),
125     cl::value_desc("mode"),
126     cl::values(clEnumValN(DumpInputHelp, "help",
127                           "Explain dump format and quit"),
128                clEnumValN(DumpInputAlways, "always", "Always dump input"),
129                clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
130                clEnumValN(DumpInputNever, "never", "Never dump input")));
131 
132 typedef cl::list<std::string>::const_iterator prefix_iterator;
133 
134 
135 
136 
137 
138 
139 
140 static void DumpCommandLine(int argc, char **argv) {
141   errs() << "FileCheck command line: ";
142   for (int I = 0; I < argc; I++)
143     errs() << " " << argv[I];
144   errs() << "\n";
145 }
146 
147 struct MarkerStyle {
148   /// The starting char (before tildes) for marking the line.
149   char Lead;
150   /// What color to use for this annotation.
151   raw_ostream::Colors Color;
152   /// A note to follow the marker, or empty string if none.
153   std::string Note;
154   MarkerStyle() {}
155   MarkerStyle(char Lead, raw_ostream::Colors Color,
156               const std::string &Note = "")
157       : Lead(Lead), Color(Color), Note(Note) {}
158 };
159 
160 static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
161   switch (MatchTy) {
162   case FileCheckDiag::MatchFoundAndExpected:
163     return MarkerStyle('^', raw_ostream::GREEN);
164   case FileCheckDiag::MatchFoundButExcluded:
165     return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
166   case FileCheckDiag::MatchFoundButWrongLine:
167     return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
168   case FileCheckDiag::MatchFoundButDiscarded:
169     return MarkerStyle('!', raw_ostream::CYAN,
170                        "discard: overlaps earlier match");
171   case FileCheckDiag::MatchNoneAndExcluded:
172     return MarkerStyle('X', raw_ostream::GREEN);
173   case FileCheckDiag::MatchNoneButExpected:
174     return MarkerStyle('X', raw_ostream::RED, "error: no match found");
175   case FileCheckDiag::MatchFuzzy:
176     return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
177   }
178   llvm_unreachable_internal("unexpected match type");
179 }
180 
181 static void DumpInputAnnotationHelp(raw_ostream &OS) {
182   OS << "The following description was requested by -dump-input=help to\n"
183      << "explain the input annotations printed by -dump-input=always and\n"
184      << "-dump-input=fail:\n\n";
185 
186   // Labels for input lines.
187   OS << "  - ";
188   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
189   OS << "     labels line number L of the input file\n";
190 
191   // Labels for annotation lines.
192   OS << "  - ";
193   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
194   OS << "    labels the only match result for either (1) a pattern of type T"
195      << " from\n"
196      << "           line L of the check file if L is an integer or (2) the"
197      << " I-th implicit\n"
198      << "           pattern if L is \"imp\" followed by an integer "
199      << "I (index origin one)\n";
200   OS << "  - ";
201   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
202   OS << "  labels the Nth match result for such a pattern\n";
203 
204   // Markers on annotation lines.
205   OS << "  - ";
206   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
207   OS << "    marks good match (reported if -v)\n"
208      << "  - ";
209   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
210   OS << "    marks bad match, such as:\n"
211      << "           - CHECK-NEXT on same line as previous match (error)\n"
212      << "           - CHECK-NOT found (error)\n"
213      << "           - CHECK-DAG overlapping match (discarded, reported if "
214      << "-vv)\n"
215      << "  - ";
216   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
217   OS << "    marks search range when no match is found, such as:\n"
218      << "           - CHECK-NEXT not found (error)\n"
219      << "           - CHECK-NOT not found (success, reported if -vv)\n"
220      << "           - CHECK-DAG not found after discarded matches (error)\n"
221      << "  - ";
222   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
223   OS << "      marks fuzzy match when no match is found\n";
224 
225   // Colors.
226   OS << "  - colors ";
227   WithColor(OS, raw_ostream::GREEN, true) << "success";
228   OS << ", ";
229   WithColor(OS, raw_ostream::RED, true) << "error";
230   OS << ", ";
231   WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
232   OS << ", ";
233   WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
234   OS << ", ";
235   WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
236   OS << "\n\n"
237      << "If you are not seeing color above or in input dumps, try: -color\n";
238 }
239 
240 /// An annotation for a single input line.
241 struct InputAnnotation {
242   /// The index of the match result across all checks
243   unsigned DiagIndex;
244   /// The label for this annotation.
245   std::string Label;
246   /// What input line (one-origin indexing) this annotation marks.  This might
247   /// be different from the starting line of the original diagnostic if this is
248   /// a non-initial fragment of a diagnostic that has been broken across
249   /// multiple lines.
250   unsigned InputLine;
251   /// The column range (one-origin indexing, open end) in which to mark the
252   /// input line.  If InputEndCol is UINT_MAX, treat it as the last column
253   /// before the newline.
254   unsigned InputStartCol, InputEndCol;
255   /// The marker to use.
256   MarkerStyle Marker;
257   /// Whether this annotation represents a good match for an expected pattern.
258   bool FoundAndExpectedMatch;
259 };
260 
261 /// Get an abbreviation for the check type.
262 std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
263   switch (Ty) {
264   case Check::CheckPlain:
265     if (Ty.getCount() > 1)
266       return "count";
267     return "check";
268   case Check::CheckNext:
269     return "next";
270   case Check::CheckSame:
271     return "same";
272   case Check::CheckNot:
273     return "not";
274   case Check::CheckDAG:
275     return "dag";
276   case Check::CheckLabel:
277     return "label";
278   case Check::CheckEmpty:
279     return "empty";
280   case Check::CheckComment:
281     return "com";
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           ? DumpInputFail
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 Prefix : CommentPrefixes)
569     Req.CommentPrefixes.push_back(Prefix);
570 
571   for (StringRef CheckNot : ImplicitCheckNot)
572     Req.ImplicitCheckNot.push_back(CheckNot);
573 
574   bool GlobalDefineError = false;
575   for (StringRef G : GlobalDefines) {
576     size_t EqIdx = G.find('=');
577     if (EqIdx == std::string::npos) {
578       errs() << "Missing equal sign in command-line definition '-D" << G
579              << "'\n";
580       GlobalDefineError = true;
581       continue;
582     }
583     if (EqIdx == 0) {
584       errs() << "Missing variable name in command-line definition '-D" << G
585              << "'\n";
586       GlobalDefineError = true;
587       continue;
588     }
589     Req.GlobalDefines.push_back(G);
590   }
591   if (GlobalDefineError)
592     return 2;
593 
594   Req.AllowEmptyInput = AllowEmptyInput;
595   Req.EnableVarScope = EnableVarScope;
596   Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
597   Req.Verbose = Verbose;
598   Req.VerboseVerbose = VerboseVerbose;
599   Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
600   Req.MatchFullLines = MatchFullLines;
601   Req.IgnoreCase = IgnoreCase;
602 
603   if (VerboseVerbose)
604     Req.Verbose = true;
605 
606   FileCheck FC(Req);
607   if (!FC.ValidateCheckPrefixes())
608     return 2;
609 
610   Regex PrefixRE = FC.buildCheckPrefixRegex();
611   std::string REError;
612   if (!PrefixRE.isValid(REError)) {
613     errs() << "Unable to combine check-prefix strings into a prefix regular "
614               "expression! This is likely a bug in FileCheck's verification of "
615               "the check-prefix strings. Regular expression parsing failed "
616               "with the following error: "
617            << REError << "\n";
618     return 2;
619   }
620 
621   SourceMgr SM;
622 
623   // Read the expected strings from the check file.
624   ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
625       MemoryBuffer::getFileOrSTDIN(CheckFilename);
626   if (std::error_code EC = CheckFileOrErr.getError()) {
627     errs() << "Could not open check file '" << CheckFilename
628            << "': " << EC.message() << '\n';
629     return 2;
630   }
631   MemoryBuffer &CheckFile = *CheckFileOrErr.get();
632 
633   SmallString<4096> CheckFileBuffer;
634   StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
635 
636   unsigned CheckFileBufferID =
637       SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
638                                 CheckFileText, CheckFile.getBufferIdentifier()),
639                             SMLoc());
640 
641   std::pair<unsigned, unsigned> ImpPatBufferIDRange;
642   if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange))
643     return 2;
644 
645   // Open the file to check and add it to SourceMgr.
646   ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
647       MemoryBuffer::getFileOrSTDIN(InputFilename);
648   if (InputFilename == "-")
649     InputFilename = "<stdin>"; // Overwrite for improved diagnostic messages
650   if (std::error_code EC = InputFileOrErr.getError()) {
651     errs() << "Could not open input file '" << InputFilename
652            << "': " << EC.message() << '\n';
653     return 2;
654   }
655   MemoryBuffer &InputFile = *InputFileOrErr.get();
656 
657   if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
658     errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
659     DumpCommandLine(argc, argv);
660     return 2;
661   }
662 
663   SmallString<4096> InputFileBuffer;
664   StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
665 
666   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
667                             InputFileText, InputFile.getBufferIdentifier()),
668                         SMLoc());
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