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