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