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