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