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