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