xref: /openbsd-src/gnu/llvm/llvm/utils/FileCheck/FileCheck.cpp (revision b99ef4df7fac99f3475b694d6cd4990521c99ae6)
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 a pattern of type T from "
197      << "line L of\n"
198      << "           the check file\n";
199   OS << "  - ";
200   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
201   OS << "  labels the Nth match result for a pattern of type T from line "
202      << "L of\n"
203      << "           the check file\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 check file line (one-origin indexing) where the directive that
244   /// produced this annotation is located.
245   unsigned CheckLine;
246   /// The index of the match result for this check.
247   unsigned CheckDiagIndex;
248   /// The label for this annotation.
249   std::string Label;
250   /// What input line (one-origin indexing) this annotation marks.  This might
251   /// be different from the starting line of the original diagnostic if this is
252   /// a non-initial fragment of a diagnostic that has been broken across
253   /// multiple lines.
254   unsigned InputLine;
255   /// The column range (one-origin indexing, open end) in which to to mark the
256   /// input line.  If InputEndCol is UINT_MAX, treat it as the last column
257   /// before the newline.
258   unsigned InputStartCol, InputEndCol;
259   /// The marker to use.
260   MarkerStyle Marker;
261   /// Whether this annotation represents a good match for an expected pattern.
262   bool FoundAndExpectedMatch;
263 };
264 
265 /// Get an abbreviation for the check type.
266 std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
267   switch (Ty) {
268   case Check::CheckPlain:
269     if (Ty.getCount() > 1)
270       return "count";
271     return "check";
272   case Check::CheckNext:
273     return "next";
274   case Check::CheckSame:
275     return "same";
276   case Check::CheckNot:
277     return "not";
278   case Check::CheckDAG:
279     return "dag";
280   case Check::CheckLabel:
281     return "label";
282   case Check::CheckEmpty:
283     return "empty";
284   case Check::CheckEOF:
285     return "eof";
286   case Check::CheckBadNot:
287     return "bad-not";
288   case Check::CheckBadCount:
289     return "bad-count";
290   case Check::CheckNone:
291     llvm_unreachable("invalid FileCheckType");
292   }
293   llvm_unreachable("unknown FileCheckType");
294 }
295 
296 static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
297                                   std::vector<InputAnnotation> &Annotations,
298                                   unsigned &LabelWidth) {
299   // How many diagnostics has the current check seen so far?
300   unsigned CheckDiagCount = 0;
301   // What's the widest label?
302   LabelWidth = 0;
303   for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
304        ++DiagItr) {
305     InputAnnotation A;
306 
307     // Build label, which uniquely identifies this check result.
308     A.CheckLine = DiagItr->CheckLine;
309     llvm::raw_string_ostream Label(A.Label);
310     Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
311           << DiagItr->CheckLine;
312     A.CheckDiagIndex = UINT_MAX;
313     auto DiagNext = std::next(DiagItr);
314     if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
315         DiagItr->CheckLine == DiagNext->CheckLine)
316       A.CheckDiagIndex = CheckDiagCount++;
317     else if (CheckDiagCount) {
318       A.CheckDiagIndex = CheckDiagCount;
319       CheckDiagCount = 0;
320     }
321     if (A.CheckDiagIndex != UINT_MAX)
322       Label << "'" << A.CheckDiagIndex;
323     else
324       A.CheckDiagIndex = 0;
325     Label.flush();
326     LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
327 
328     A.Marker = GetMarker(DiagItr->MatchTy);
329     A.FoundAndExpectedMatch =
330         DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
331 
332     // Compute the mark location, and break annotation into multiple
333     // annotations if it spans multiple lines.
334     A.InputLine = DiagItr->InputStartLine;
335     A.InputStartCol = DiagItr->InputStartCol;
336     if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
337       // Sometimes ranges are empty in order to indicate a specific point, but
338       // that would mean nothing would be marked, so adjust the range to
339       // include the following character.
340       A.InputEndCol =
341           std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
342       Annotations.push_back(A);
343     } else {
344       assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
345              "expected input range not to be inverted");
346       A.InputEndCol = UINT_MAX;
347       Annotations.push_back(A);
348       for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
349            L <= E; ++L) {
350         // If a range ends before the first column on a line, then it has no
351         // characters on that line, so there's nothing to render.
352         if (DiagItr->InputEndCol == 1 && L == E)
353           break;
354         InputAnnotation B;
355         B.CheckLine = A.CheckLine;
356         B.CheckDiagIndex = A.CheckDiagIndex;
357         B.Label = A.Label;
358         B.InputLine = L;
359         B.Marker = A.Marker;
360         B.Marker.Lead = '~';
361         B.Marker.Note = "";
362         B.InputStartCol = 1;
363         if (L != E)
364           B.InputEndCol = UINT_MAX;
365         else
366           B.InputEndCol = DiagItr->InputEndCol;
367         B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
368         Annotations.push_back(B);
369       }
370     }
371   }
372 }
373 
374 static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
375                                StringRef InputFileText,
376                                std::vector<InputAnnotation> &Annotations,
377                                unsigned LabelWidth) {
378   OS << "Full input was:\n<<<<<<\n";
379 
380   // Sort annotations.
381   //
382   // First, sort in the order of input lines to make it easier to find relevant
383   // annotations while iterating input lines in the implementation below.
384   // FileCheck diagnostics are not always reported and recorded in the order of
385   // input lines due to, for example, CHECK-DAG and CHECK-NOT.
386   //
387   // Second, for annotations for the same input line, sort in the order of the
388   // FileCheck directive's line in the check file (where there's at most one
389   // directive per line) and then by the index of the match result for that
390   // directive.  The rationale of this choice is that, for any input line, this
391   // sort establishes a total order of annotations that, with respect to match
392   // results, is consistent across multiple lines, thus making match results
393   // easier to track from one line to the next when they span multiple lines.
394   std::sort(Annotations.begin(), Annotations.end(),
395             [](const InputAnnotation &A, const InputAnnotation &B) {
396               if (A.InputLine != B.InputLine)
397                 return A.InputLine < B.InputLine;
398               if (A.CheckLine != B.CheckLine)
399                 return A.CheckLine < B.CheckLine;
400               // FIXME: Sometimes CHECK-LABEL reports its match twice with
401               // other diagnostics in between, and then diag index incrementing
402               // fails to work properly, and then this assert fails.  We should
403               // suppress one of those diagnostics or do a better job of
404               // computing this index.  For now, we just produce a redundant
405               // CHECK-LABEL annotation.
406               // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
407               //        "expected diagnostic indices to be unique within a "
408               //        " check line");
409               return A.CheckDiagIndex < B.CheckDiagIndex;
410             });
411 
412   // Compute the width of the label column.
413   const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
414                       *InputFileEnd = InputFileText.bytes_end();
415   unsigned LineCount = InputFileText.count('\n');
416   if (InputFileEnd[-1] != '\n')
417     ++LineCount;
418   unsigned LineNoWidth = std::log10(LineCount) + 1;
419   // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
420   // on input lines and (2) to the right of the (left-aligned) labels on
421   // annotation lines so that input lines and annotation lines are more
422   // visually distinct.  For example, the spaces on the annotation lines ensure
423   // that input line numbers and check directive line numbers never align
424   // horizontally.  Those line numbers might not even be for the same file.
425   // One space would be enough to achieve that, but more makes it even easier
426   // to see.
427   LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
428 
429   // Print annotated input lines.
430   auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
431   for (unsigned Line = 1;
432        InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
433        ++Line) {
434     const unsigned char *InputFileLine = InputFilePtr;
435 
436     // Print right-aligned line number.
437     WithColor(OS, raw_ostream::BLACK, true)
438         << format_decimal(Line, LabelWidth) << ": ";
439 
440     // For the case where -v and colors are enabled, find the annotations for
441     // good matches for expected patterns in order to highlight everything
442     // else in the line.  There are no such annotations if -v is disabled.
443     std::vector<InputAnnotation> FoundAndExpectedMatches;
444     if (Req.Verbose && WithColor(OS).colorsEnabled()) {
445       for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
446            ++I) {
447         if (I->FoundAndExpectedMatch)
448           FoundAndExpectedMatches.push_back(*I);
449       }
450     }
451 
452     // Print numbered line with highlighting where there are no matches for
453     // expected patterns.
454     bool Newline = false;
455     {
456       WithColor COS(OS);
457       bool InMatch = false;
458       if (Req.Verbose)
459         COS.changeColor(raw_ostream::CYAN, true, true);
460       for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
461         bool WasInMatch = InMatch;
462         InMatch = false;
463         for (auto M : FoundAndExpectedMatches) {
464           if (M.InputStartCol <= Col && Col < M.InputEndCol) {
465             InMatch = true;
466             break;
467           }
468         }
469         if (!WasInMatch && InMatch)
470           COS.resetColor();
471         else if (WasInMatch && !InMatch)
472           COS.changeColor(raw_ostream::CYAN, true, true);
473         if (*InputFilePtr == '\n')
474           Newline = true;
475         else
476           COS << *InputFilePtr;
477         ++InputFilePtr;
478       }
479     }
480     OS << '\n';
481     unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
482 
483     // Print any annotations.
484     while (AnnotationItr != AnnotationEnd &&
485            AnnotationItr->InputLine == Line) {
486       WithColor COS(OS, AnnotationItr->Marker.Color, true);
487       // The two spaces below are where the ": " appears on input lines.
488       COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";
489       unsigned Col;
490       for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
491         COS << ' ';
492       COS << AnnotationItr->Marker.Lead;
493       // If InputEndCol=UINT_MAX, stop at InputLineWidth.
494       for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
495            ++Col)
496         COS << '~';
497       const std::string &Note = AnnotationItr->Marker.Note;
498       if (!Note.empty()) {
499         // Put the note at the end of the input line.  If we were to instead
500         // put the note right after the marker, subsequent annotations for the
501         // same input line might appear to mark this note instead of the input
502         // line.
503         for (; Col <= InputLineWidth; ++Col)
504           COS << ' ';
505         COS << ' ' << Note;
506       }
507       COS << '\n';
508       ++AnnotationItr;
509     }
510   }
511 
512   OS << ">>>>>>\n";
513 }
514 
515 int main(int argc, char **argv) {
516   // Enable use of ANSI color codes because FileCheck is using them to
517   // highlight text.
518   llvm::sys::Process::UseANSIEscapeCodes(true);
519 
520   InitLLVM X(argc, argv);
521   cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
522                               "FILECHECK_OPTS");
523   DumpInputValue DumpInput =
524       DumpInputs.empty()
525           ? DumpInputDefault
526           : *std::max_element(DumpInputs.begin(), DumpInputs.end());
527   if (DumpInput == DumpInputHelp) {
528     DumpInputAnnotationHelp(outs());
529     return 0;
530   }
531   if (CheckFilename.empty()) {
532     errs() << "<check-file> not specified\n";
533     return 2;
534   }
535 
536   FileCheckRequest Req;
537   for (auto Prefix : CheckPrefixes)
538     Req.CheckPrefixes.push_back(Prefix);
539 
540   for (auto CheckNot : ImplicitCheckNot)
541     Req.ImplicitCheckNot.push_back(CheckNot);
542 
543   bool GlobalDefineError = false;
544   for (auto G : GlobalDefines) {
545     size_t EqIdx = G.find('=');
546     if (EqIdx == std::string::npos) {
547       errs() << "Missing equal sign in command-line definition '-D" << G
548              << "'\n";
549       GlobalDefineError = true;
550       continue;
551     }
552     if (EqIdx == 0) {
553       errs() << "Missing variable name in command-line definition '-D" << G
554              << "'\n";
555       GlobalDefineError = true;
556       continue;
557     }
558     Req.GlobalDefines.push_back(G);
559   }
560   if (GlobalDefineError)
561     return 2;
562 
563   Req.AllowEmptyInput = AllowEmptyInput;
564   Req.EnableVarScope = EnableVarScope;
565   Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
566   Req.Verbose = Verbose;
567   Req.VerboseVerbose = VerboseVerbose;
568   Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
569   Req.MatchFullLines = MatchFullLines;
570   Req.IgnoreCase = IgnoreCase;
571 
572   if (VerboseVerbose)
573     Req.Verbose = true;
574 
575   FileCheck FC(Req);
576   if (!FC.ValidateCheckPrefixes()) {
577     errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
578               "start with a letter and contain only alphanumeric characters, "
579               "hyphens and underscores\n";
580     return 2;
581   }
582 
583   Regex PrefixRE = FC.buildCheckPrefixRegex();
584   std::string REError;
585   if (!PrefixRE.isValid(REError)) {
586     errs() << "Unable to combine check-prefix strings into a prefix regular "
587               "expression! This is likely a bug in FileCheck's verification of "
588               "the check-prefix strings. Regular expression parsing failed "
589               "with the following error: "
590            << REError << "\n";
591     return 2;
592   }
593 
594   SourceMgr SM;
595 
596   // Read the expected strings from the check file.
597   ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
598       MemoryBuffer::getFileOrSTDIN(CheckFilename);
599   if (std::error_code EC = CheckFileOrErr.getError()) {
600     errs() << "Could not open check file '" << CheckFilename
601            << "': " << EC.message() << '\n';
602     return 2;
603   }
604   MemoryBuffer &CheckFile = *CheckFileOrErr.get();
605 
606   SmallString<4096> CheckFileBuffer;
607   StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
608 
609   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
610                             CheckFileText, CheckFile.getBufferIdentifier()),
611                         SMLoc());
612 
613   if (FC.readCheckFile(SM, CheckFileText, PrefixRE))
614     return 2;
615 
616   // Open the file to check and add it to SourceMgr.
617   ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
618       MemoryBuffer::getFileOrSTDIN(InputFilename);
619   if (std::error_code EC = InputFileOrErr.getError()) {
620     errs() << "Could not open input file '" << InputFilename
621            << "': " << EC.message() << '\n';
622     return 2;
623   }
624   MemoryBuffer &InputFile = *InputFileOrErr.get();
625 
626   if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
627     errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
628     DumpCommandLine(argc, argv);
629     return 2;
630   }
631 
632   SmallString<4096> InputFileBuffer;
633   StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
634 
635   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
636                             InputFileText, InputFile.getBufferIdentifier()),
637                         SMLoc());
638 
639   if (DumpInput == DumpInputDefault)
640     DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
641 
642   std::vector<FileCheckDiag> Diags;
643   int ExitCode = FC.checkInput(SM, InputFileText,
644                                DumpInput == DumpInputNever ? nullptr : &Diags)
645                      ? EXIT_SUCCESS
646                      : 1;
647   if (DumpInput == DumpInputAlways ||
648       (ExitCode == 1 && DumpInput == DumpInputFail)) {
649     errs() << "\n"
650            << "Input file: "
651            << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())
652            << "\n"
653            << "Check file: " << CheckFilename << "\n"
654            << "\n"
655            << "-dump-input=help describes the format of the following dump.\n"
656            << "\n";
657     std::vector<InputAnnotation> Annotations;
658     unsigned LabelWidth;
659     BuildInputAnnotations(Diags, Annotations, LabelWidth);
660     DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
661   }
662 
663   return ExitCode;
664 }
665