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