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