1 //===- FileCheck.cpp - Check that File's Contents match what is expected --===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // FileCheck does a line-by line check of a file that validates whether it
11 // contains the expected content.  This is useful for regression tests etc.
12 //
13 // This program exits with an exit status of 2 on error, exit status of 0 if
14 // the file matched the expected contents, and exit status of 1 if it did not
15 // contain the expected contents.
16 //
17 //===----------------------------------------------------------------------===//
18 
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Support/InitLLVM.h"
21 #include "llvm/Support/Process.h"
22 #include "llvm/Support/WithColor.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include "llvm/Support/FileCheck.h"
25 using namespace llvm;
26 
27 static cl::opt<std::string>
28     CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
29 
30 static cl::opt<std::string>
31     InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
32                   cl::init("-"), cl::value_desc("filename"));
33 
34 static cl::list<std::string> CheckPrefixes(
35     "check-prefix",
36     cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
37 static cl::alias CheckPrefixesAlias(
38     "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
39     cl::NotHidden,
40     cl::desc(
41         "Alias for -check-prefix permitting multiple comma separated values"));
42 
43 static cl::opt<bool> NoCanonicalizeWhiteSpace(
44     "strict-whitespace",
45     cl::desc("Do not treat all horizontal whitespace as equivalent"));
46 
47 static cl::list<std::string> ImplicitCheckNot(
48     "implicit-check-not",
49     cl::desc("Add an implicit negative check with this pattern to every\n"
50              "positive check. This can be used to ensure that no instances of\n"
51              "this pattern occur which are not matched by a positive pattern"),
52     cl::value_desc("pattern"));
53 
54 static cl::list<std::string> GlobalDefines("D", cl::Prefix,
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::MatchFinalAndExpected:
148     return MarkerStyle('^', raw_ostream::GREEN);
149   case FileCheckDiag::MatchFinalButExcluded:
150     return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
151   case FileCheckDiag::MatchFinalButWrongLine:
152     return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
153   case FileCheckDiag::MatchNoneButExpected:
154     return MarkerStyle('X', raw_ostream::RED, "error: no match found");
155   case FileCheckDiag::MatchFuzzy:
156     return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
157   case FileCheckDiag::MatchTypeCount:
158     llvm_unreachable_internal("unexpected match type");
159   }
160   llvm_unreachable_internal("unexpected match type");
161 }
162 
163 static void DumpInputAnnotationHelp(raw_ostream &OS) {
164   OS << "The following description was requested by -dump-input=help to\n"
165      << "explain the input annotations printed by -dump-input=always and\n"
166      << "-dump-input=fail:\n\n";
167 
168   // Labels for input lines.
169   OS << "  - ";
170   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
171   OS << "     labels line number L of the input file\n";
172 
173   // Labels for annotation lines.
174   OS << "  - ";
175   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
176   OS << "    labels the only match result for a pattern of type T from "
177      << "line L of\n"
178      << "           the check file\n";
179   OS << "  - ";
180   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
181   OS << "  labels the Nth match result for a pattern of type T from line "
182      << "L of\n"
183      << "           the check file\n";
184 
185   // Markers on annotation lines.
186   OS << "  - ";
187   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
188   OS << "    marks good match (reported if -v)\n"
189      << "  - ";
190   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
191   OS << "    marks bad match, such as:\n"
192      << "           - CHECK-NEXT on same line as previous match (error)\n"
193      << "           - CHECK-NOT found (error)\n"
194      << "  - ";
195   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
196   OS << "    marks search range when no match is found, such as:\n"
197      << "           - CHECK-NEXT not found (error)\n"
198      << "  - ";
199   WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
200   OS << "      marks fuzzy match when no match is found\n";
201 
202   // Colors.
203   OS << "  - colors ";
204   WithColor(OS, raw_ostream::GREEN, true) << "success";
205   OS << ", ";
206   WithColor(OS, raw_ostream::RED, true) << "error";
207   OS << ", ";
208   WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
209   OS << ", ";
210   WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
211   OS << "\n\n"
212      << "If you are not seeing color above or in input dumps, try: -color\n";
213 }
214 
215 /// An annotation for a single input line.
216 struct InputAnnotation {
217   /// The check file line (one-origin indexing) where the directive that
218   /// produced this annotation is located.
219   unsigned CheckLine;
220   /// The index of the match result for this check.
221   unsigned CheckDiagIndex;
222   /// The label for this annotation.
223   std::string Label;
224   /// What input line (one-origin indexing) this annotation marks.  This might
225   /// be different from the starting line of the original diagnostic if this is
226   /// a non-initial fragment of a diagnostic that has been broken across
227   /// multiple lines.
228   unsigned InputLine;
229   /// The column range (one-origin indexing, open end) in which to to mark the
230   /// input line.  If InputEndCol is UINT_MAX, treat it as the last column
231   /// before the newline.
232   unsigned InputStartCol, InputEndCol;
233   /// The marker to use.
234   MarkerStyle Marker;
235   /// Whether this annotation represents a final match for an expected pattern.
236   bool FinalAndExpectedMatch;
237 };
238 
239 /// Get an abbreviation for the check type.
240 std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
241   switch (Ty) {
242   case Check::CheckPlain:
243     if (Ty.getCount() > 1)
244       return "count";
245     return "check";
246   case Check::CheckNext:
247     return "next";
248   case Check::CheckSame:
249     return "same";
250   case Check::CheckNot:
251     return "not";
252   case Check::CheckDAG:
253     return "dag";
254   case Check::CheckLabel:
255     return "label";
256   case Check::CheckEmpty:
257     return "empty";
258   case Check::CheckEOF:
259     return "eof";
260   case Check::CheckBadNot:
261     return "bad-not";
262   case Check::CheckBadCount:
263     return "bad-count";
264   case Check::CheckNone:
265     llvm_unreachable("invalid FileCheckType");
266   }
267   llvm_unreachable("unknown FileCheckType");
268 }
269 
270 static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
271                                   std::vector<InputAnnotation> &Annotations,
272                                   unsigned &LabelWidth) {
273   // How many diagnostics has the current check seen so far?
274   unsigned CheckDiagCount = 0;
275   // What's the widest label?
276   LabelWidth = 0;
277   for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
278        ++DiagItr) {
279     InputAnnotation A;
280 
281     // Build label, which uniquely identifies this check result.
282     A.CheckLine = DiagItr->CheckLine;
283     llvm::raw_string_ostream Label(A.Label);
284     Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
285           << DiagItr->CheckLine;
286     A.CheckDiagIndex = UINT_MAX;
287     auto DiagNext = std::next(DiagItr);
288     if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
289         DiagItr->CheckLine == DiagNext->CheckLine)
290       A.CheckDiagIndex = CheckDiagCount++;
291     else if (CheckDiagCount) {
292       A.CheckDiagIndex = CheckDiagCount;
293       CheckDiagCount = 0;
294     }
295     if (A.CheckDiagIndex != UINT_MAX)
296       Label << "'" << A.CheckDiagIndex;
297     else
298       A.CheckDiagIndex = 0;
299     Label.flush();
300     LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
301 
302     MarkerStyle Marker = GetMarker(DiagItr->MatchTy);
303     A.Marker = Marker;
304     A.FinalAndExpectedMatch =
305         DiagItr->MatchTy == FileCheckDiag::MatchFinalAndExpected;
306 
307     // Compute the mark location, and break annotation into multiple
308     // annotations if it spans multiple lines.
309     A.InputLine = DiagItr->InputStartLine;
310     A.InputStartCol = DiagItr->InputStartCol;
311     if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
312       // Sometimes ranges are empty in order to indicate a specific point, but
313       // that would mean nothing would be marked, so adjust the range to
314       // include the following character.
315       A.InputEndCol =
316           std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
317       Annotations.push_back(A);
318     } else {
319       assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
320              "expected input range not to be inverted");
321       A.InputEndCol = UINT_MAX;
322       A.Marker.Note = "";
323       Annotations.push_back(A);
324       for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
325            L <= E; ++L) {
326         // If a range ends before the first column on a line, then it has no
327         // characters on that line, so there's nothing to render.
328         if (DiagItr->InputEndCol == 1 && L == E) {
329           Annotations.back().Marker.Note = Marker.Note;
330           break;
331         }
332         InputAnnotation B;
333         B.CheckLine = A.CheckLine;
334         B.CheckDiagIndex = A.CheckDiagIndex;
335         B.Label = A.Label;
336         B.InputLine = L;
337         B.Marker = Marker;
338         B.Marker.Lead = '~';
339         B.InputStartCol = 1;
340         if (L != E) {
341           B.InputEndCol = UINT_MAX;
342           B.Marker.Note = "";
343         } else
344           B.InputEndCol = DiagItr->InputEndCol;
345         B.FinalAndExpectedMatch = A.FinalAndExpectedMatch;
346         Annotations.push_back(B);
347       }
348     }
349   }
350 }
351 
352 static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
353                                StringRef InputFileText,
354                                std::vector<InputAnnotation> &Annotations,
355                                unsigned LabelWidth) {
356   OS << "Full input was:\n<<<<<<\n";
357 
358   // Sort annotations.
359   //
360   // First, sort in the order of input lines to make it easier to find relevant
361   // annotations while iterating input lines in the implementation below.
362   // FileCheck diagnostics are not always reported and recorded in the order of
363   // input lines due to, for example, CHECK-DAG and CHECK-NOT.
364   //
365   // Second, for annotations for the same input line, sort in the order of the
366   // FileCheck directive's line in the check file (where there's at most one
367   // directive per line) and then by the index of the match result for that
368   // directive.  The rationale of this choice is that, for any input line, this
369   // sort establishes a total order of annotations that, with respect to match
370   // results, is consistent across multiple lines, thus making match results
371   // easier to track from one line to the next when they span multiple lines.
372   std::sort(Annotations.begin(), Annotations.end(),
373             [](const InputAnnotation &A, const InputAnnotation &B) {
374               if (A.InputLine != B.InputLine)
375                 return A.InputLine < B.InputLine;
376               if (A.CheckLine != B.CheckLine)
377                 return A.CheckLine < B.CheckLine;
378               // FIXME: Sometimes CHECK-LABEL reports its match twice with
379               // other diagnostics in between, and then diag index incrementing
380               // fails to work properly, and then this assert fails.  We should
381               // suppress one of those diagnostics or do a better job of
382               // computing this index.  For now, we just produce a redundant
383               // CHECK-LABEL annotation.
384               // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
385               //        "expected diagnostic indices to be unique within a "
386               //        " check line");
387               return A.CheckDiagIndex < B.CheckDiagIndex;
388             });
389 
390   // Compute the width of the label column.
391   const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
392                       *InputFileEnd = InputFileText.bytes_end();
393   unsigned LineCount = InputFileText.count('\n');
394   if (InputFileEnd[-1] != '\n')
395     ++LineCount;
396   unsigned LineNoWidth = log10(LineCount) + 1;
397   // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
398   // on input lines and (2) to the right of the (left-aligned) labels on
399   // annotation lines so that input lines and annotation lines are more
400   // visually distinct.  For example, the spaces on the annotation lines ensure
401   // that input line numbers and check directive line numbers never align
402   // horizontally.  Those line numbers might not even be for the same file.
403   // One space would be enough to achieve that, but more makes it even easier
404   // to see.
405   LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
406 
407   // Print annotated input lines.
408   auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
409   for (unsigned Line = 1;
410        InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
411        ++Line) {
412     const unsigned char *InputFileLine = InputFilePtr;
413 
414     // Print right-aligned line number.
415     WithColor(OS, raw_ostream::BLACK, true)
416         << format_decimal(Line, LabelWidth) << ": ";
417 
418     // For case where -v and colors are enabled, find the annotations for final
419     // matches for expected patterns in order to highlight everything else in
420     // the line.  There are no such annotations if -v is disabled.
421     std::vector<InputAnnotation> FinalAndExpectedMatches;
422     if (Req.Verbose && WithColor(OS).colorsEnabled()) {
423       for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
424            ++I) {
425         if (I->FinalAndExpectedMatch)
426           FinalAndExpectedMatches.push_back(*I);
427       }
428     }
429 
430     // Print numbered line with highlighting where there are no matches for
431     // expected patterns.
432     bool Newline = false;
433     {
434       WithColor COS(OS);
435       bool InMatch = false;
436       if (Req.Verbose)
437         COS.changeColor(raw_ostream::CYAN, true, true);
438       for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
439         bool WasInMatch = InMatch;
440         InMatch = false;
441         for (auto M : FinalAndExpectedMatches) {
442           if (M.InputStartCol <= Col && Col < M.InputEndCol) {
443             InMatch = true;
444             break;
445           }
446         }
447         if (!WasInMatch && InMatch)
448           COS.resetColor();
449         else if (WasInMatch && !InMatch)
450           COS.changeColor(raw_ostream::CYAN, true, true);
451         if (*InputFilePtr == '\n')
452           Newline = true;
453         else
454           COS << *InputFilePtr;
455         ++InputFilePtr;
456       }
457     }
458     OS << '\n';
459     unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
460 
461     // Print any annotations.
462     while (AnnotationItr != AnnotationEnd &&
463            AnnotationItr->InputLine == Line) {
464       WithColor COS(OS, AnnotationItr->Marker.Color, true);
465       // The two spaces below are where the ": " appears on input lines.
466       COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";
467       unsigned Col;
468       for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
469         COS << ' ';
470       COS << AnnotationItr->Marker.Lead;
471       // If InputEndCol=UINT_MAX, stop at InputLineWidth.
472       for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
473            ++Col)
474         COS << '~';
475       const std::string &Note = AnnotationItr->Marker.Note;
476       if (!Note.empty()) {
477         // Put the note at the end of the input line.  If we were to instead
478         // put the note right after the marker, subsequent annotations for the
479         // same input line might appear to mark this note instead of the input
480         // line.
481         for (; Col <= InputLineWidth; ++Col)
482           COS << ' ';
483         COS << ' ' << Note;
484       }
485       COS << '\n';
486       ++AnnotationItr;
487     }
488   }
489 
490   OS << ">>>>>>\n";
491 }
492 
493 int main(int argc, char **argv) {
494   // Enable use of ANSI color codes because FileCheck is using them to
495   // highlight text.
496   llvm::sys::Process::UseANSIEscapeCodes(true);
497 
498   InitLLVM X(argc, argv);
499   cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
500                               "FILECHECK_OPTS");
501   if (DumpInput == DumpInputHelp) {
502     DumpInputAnnotationHelp(outs());
503     return 0;
504   }
505   if (CheckFilename.empty()) {
506     errs() << "<check-file> not specified\n";
507     return 2;
508   }
509 
510   FileCheckRequest Req;
511   for (auto Prefix : CheckPrefixes)
512     Req.CheckPrefixes.push_back(Prefix);
513 
514   for (auto CheckNot : ImplicitCheckNot)
515     Req.ImplicitCheckNot.push_back(CheckNot);
516 
517   for (auto G : GlobalDefines)
518     Req.GlobalDefines.push_back(G);
519 
520   Req.AllowEmptyInput = AllowEmptyInput;
521   Req.EnableVarScope = EnableVarScope;
522   Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
523   Req.Verbose = Verbose;
524   Req.VerboseVerbose = VerboseVerbose;
525   Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
526   Req.MatchFullLines = MatchFullLines;
527 
528   if (VerboseVerbose)
529     Req.Verbose = true;
530 
531   FileCheck FC(Req);
532   if (!FC.ValidateCheckPrefixes()) {
533     errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
534               "start with a letter and contain only alphanumeric characters, "
535               "hyphens and underscores\n";
536     return 2;
537   }
538 
539   Regex PrefixRE = FC.buildCheckPrefixRegex();
540   std::string REError;
541   if (!PrefixRE.isValid(REError)) {
542     errs() << "Unable to combine check-prefix strings into a prefix regular "
543               "expression! This is likely a bug in FileCheck's verification of "
544               "the check-prefix strings. Regular expression parsing failed "
545               "with the following error: "
546            << REError << "\n";
547     return 2;
548   }
549 
550   SourceMgr SM;
551 
552   // Read the expected strings from the check file.
553   ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
554       MemoryBuffer::getFileOrSTDIN(CheckFilename);
555   if (std::error_code EC = CheckFileOrErr.getError()) {
556     errs() << "Could not open check file '" << CheckFilename
557            << "': " << EC.message() << '\n';
558     return 2;
559   }
560   MemoryBuffer &CheckFile = *CheckFileOrErr.get();
561 
562   SmallString<4096> CheckFileBuffer;
563   StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
564 
565   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
566                             CheckFileText, CheckFile.getBufferIdentifier()),
567                         SMLoc());
568 
569   std::vector<FileCheckString> CheckStrings;
570   if (FC.ReadCheckFile(SM, CheckFileText, PrefixRE, CheckStrings))
571     return 2;
572 
573   // Open the file to check and add it to SourceMgr.
574   ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
575       MemoryBuffer::getFileOrSTDIN(InputFilename);
576   if (std::error_code EC = InputFileOrErr.getError()) {
577     errs() << "Could not open input file '" << InputFilename
578            << "': " << EC.message() << '\n';
579     return 2;
580   }
581   MemoryBuffer &InputFile = *InputFileOrErr.get();
582 
583   if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
584     errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
585     DumpCommandLine(argc, argv);
586     return 2;
587   }
588 
589   SmallString<4096> InputFileBuffer;
590   StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
591 
592   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
593                             InputFileText, InputFile.getBufferIdentifier()),
594                         SMLoc());
595 
596   if (DumpInput == DumpInputDefault)
597     DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
598 
599   std::vector<FileCheckDiag> Diags;
600   int ExitCode = FC.CheckInput(SM, InputFileText, CheckStrings,
601                                DumpInput == DumpInputNever ? nullptr : &Diags)
602                      ? EXIT_SUCCESS
603                      : 1;
604   if (DumpInput == DumpInputAlways ||
605       (ExitCode == 1 && DumpInput == DumpInputFail)) {
606     errs() << "\n"
607            << "Input file: "
608            << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())
609            << "\n"
610            << "Check file: " << CheckFilename << "\n"
611            << "\n"
612            << "-dump-input=help describes the format of the following dump.\n"
613            << "\n";
614     std::vector<InputAnnotation> Annotations;
615     unsigned LabelWidth;
616     BuildInputAnnotations(Diags, Annotations, LabelWidth);
617     DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
618   }
619 
620   return ExitCode;
621 }
622