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