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 #include <cmath> 25 using namespace llvm; 26 27 static cl::extrahelp FileCheckOptsEnv( 28 "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n" 29 "from the command line.\n"); 30 31 static cl::opt<std::string> 32 CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional); 33 34 static cl::opt<std::string> 35 InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), 36 cl::init("-"), cl::value_desc("filename")); 37 38 static cl::list<std::string> CheckPrefixes( 39 "check-prefix", 40 cl::desc("Prefix to use from check file (defaults to 'CHECK')")); 41 static cl::alias CheckPrefixesAlias( 42 "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated, 43 cl::NotHidden, 44 cl::desc( 45 "Alias for -check-prefix permitting multiple comma separated values")); 46 47 static cl::list<std::string> CommentPrefixes( 48 "comment-prefixes", cl::CommaSeparated, cl::Hidden, 49 cl::desc("Comma-separated list of comment prefixes to use from check file\n" 50 "(defaults to 'COM,RUN'). Please avoid using this feature in\n" 51 "LLVM's LIT-based test suites, which should be easier to\n" 52 "maintain if they all follow a consistent comment style. This\n" 53 "feature is meant for non-LIT test suites using FileCheck.")); 54 55 static cl::opt<bool> NoCanonicalizeWhiteSpace( 56 "strict-whitespace", 57 cl::desc("Do not treat all horizontal whitespace as equivalent")); 58 59 static cl::opt<bool> IgnoreCase( 60 "ignore-case", 61 cl::desc("Use case-insensitive matching")); 62 63 static cl::list<std::string> ImplicitCheckNot( 64 "implicit-check-not", 65 cl::desc("Add an implicit negative check with this pattern to every\n" 66 "positive check. This can be used to ensure that no instances of\n" 67 "this pattern occur which are not matched by a positive pattern"), 68 cl::value_desc("pattern")); 69 70 static cl::list<std::string> 71 GlobalDefines("D", cl::AlwaysPrefix, 72 cl::desc("Define a variable to be used in capture patterns."), 73 cl::value_desc("VAR=VALUE")); 74 75 static cl::opt<bool> AllowEmptyInput( 76 "allow-empty", cl::init(false), 77 cl::desc("Allow the input file to be empty. This is useful when making\n" 78 "checks that some error message does not occur, for example.")); 79 80 static cl::opt<bool> MatchFullLines( 81 "match-full-lines", cl::init(false), 82 cl::desc("Require all positive matches to cover an entire input line.\n" 83 "Allows leading and trailing whitespace if --strict-whitespace\n" 84 "is not also passed.")); 85 86 static cl::opt<bool> EnableVarScope( 87 "enable-var-scope", cl::init(false), 88 cl::desc("Enables scope for regex variables. Variables with names that\n" 89 "do not start with '$' will be reset at the beginning of\n" 90 "each CHECK-LABEL block.")); 91 92 static cl::opt<bool> AllowDeprecatedDagOverlap( 93 "allow-deprecated-dag-overlap", cl::init(false), 94 cl::desc("Enable overlapping among matches in a group of consecutive\n" 95 "CHECK-DAG directives. This option is deprecated and is only\n" 96 "provided for convenience as old tests are migrated to the new\n" 97 "non-overlapping CHECK-DAG implementation.\n")); 98 99 static cl::opt<bool> Verbose( 100 "v", cl::init(false), 101 cl::desc("Print directive pattern matches, or add them to the input dump\n" 102 "if enabled.\n")); 103 104 static cl::opt<bool> VerboseVerbose( 105 "vv", cl::init(false), 106 cl::desc("Print information helpful in diagnosing internal FileCheck\n" 107 "issues, or add it to the input dump if enabled. Implies\n" 108 "-v.\n")); 109 110 // The order of DumpInputValue members affects their precedence, as documented 111 // for -dump-input below. 112 enum DumpInputValue { 113 DumpInputDefault, 114 DumpInputNever, 115 DumpInputFail, 116 DumpInputAlways, 117 DumpInputHelp 118 }; 119 120 static cl::list<DumpInputValue> DumpInputs( 121 "dump-input", 122 cl::desc("Dump input to stderr, adding annotations representing\n" 123 "currently enabled diagnostics. When there are multiple\n" 124 "occurrences of this option, the <value> that appears earliest\n" 125 "in the list below has precedence.\n"), 126 cl::value_desc("mode"), 127 cl::values(clEnumValN(DumpInputHelp, "help", 128 "Explain dump format and quit"), 129 clEnumValN(DumpInputAlways, "always", "Always dump input"), 130 clEnumValN(DumpInputFail, "fail", "Dump input on failure"), 131 clEnumValN(DumpInputNever, "never", "Never dump input"))); 132 133 typedef cl::list<std::string>::const_iterator prefix_iterator; 134 135 136 137 138 139 140 141 static void DumpCommandLine(int argc, char **argv) { 142 errs() << "FileCheck command line: "; 143 for (int I = 0; I < argc; I++) 144 errs() << " " << argv[I]; 145 errs() << "\n"; 146 } 147 148 struct MarkerStyle { 149 /// The starting char (before tildes) for marking the line. 150 char Lead; 151 /// What color to use for this annotation. 152 raw_ostream::Colors Color; 153 /// A note to follow the marker, or empty string if none. 154 std::string Note; 155 MarkerStyle() {} 156 MarkerStyle(char Lead, raw_ostream::Colors Color, 157 const std::string &Note = "") 158 : Lead(Lead), Color(Color), Note(Note) {} 159 }; 160 161 static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) { 162 switch (MatchTy) { 163 case FileCheckDiag::MatchFoundAndExpected: 164 return MarkerStyle('^', raw_ostream::GREEN); 165 case FileCheckDiag::MatchFoundButExcluded: 166 return MarkerStyle('!', raw_ostream::RED, "error: no match expected"); 167 case FileCheckDiag::MatchFoundButWrongLine: 168 return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line"); 169 case FileCheckDiag::MatchFoundButDiscarded: 170 return MarkerStyle('!', raw_ostream::CYAN, 171 "discard: overlaps earlier match"); 172 case FileCheckDiag::MatchNoneAndExcluded: 173 return MarkerStyle('X', raw_ostream::GREEN); 174 case FileCheckDiag::MatchNoneButExpected: 175 return MarkerStyle('X', raw_ostream::RED, "error: no match found"); 176 case FileCheckDiag::MatchFuzzy: 177 return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match"); 178 } 179 llvm_unreachable_internal("unexpected match type"); 180 } 181 182 static void DumpInputAnnotationHelp(raw_ostream &OS) { 183 OS << "The following description was requested by -dump-input=help to\n" 184 << "explain the input annotations printed by -dump-input=always and\n" 185 << "-dump-input=fail:\n\n"; 186 187 // Labels for input lines. 188 OS << " - "; 189 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:"; 190 OS << " labels line number L of the input file\n"; 191 192 // Labels for annotation lines. 193 OS << " - "; 194 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L"; 195 OS << " labels the only match result for either (1) a pattern of type T" 196 << " from\n" 197 << " line L of the check file if L is an integer or (2) the" 198 << " I-th implicit\n" 199 << " pattern if L is \"imp\" followed by an integer " 200 << "I (index origin one)\n"; 201 OS << " - "; 202 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N"; 203 OS << " labels the Nth match result for such a pattern\n"; 204 205 // Markers on annotation lines. 206 OS << " - "; 207 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~"; 208 OS << " marks good match (reported if -v)\n" 209 << " - "; 210 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~"; 211 OS << " marks bad match, such as:\n" 212 << " - CHECK-NEXT on same line as previous match (error)\n" 213 << " - CHECK-NOT found (error)\n" 214 << " - CHECK-DAG overlapping match (discarded, reported if " 215 << "-vv)\n" 216 << " - "; 217 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~"; 218 OS << " marks search range when no match is found, such as:\n" 219 << " - CHECK-NEXT not found (error)\n" 220 << " - CHECK-NOT not found (success, reported if -vv)\n" 221 << " - CHECK-DAG not found after discarded matches (error)\n" 222 << " - "; 223 WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?"; 224 OS << " marks fuzzy match when no match is found\n"; 225 226 // Colors. 227 OS << " - colors "; 228 WithColor(OS, raw_ostream::GREEN, true) << "success"; 229 OS << ", "; 230 WithColor(OS, raw_ostream::RED, true) << "error"; 231 OS << ", "; 232 WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match"; 233 OS << ", "; 234 WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match"; 235 OS << ", "; 236 WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input"; 237 OS << "\n\n" 238 << "If you are not seeing color above or in input dumps, try: -color\n"; 239 } 240 241 /// An annotation for a single input line. 242 struct InputAnnotation { 243 /// The index of the match result across all checks 244 unsigned DiagIndex; 245 /// The label for this annotation. 246 std::string Label; 247 /// What input line (one-origin indexing) this annotation marks. This might 248 /// be different from the starting line of the original diagnostic if this is 249 /// a non-initial fragment of a diagnostic that has been broken across 250 /// multiple lines. 251 unsigned InputLine; 252 /// The column range (one-origin indexing, open end) in which to mark the 253 /// input line. If InputEndCol is UINT_MAX, treat it as the last column 254 /// before the newline. 255 unsigned InputStartCol, InputEndCol; 256 /// The marker to use. 257 MarkerStyle Marker; 258 /// Whether this annotation represents a good match for an expected pattern. 259 bool FoundAndExpectedMatch; 260 }; 261 262 /// Get an abbreviation for the check type. 263 std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) { 264 switch (Ty) { 265 case Check::CheckPlain: 266 if (Ty.getCount() > 1) 267 return "count"; 268 return "check"; 269 case Check::CheckNext: 270 return "next"; 271 case Check::CheckSame: 272 return "same"; 273 case Check::CheckNot: 274 return "not"; 275 case Check::CheckDAG: 276 return "dag"; 277 case Check::CheckLabel: 278 return "label"; 279 case Check::CheckEmpty: 280 return "empty"; 281 case Check::CheckComment: 282 return "com"; 283 case Check::CheckEOF: 284 return "eof"; 285 case Check::CheckBadNot: 286 return "bad-not"; 287 case Check::CheckBadCount: 288 return "bad-count"; 289 case Check::CheckNone: 290 llvm_unreachable("invalid FileCheckType"); 291 } 292 llvm_unreachable("unknown FileCheckType"); 293 } 294 295 static void 296 BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID, 297 const std::pair<unsigned, unsigned> &ImpPatBufferIDRange, 298 const std::vector<FileCheckDiag> &Diags, 299 std::vector<InputAnnotation> &Annotations, 300 unsigned &LabelWidth) { 301 // How many diagnostics have we seen so far? 302 unsigned DiagCount = 0; 303 // How many diagnostics has the current check seen so far? 304 unsigned CheckDiagCount = 0; 305 // What's the widest label? 306 LabelWidth = 0; 307 for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd; 308 ++DiagItr) { 309 InputAnnotation A; 310 A.DiagIndex = DiagCount++; 311 312 // Build label, which uniquely identifies this check result. 313 unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc); 314 auto CheckLineAndCol = 315 SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID); 316 llvm::raw_string_ostream Label(A.Label); 317 Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"; 318 if (CheckBufferID == CheckFileBufferID) 319 Label << CheckLineAndCol.first; 320 else if (ImpPatBufferIDRange.first <= CheckBufferID && 321 CheckBufferID < ImpPatBufferIDRange.second) 322 Label << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1); 323 else 324 llvm_unreachable("expected diagnostic's check location to be either in " 325 "the check file or for an implicit pattern"); 326 unsigned CheckDiagIndex = UINT_MAX; 327 auto DiagNext = std::next(DiagItr); 328 if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy && 329 DiagItr->CheckLoc == DiagNext->CheckLoc) 330 CheckDiagIndex = CheckDiagCount++; 331 else if (CheckDiagCount) { 332 CheckDiagIndex = CheckDiagCount; 333 CheckDiagCount = 0; 334 } 335 if (CheckDiagIndex != UINT_MAX) 336 Label << "'" << CheckDiagIndex; 337 Label.flush(); 338 LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size()); 339 340 A.Marker = GetMarker(DiagItr->MatchTy); 341 A.FoundAndExpectedMatch = 342 DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected; 343 344 // Compute the mark location, and break annotation into multiple 345 // annotations if it spans multiple lines. 346 A.InputLine = DiagItr->InputStartLine; 347 A.InputStartCol = DiagItr->InputStartCol; 348 if (DiagItr->InputStartLine == DiagItr->InputEndLine) { 349 // Sometimes ranges are empty in order to indicate a specific point, but 350 // that would mean nothing would be marked, so adjust the range to 351 // include the following character. 352 A.InputEndCol = 353 std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol); 354 Annotations.push_back(A); 355 } else { 356 assert(DiagItr->InputStartLine < DiagItr->InputEndLine && 357 "expected input range not to be inverted"); 358 A.InputEndCol = UINT_MAX; 359 Annotations.push_back(A); 360 for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine; 361 L <= E; ++L) { 362 // If a range ends before the first column on a line, then it has no 363 // characters on that line, so there's nothing to render. 364 if (DiagItr->InputEndCol == 1 && L == E) 365 break; 366 InputAnnotation B; 367 B.DiagIndex = A.DiagIndex; 368 B.Label = A.Label; 369 B.InputLine = L; 370 B.Marker = A.Marker; 371 B.Marker.Lead = '~'; 372 B.Marker.Note = ""; 373 B.InputStartCol = 1; 374 if (L != E) 375 B.InputEndCol = UINT_MAX; 376 else 377 B.InputEndCol = DiagItr->InputEndCol; 378 B.FoundAndExpectedMatch = A.FoundAndExpectedMatch; 379 Annotations.push_back(B); 380 } 381 } 382 } 383 } 384 385 static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req, 386 StringRef InputFileText, 387 std::vector<InputAnnotation> &Annotations, 388 unsigned LabelWidth) { 389 OS << "Full input was:\n<<<<<<\n"; 390 391 // Sort annotations. 392 std::sort(Annotations.begin(), Annotations.end(), 393 [](const InputAnnotation &A, const InputAnnotation &B) { 394 // 1. Sort annotations in the order of the input lines. 395 // 396 // This makes it easier to find relevant annotations while 397 // iterating input lines in the implementation below. FileCheck 398 // does not always produce diagnostics in the order of input 399 // lines due to, for example, CHECK-DAG and CHECK-NOT. 400 if (A.InputLine != B.InputLine) 401 return A.InputLine < B.InputLine; 402 // 2. Sort annotations in the temporal order FileCheck produced 403 // their associated diagnostics. 404 // 405 // This sort offers several benefits: 406 // 407 // A. On a single input line, the order of annotations reflects 408 // the FileCheck logic for processing directives/patterns. 409 // This can be helpful in understanding cases in which the 410 // order of the associated directives/patterns in the check 411 // file or on the command line either (i) does not match the 412 // temporal order in which FileCheck looks for matches for the 413 // directives/patterns (due to, for example, CHECK-LABEL, 414 // CHECK-NOT, or `--implicit-check-not`) or (ii) does match 415 // that order but does not match the order of those 416 // diagnostics along an input line (due to, for example, 417 // CHECK-DAG). 418 // 419 // On the other hand, because our presentation format presents 420 // input lines in order, there's no clear way to offer the 421 // same benefit across input lines. For consistency, it might 422 // then seem worthwhile to have annotations on a single line 423 // also sorted in input order (that is, by input column). 424 // However, in practice, this appears to be more confusing 425 // than helpful. Perhaps it's intuitive to expect annotations 426 // to be listed in the temporal order in which they were 427 // produced except in cases the presentation format obviously 428 // and inherently cannot support it (that is, across input 429 // lines). 430 // 431 // B. When diagnostics' annotations are split among multiple 432 // input lines, the user must track them from one input line 433 // to the next. One property of the sort chosen here is that 434 // it facilitates the user in this regard by ensuring the 435 // following: when comparing any two input lines, a 436 // diagnostic's annotations are sorted in the same position 437 // relative to all other diagnostics' annotations. 438 return A.DiagIndex < B.DiagIndex; 439 }); 440 441 // Compute the width of the label column. 442 const unsigned char *InputFilePtr = InputFileText.bytes_begin(), 443 *InputFileEnd = InputFileText.bytes_end(); 444 unsigned LineCount = InputFileText.count('\n'); 445 if (InputFileEnd[-1] != '\n') 446 ++LineCount; 447 unsigned LineNoWidth = std::log10(LineCount) + 1; 448 // +3 below adds spaces (1) to the left of the (right-aligned) line numbers 449 // on input lines and (2) to the right of the (left-aligned) labels on 450 // annotation lines so that input lines and annotation lines are more 451 // visually distinct. For example, the spaces on the annotation lines ensure 452 // that input line numbers and check directive line numbers never align 453 // horizontally. Those line numbers might not even be for the same file. 454 // One space would be enough to achieve that, but more makes it even easier 455 // to see. 456 LabelWidth = std::max(LabelWidth, LineNoWidth) + 3; 457 458 // Print annotated input lines. 459 auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end(); 460 for (unsigned Line = 1; 461 InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd; 462 ++Line) { 463 const unsigned char *InputFileLine = InputFilePtr; 464 465 // Print right-aligned line number. 466 WithColor(OS, raw_ostream::BLACK, true) 467 << format_decimal(Line, LabelWidth) << ": "; 468 469 // For the case where -v and colors are enabled, find the annotations for 470 // good matches for expected patterns in order to highlight everything 471 // else in the line. There are no such annotations if -v is disabled. 472 std::vector<InputAnnotation> FoundAndExpectedMatches; 473 if (Req.Verbose && WithColor(OS).colorsEnabled()) { 474 for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line; 475 ++I) { 476 if (I->FoundAndExpectedMatch) 477 FoundAndExpectedMatches.push_back(*I); 478 } 479 } 480 481 // Print numbered line with highlighting where there are no matches for 482 // expected patterns. 483 bool Newline = false; 484 { 485 WithColor COS(OS); 486 bool InMatch = false; 487 if (Req.Verbose) 488 COS.changeColor(raw_ostream::CYAN, true, true); 489 for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) { 490 bool WasInMatch = InMatch; 491 InMatch = false; 492 for (auto M : FoundAndExpectedMatches) { 493 if (M.InputStartCol <= Col && Col < M.InputEndCol) { 494 InMatch = true; 495 break; 496 } 497 } 498 if (!WasInMatch && InMatch) 499 COS.resetColor(); 500 else if (WasInMatch && !InMatch) 501 COS.changeColor(raw_ostream::CYAN, true, true); 502 if (*InputFilePtr == '\n') 503 Newline = true; 504 else 505 COS << *InputFilePtr; 506 ++InputFilePtr; 507 } 508 } 509 OS << '\n'; 510 unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline; 511 512 // Print any annotations. 513 while (AnnotationItr != AnnotationEnd && 514 AnnotationItr->InputLine == Line) { 515 WithColor COS(OS, AnnotationItr->Marker.Color, true); 516 // The two spaces below are where the ": " appears on input lines. 517 COS << left_justify(AnnotationItr->Label, LabelWidth) << " "; 518 unsigned Col; 519 for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col) 520 COS << ' '; 521 COS << AnnotationItr->Marker.Lead; 522 // If InputEndCol=UINT_MAX, stop at InputLineWidth. 523 for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth; 524 ++Col) 525 COS << '~'; 526 const std::string &Note = AnnotationItr->Marker.Note; 527 if (!Note.empty()) { 528 // Put the note at the end of the input line. If we were to instead 529 // put the note right after the marker, subsequent annotations for the 530 // same input line might appear to mark this note instead of the input 531 // line. 532 for (; Col <= InputLineWidth; ++Col) 533 COS << ' '; 534 COS << ' ' << Note; 535 } 536 COS << '\n'; 537 ++AnnotationItr; 538 } 539 } 540 541 OS << ">>>>>>\n"; 542 } 543 544 int main(int argc, char **argv) { 545 // Enable use of ANSI color codes because FileCheck is using them to 546 // highlight text. 547 llvm::sys::Process::UseANSIEscapeCodes(true); 548 549 InitLLVM X(argc, argv); 550 cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr, 551 "FILECHECK_OPTS"); 552 DumpInputValue DumpInput = 553 DumpInputs.empty() 554 ? DumpInputDefault 555 : *std::max_element(DumpInputs.begin(), DumpInputs.end()); 556 if (DumpInput == DumpInputHelp) { 557 DumpInputAnnotationHelp(outs()); 558 return 0; 559 } 560 if (CheckFilename.empty()) { 561 errs() << "<check-file> not specified\n"; 562 return 2; 563 } 564 565 FileCheckRequest Req; 566 for (StringRef Prefix : CheckPrefixes) 567 Req.CheckPrefixes.push_back(Prefix); 568 569 for (StringRef Prefix : CommentPrefixes) 570 Req.CommentPrefixes.push_back(Prefix); 571 572 for (StringRef CheckNot : ImplicitCheckNot) 573 Req.ImplicitCheckNot.push_back(CheckNot); 574 575 bool GlobalDefineError = false; 576 for (StringRef G : GlobalDefines) { 577 size_t EqIdx = G.find('='); 578 if (EqIdx == std::string::npos) { 579 errs() << "Missing equal sign in command-line definition '-D" << G 580 << "'\n"; 581 GlobalDefineError = true; 582 continue; 583 } 584 if (EqIdx == 0) { 585 errs() << "Missing variable name in command-line definition '-D" << G 586 << "'\n"; 587 GlobalDefineError = true; 588 continue; 589 } 590 Req.GlobalDefines.push_back(G); 591 } 592 if (GlobalDefineError) 593 return 2; 594 595 Req.AllowEmptyInput = AllowEmptyInput; 596 Req.EnableVarScope = EnableVarScope; 597 Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap; 598 Req.Verbose = Verbose; 599 Req.VerboseVerbose = VerboseVerbose; 600 Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace; 601 Req.MatchFullLines = MatchFullLines; 602 Req.IgnoreCase = IgnoreCase; 603 604 if (VerboseVerbose) 605 Req.Verbose = true; 606 607 FileCheck FC(Req); 608 if (!FC.ValidateCheckPrefixes()) 609 return 2; 610 611 Regex PrefixRE = FC.buildCheckPrefixRegex(); 612 std::string REError; 613 if (!PrefixRE.isValid(REError)) { 614 errs() << "Unable to combine check-prefix strings into a prefix regular " 615 "expression! This is likely a bug in FileCheck's verification of " 616 "the check-prefix strings. Regular expression parsing failed " 617 "with the following error: " 618 << REError << "\n"; 619 return 2; 620 } 621 622 SourceMgr SM; 623 624 // Read the expected strings from the check file. 625 ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr = 626 MemoryBuffer::getFileOrSTDIN(CheckFilename); 627 if (std::error_code EC = CheckFileOrErr.getError()) { 628 errs() << "Could not open check file '" << CheckFilename 629 << "': " << EC.message() << '\n'; 630 return 2; 631 } 632 MemoryBuffer &CheckFile = *CheckFileOrErr.get(); 633 634 SmallString<4096> CheckFileBuffer; 635 StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer); 636 637 unsigned CheckFileBufferID = 638 SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer( 639 CheckFileText, CheckFile.getBufferIdentifier()), 640 SMLoc()); 641 642 std::pair<unsigned, unsigned> ImpPatBufferIDRange; 643 if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange)) 644 return 2; 645 646 // Open the file to check and add it to SourceMgr. 647 ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr = 648 MemoryBuffer::getFileOrSTDIN(InputFilename); 649 if (InputFilename == "-") 650 InputFilename = "<stdin>"; // Overwrite for improved diagnostic messages 651 if (std::error_code EC = InputFileOrErr.getError()) { 652 errs() << "Could not open input file '" << InputFilename 653 << "': " << EC.message() << '\n'; 654 return 2; 655 } 656 MemoryBuffer &InputFile = *InputFileOrErr.get(); 657 658 if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) { 659 errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; 660 DumpCommandLine(argc, argv); 661 return 2; 662 } 663 664 SmallString<4096> InputFileBuffer; 665 StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer); 666 667 SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer( 668 InputFileText, InputFile.getBufferIdentifier()), 669 SMLoc()); 670 671 if (DumpInput == DumpInputDefault) 672 DumpInput = DumpInputFail; 673 674 std::vector<FileCheckDiag> Diags; 675 int ExitCode = FC.checkInput(SM, InputFileText, 676 DumpInput == DumpInputNever ? nullptr : &Diags) 677 ? EXIT_SUCCESS 678 : 1; 679 if (DumpInput == DumpInputAlways || 680 (ExitCode == 1 && DumpInput == DumpInputFail)) { 681 errs() << "\n" 682 << "Input file: " 683 << InputFilename 684 << "\n" 685 << "Check file: " << CheckFilename << "\n" 686 << "\n" 687 << "-dump-input=help describes the format of the following dump.\n" 688 << "\n"; 689 std::vector<InputAnnotation> Annotations; 690 unsigned LabelWidth; 691 BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags, 692 Annotations, LabelWidth); 693 DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth); 694 } 695 696 return ExitCode; 697 } 698