109467b48Spatrick //===- FileCheck.cpp - Check that File's Contents match what is expected --===// 209467b48Spatrick // 309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information. 509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 609467b48Spatrick // 709467b48Spatrick //===----------------------------------------------------------------------===// 809467b48Spatrick // 909467b48Spatrick // FileCheck does a line-by line check of a file that validates whether it 1009467b48Spatrick // contains the expected content. This is useful for regression tests etc. 1109467b48Spatrick // 1209467b48Spatrick // This program exits with an exit status of 2 on error, exit status of 0 if 1309467b48Spatrick // the file matched the expected contents, and exit status of 1 if it did not 1409467b48Spatrick // contain the expected contents. 1509467b48Spatrick // 1609467b48Spatrick //===----------------------------------------------------------------------===// 1709467b48Spatrick 1809467b48Spatrick #include "llvm/Support/CommandLine.h" 1909467b48Spatrick #include "llvm/Support/InitLLVM.h" 2009467b48Spatrick #include "llvm/Support/Process.h" 2109467b48Spatrick #include "llvm/Support/WithColor.h" 2209467b48Spatrick #include "llvm/Support/raw_ostream.h" 2309467b48Spatrick #include "llvm/Support/FileCheck.h" 2409467b48Spatrick #include <cmath> 2509467b48Spatrick using namespace llvm; 2609467b48Spatrick 2709467b48Spatrick static cl::extrahelp FileCheckOptsEnv( 2809467b48Spatrick "\nOptions are parsed from the environment variable FILECHECK_OPTS and\n" 2909467b48Spatrick "from the command line.\n"); 3009467b48Spatrick 3109467b48Spatrick static cl::opt<std::string> 3209467b48Spatrick CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional); 3309467b48Spatrick 3409467b48Spatrick static cl::opt<std::string> 3509467b48Spatrick InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), 3609467b48Spatrick cl::init("-"), cl::value_desc("filename")); 3709467b48Spatrick 3809467b48Spatrick static cl::list<std::string> CheckPrefixes( 3909467b48Spatrick "check-prefix", 4009467b48Spatrick cl::desc("Prefix to use from check file (defaults to 'CHECK')")); 4109467b48Spatrick static cl::alias CheckPrefixesAlias( 4209467b48Spatrick "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated, 4309467b48Spatrick cl::NotHidden, 4409467b48Spatrick cl::desc( 4509467b48Spatrick "Alias for -check-prefix permitting multiple comma separated values")); 4609467b48Spatrick 47*097a140dSpatrick static cl::list<std::string> CommentPrefixes( 48*097a140dSpatrick "comment-prefixes", cl::CommaSeparated, cl::Hidden, 49*097a140dSpatrick cl::desc("Comma-separated list of comment prefixes to use from check file\n" 50*097a140dSpatrick "(defaults to 'COM,RUN'). Please avoid using this feature in\n" 51*097a140dSpatrick "LLVM's LIT-based test suites, which should be easier to\n" 52*097a140dSpatrick "maintain if they all follow a consistent comment style. This\n" 53*097a140dSpatrick "feature is meant for non-LIT test suites using FileCheck.")); 54*097a140dSpatrick 5509467b48Spatrick static cl::opt<bool> NoCanonicalizeWhiteSpace( 5609467b48Spatrick "strict-whitespace", 5709467b48Spatrick cl::desc("Do not treat all horizontal whitespace as equivalent")); 5809467b48Spatrick 5909467b48Spatrick static cl::opt<bool> IgnoreCase( 6009467b48Spatrick "ignore-case", 6109467b48Spatrick cl::desc("Use case-insensitive matching")); 6209467b48Spatrick 6309467b48Spatrick static cl::list<std::string> ImplicitCheckNot( 6409467b48Spatrick "implicit-check-not", 6509467b48Spatrick cl::desc("Add an implicit negative check with this pattern to every\n" 6609467b48Spatrick "positive check. This can be used to ensure that no instances of\n" 6709467b48Spatrick "this pattern occur which are not matched by a positive pattern"), 6809467b48Spatrick cl::value_desc("pattern")); 6909467b48Spatrick 7009467b48Spatrick static cl::list<std::string> 7109467b48Spatrick GlobalDefines("D", cl::AlwaysPrefix, 7209467b48Spatrick cl::desc("Define a variable to be used in capture patterns."), 7309467b48Spatrick cl::value_desc("VAR=VALUE")); 7409467b48Spatrick 7509467b48Spatrick static cl::opt<bool> AllowEmptyInput( 7609467b48Spatrick "allow-empty", cl::init(false), 7709467b48Spatrick cl::desc("Allow the input file to be empty. This is useful when making\n" 7809467b48Spatrick "checks that some error message does not occur, for example.")); 7909467b48Spatrick 8009467b48Spatrick static cl::opt<bool> MatchFullLines( 8109467b48Spatrick "match-full-lines", cl::init(false), 8209467b48Spatrick cl::desc("Require all positive matches to cover an entire input line.\n" 8309467b48Spatrick "Allows leading and trailing whitespace if --strict-whitespace\n" 8409467b48Spatrick "is not also passed.")); 8509467b48Spatrick 8609467b48Spatrick static cl::opt<bool> EnableVarScope( 8709467b48Spatrick "enable-var-scope", cl::init(false), 8809467b48Spatrick cl::desc("Enables scope for regex variables. Variables with names that\n" 8909467b48Spatrick "do not start with '$' will be reset at the beginning of\n" 9009467b48Spatrick "each CHECK-LABEL block.")); 9109467b48Spatrick 9209467b48Spatrick static cl::opt<bool> AllowDeprecatedDagOverlap( 9309467b48Spatrick "allow-deprecated-dag-overlap", cl::init(false), 9409467b48Spatrick cl::desc("Enable overlapping among matches in a group of consecutive\n" 9509467b48Spatrick "CHECK-DAG directives. This option is deprecated and is only\n" 9609467b48Spatrick "provided for convenience as old tests are migrated to the new\n" 9709467b48Spatrick "non-overlapping CHECK-DAG implementation.\n")); 9809467b48Spatrick 9909467b48Spatrick static cl::opt<bool> Verbose( 100*097a140dSpatrick "v", cl::init(false), cl::ZeroOrMore, 10109467b48Spatrick cl::desc("Print directive pattern matches, or add them to the input dump\n" 10209467b48Spatrick "if enabled.\n")); 10309467b48Spatrick 10409467b48Spatrick static cl::opt<bool> VerboseVerbose( 105*097a140dSpatrick "vv", cl::init(false), cl::ZeroOrMore, 10609467b48Spatrick cl::desc("Print information helpful in diagnosing internal FileCheck\n" 10709467b48Spatrick "issues, or add it to the input dump if enabled. Implies\n" 10809467b48Spatrick "-v.\n")); 10909467b48Spatrick 11009467b48Spatrick // The order of DumpInputValue members affects their precedence, as documented 11109467b48Spatrick // for -dump-input below. 11209467b48Spatrick enum DumpInputValue { 11309467b48Spatrick DumpInputNever, 11409467b48Spatrick DumpInputFail, 11509467b48Spatrick DumpInputAlways, 11609467b48Spatrick DumpInputHelp 11709467b48Spatrick }; 11809467b48Spatrick 11909467b48Spatrick static cl::list<DumpInputValue> DumpInputs( 12009467b48Spatrick "dump-input", 12109467b48Spatrick cl::desc("Dump input to stderr, adding annotations representing\n" 12209467b48Spatrick "currently enabled diagnostics. When there are multiple\n" 12309467b48Spatrick "occurrences of this option, the <value> that appears earliest\n" 124*097a140dSpatrick "in the list below has precedence. The default is 'fail'.\n"), 12509467b48Spatrick cl::value_desc("mode"), 126*097a140dSpatrick cl::values(clEnumValN(DumpInputHelp, "help", "Explain input dump and quit"), 12709467b48Spatrick clEnumValN(DumpInputAlways, "always", "Always dump input"), 12809467b48Spatrick clEnumValN(DumpInputFail, "fail", "Dump input on failure"), 12909467b48Spatrick clEnumValN(DumpInputNever, "never", "Never dump input"))); 13009467b48Spatrick 131*097a140dSpatrick // The order of DumpInputFilterValue members affects their precedence, as 132*097a140dSpatrick // documented for -dump-input-filter below. 133*097a140dSpatrick enum DumpInputFilterValue { 134*097a140dSpatrick DumpInputFilterError, 135*097a140dSpatrick DumpInputFilterAnnotation, 136*097a140dSpatrick DumpInputFilterAnnotationFull, 137*097a140dSpatrick DumpInputFilterAll 138*097a140dSpatrick }; 139*097a140dSpatrick 140*097a140dSpatrick static cl::list<DumpInputFilterValue> DumpInputFilters( 141*097a140dSpatrick "dump-input-filter", 142*097a140dSpatrick cl::desc("In the dump requested by -dump-input, print only input lines of\n" 143*097a140dSpatrick "kind <value> plus any context specified by -dump-input-context.\n" 144*097a140dSpatrick "When there are multiple occurrences of this option, the <value>\n" 145*097a140dSpatrick "that appears earliest in the list below has precedence. The\n" 146*097a140dSpatrick "default is 'error' when -dump-input=fail, and it's 'all' when\n" 147*097a140dSpatrick "-dump-input=always.\n"), 148*097a140dSpatrick cl::values(clEnumValN(DumpInputFilterAll, "all", "All input lines"), 149*097a140dSpatrick clEnumValN(DumpInputFilterAnnotationFull, "annotation-full", 150*097a140dSpatrick "Input lines with annotations"), 151*097a140dSpatrick clEnumValN(DumpInputFilterAnnotation, "annotation", 152*097a140dSpatrick "Input lines with starting points of annotations"), 153*097a140dSpatrick clEnumValN(DumpInputFilterError, "error", 154*097a140dSpatrick "Input lines with starting points of error " 155*097a140dSpatrick "annotations"))); 156*097a140dSpatrick 157*097a140dSpatrick static cl::list<unsigned> DumpInputContexts( 158*097a140dSpatrick "dump-input-context", cl::value_desc("N"), 159*097a140dSpatrick cl::desc("In the dump requested by -dump-input, print <N> input lines\n" 160*097a140dSpatrick "before and <N> input lines after any lines specified by\n" 161*097a140dSpatrick "-dump-input-filter. When there are multiple occurrences of\n" 162*097a140dSpatrick "this option, the largest specified <N> has precedence. The\n" 163*097a140dSpatrick "default is 5.\n")); 164*097a140dSpatrick 16509467b48Spatrick typedef cl::list<std::string>::const_iterator prefix_iterator; 16609467b48Spatrick 16709467b48Spatrick 16809467b48Spatrick 16909467b48Spatrick 17009467b48Spatrick 17109467b48Spatrick 17209467b48Spatrick 17309467b48Spatrick static void DumpCommandLine(int argc, char **argv) { 17409467b48Spatrick errs() << "FileCheck command line: "; 17509467b48Spatrick for (int I = 0; I < argc; I++) 17609467b48Spatrick errs() << " " << argv[I]; 17709467b48Spatrick errs() << "\n"; 17809467b48Spatrick } 17909467b48Spatrick 18009467b48Spatrick struct MarkerStyle { 18109467b48Spatrick /// The starting char (before tildes) for marking the line. 18209467b48Spatrick char Lead; 18309467b48Spatrick /// What color to use for this annotation. 18409467b48Spatrick raw_ostream::Colors Color; 18509467b48Spatrick /// A note to follow the marker, or empty string if none. 18609467b48Spatrick std::string Note; 187*097a140dSpatrick /// Does this marker indicate inclusion by -dump-input-filter=error? 188*097a140dSpatrick bool FiltersAsError; 18909467b48Spatrick MarkerStyle() {} 19009467b48Spatrick MarkerStyle(char Lead, raw_ostream::Colors Color, 191*097a140dSpatrick const std::string &Note = "", bool FiltersAsError = false) 192*097a140dSpatrick : Lead(Lead), Color(Color), Note(Note), FiltersAsError(FiltersAsError) { 193*097a140dSpatrick assert((!FiltersAsError || !Note.empty()) && 194*097a140dSpatrick "expected error diagnostic to have note"); 195*097a140dSpatrick } 19609467b48Spatrick }; 19709467b48Spatrick 19809467b48Spatrick static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) { 19909467b48Spatrick switch (MatchTy) { 20009467b48Spatrick case FileCheckDiag::MatchFoundAndExpected: 20109467b48Spatrick return MarkerStyle('^', raw_ostream::GREEN); 20209467b48Spatrick case FileCheckDiag::MatchFoundButExcluded: 203*097a140dSpatrick return MarkerStyle('!', raw_ostream::RED, "error: no match expected", 204*097a140dSpatrick /*FiltersAsError=*/true); 20509467b48Spatrick case FileCheckDiag::MatchFoundButWrongLine: 206*097a140dSpatrick return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line", 207*097a140dSpatrick /*FiltersAsError=*/true); 20809467b48Spatrick case FileCheckDiag::MatchFoundButDiscarded: 20909467b48Spatrick return MarkerStyle('!', raw_ostream::CYAN, 21009467b48Spatrick "discard: overlaps earlier match"); 21109467b48Spatrick case FileCheckDiag::MatchNoneAndExcluded: 21209467b48Spatrick return MarkerStyle('X', raw_ostream::GREEN); 21309467b48Spatrick case FileCheckDiag::MatchNoneButExpected: 214*097a140dSpatrick return MarkerStyle('X', raw_ostream::RED, "error: no match found", 215*097a140dSpatrick /*FiltersAsError=*/true); 21609467b48Spatrick case FileCheckDiag::MatchFuzzy: 217*097a140dSpatrick return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match", 218*097a140dSpatrick /*FiltersAsError=*/true); 21909467b48Spatrick } 22009467b48Spatrick llvm_unreachable_internal("unexpected match type"); 22109467b48Spatrick } 22209467b48Spatrick 22309467b48Spatrick static void DumpInputAnnotationHelp(raw_ostream &OS) { 22409467b48Spatrick OS << "The following description was requested by -dump-input=help to\n" 225*097a140dSpatrick << "explain the input dump printed by FileCheck.\n" 226*097a140dSpatrick << "\n" 227*097a140dSpatrick << "Related command-line options:\n" 228*097a140dSpatrick << "\n" 229*097a140dSpatrick << " - -dump-input=<value> enables or disables the input dump\n" 230*097a140dSpatrick << " - -dump-input-filter=<value> filters the input lines\n" 231*097a140dSpatrick << " - -dump-input-context=<N> adjusts the context of filtered lines\n" 232*097a140dSpatrick << " - -v and -vv add more annotations\n" 233*097a140dSpatrick << " - -color forces colors to be enabled both in the dump and below\n" 234*097a140dSpatrick << " - -help documents the above options in more detail\n" 235*097a140dSpatrick << "\n" 236*097a140dSpatrick << "These options can also be set via FILECHECK_OPTS. For example, for\n" 237*097a140dSpatrick << "maximum debugging output on failures:\n" 238*097a140dSpatrick << "\n" 239*097a140dSpatrick << " $ FILECHECK_OPTS='-dump-input-filter=all -vv -color' ninja check\n" 240*097a140dSpatrick << "\n" 241*097a140dSpatrick << "Input dump annotation format:\n" 242*097a140dSpatrick << "\n"; 24309467b48Spatrick 24409467b48Spatrick // Labels for input lines. 24509467b48Spatrick OS << " - "; 24609467b48Spatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:"; 24709467b48Spatrick OS << " labels line number L of the input file\n"; 24809467b48Spatrick 24909467b48Spatrick // Labels for annotation lines. 25009467b48Spatrick OS << " - "; 25109467b48Spatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L"; 252*097a140dSpatrick OS << " labels the only match result for either (1) a pattern of type T" 253*097a140dSpatrick << " from\n" 254*097a140dSpatrick << " line L of the check file if L is an integer or (2) the" 255*097a140dSpatrick << " I-th implicit\n" 256*097a140dSpatrick << " pattern if L is \"imp\" followed by an integer " 257*097a140dSpatrick << "I (index origin one)\n"; 25809467b48Spatrick OS << " - "; 25909467b48Spatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N"; 260*097a140dSpatrick OS << " labels the Nth match result for such a pattern\n"; 26109467b48Spatrick 26209467b48Spatrick // Markers on annotation lines. 26309467b48Spatrick OS << " - "; 26409467b48Spatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~"; 26509467b48Spatrick OS << " marks good match (reported if -v)\n" 26609467b48Spatrick << " - "; 26709467b48Spatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~"; 26809467b48Spatrick OS << " marks bad match, such as:\n" 26909467b48Spatrick << " - CHECK-NEXT on same line as previous match (error)\n" 27009467b48Spatrick << " - CHECK-NOT found (error)\n" 27109467b48Spatrick << " - CHECK-DAG overlapping match (discarded, reported if " 27209467b48Spatrick << "-vv)\n" 27309467b48Spatrick << " - "; 27409467b48Spatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~"; 27509467b48Spatrick OS << " marks search range when no match is found, such as:\n" 27609467b48Spatrick << " - CHECK-NEXT not found (error)\n" 27709467b48Spatrick << " - CHECK-NOT not found (success, reported if -vv)\n" 27809467b48Spatrick << " - CHECK-DAG not found after discarded matches (error)\n" 27909467b48Spatrick << " - "; 28009467b48Spatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?"; 28109467b48Spatrick OS << " marks fuzzy match when no match is found\n"; 28209467b48Spatrick 283*097a140dSpatrick // Elided lines. 284*097a140dSpatrick OS << " - "; 285*097a140dSpatrick WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "..."; 286*097a140dSpatrick OS << " indicates elided input lines and annotations, as specified by\n" 287*097a140dSpatrick << " -dump-input-filter and -dump-input-context\n"; 288*097a140dSpatrick 28909467b48Spatrick // Colors. 29009467b48Spatrick OS << " - colors "; 29109467b48Spatrick WithColor(OS, raw_ostream::GREEN, true) << "success"; 29209467b48Spatrick OS << ", "; 29309467b48Spatrick WithColor(OS, raw_ostream::RED, true) << "error"; 29409467b48Spatrick OS << ", "; 29509467b48Spatrick WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match"; 29609467b48Spatrick OS << ", "; 29709467b48Spatrick WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match"; 29809467b48Spatrick OS << ", "; 29909467b48Spatrick WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input"; 300*097a140dSpatrick OS << "\n"; 30109467b48Spatrick } 30209467b48Spatrick 30309467b48Spatrick /// An annotation for a single input line. 30409467b48Spatrick struct InputAnnotation { 305*097a140dSpatrick /// The index of the match result across all checks 306*097a140dSpatrick unsigned DiagIndex; 30709467b48Spatrick /// The label for this annotation. 30809467b48Spatrick std::string Label; 309*097a140dSpatrick /// Is this the initial fragment of a diagnostic that has been broken across 310*097a140dSpatrick /// multiple lines? 311*097a140dSpatrick bool IsFirstLine; 31209467b48Spatrick /// What input line (one-origin indexing) this annotation marks. This might 313*097a140dSpatrick /// be different from the starting line of the original diagnostic if 314*097a140dSpatrick /// !IsFirstLine. 31509467b48Spatrick unsigned InputLine; 316*097a140dSpatrick /// The column range (one-origin indexing, open end) in which to mark the 31709467b48Spatrick /// input line. If InputEndCol is UINT_MAX, treat it as the last column 31809467b48Spatrick /// before the newline. 31909467b48Spatrick unsigned InputStartCol, InputEndCol; 32009467b48Spatrick /// The marker to use. 32109467b48Spatrick MarkerStyle Marker; 32209467b48Spatrick /// Whether this annotation represents a good match for an expected pattern. 32309467b48Spatrick bool FoundAndExpectedMatch; 32409467b48Spatrick }; 32509467b48Spatrick 32609467b48Spatrick /// Get an abbreviation for the check type. 32709467b48Spatrick std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) { 32809467b48Spatrick switch (Ty) { 32909467b48Spatrick case Check::CheckPlain: 33009467b48Spatrick if (Ty.getCount() > 1) 33109467b48Spatrick return "count"; 33209467b48Spatrick return "check"; 33309467b48Spatrick case Check::CheckNext: 33409467b48Spatrick return "next"; 33509467b48Spatrick case Check::CheckSame: 33609467b48Spatrick return "same"; 33709467b48Spatrick case Check::CheckNot: 33809467b48Spatrick return "not"; 33909467b48Spatrick case Check::CheckDAG: 34009467b48Spatrick return "dag"; 34109467b48Spatrick case Check::CheckLabel: 34209467b48Spatrick return "label"; 34309467b48Spatrick case Check::CheckEmpty: 34409467b48Spatrick return "empty"; 345*097a140dSpatrick case Check::CheckComment: 346*097a140dSpatrick return "com"; 34709467b48Spatrick case Check::CheckEOF: 34809467b48Spatrick return "eof"; 34909467b48Spatrick case Check::CheckBadNot: 35009467b48Spatrick return "bad-not"; 35109467b48Spatrick case Check::CheckBadCount: 35209467b48Spatrick return "bad-count"; 35309467b48Spatrick case Check::CheckNone: 35409467b48Spatrick llvm_unreachable("invalid FileCheckType"); 35509467b48Spatrick } 35609467b48Spatrick llvm_unreachable("unknown FileCheckType"); 35709467b48Spatrick } 35809467b48Spatrick 359*097a140dSpatrick static void 360*097a140dSpatrick BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID, 361*097a140dSpatrick const std::pair<unsigned, unsigned> &ImpPatBufferIDRange, 362*097a140dSpatrick const std::vector<FileCheckDiag> &Diags, 36309467b48Spatrick std::vector<InputAnnotation> &Annotations, 36409467b48Spatrick unsigned &LabelWidth) { 365*097a140dSpatrick // How many diagnostics have we seen so far? 366*097a140dSpatrick unsigned DiagCount = 0; 36709467b48Spatrick // How many diagnostics has the current check seen so far? 36809467b48Spatrick unsigned CheckDiagCount = 0; 36909467b48Spatrick // What's the widest label? 37009467b48Spatrick LabelWidth = 0; 37109467b48Spatrick for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd; 37209467b48Spatrick ++DiagItr) { 37309467b48Spatrick InputAnnotation A; 374*097a140dSpatrick A.DiagIndex = DiagCount++; 37509467b48Spatrick 37609467b48Spatrick // Build label, which uniquely identifies this check result. 377*097a140dSpatrick unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc); 378*097a140dSpatrick auto CheckLineAndCol = 379*097a140dSpatrick SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID); 38009467b48Spatrick llvm::raw_string_ostream Label(A.Label); 381*097a140dSpatrick Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"; 382*097a140dSpatrick if (CheckBufferID == CheckFileBufferID) 383*097a140dSpatrick Label << CheckLineAndCol.first; 384*097a140dSpatrick else if (ImpPatBufferIDRange.first <= CheckBufferID && 385*097a140dSpatrick CheckBufferID < ImpPatBufferIDRange.second) 386*097a140dSpatrick Label << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1); 387*097a140dSpatrick else 388*097a140dSpatrick llvm_unreachable("expected diagnostic's check location to be either in " 389*097a140dSpatrick "the check file or for an implicit pattern"); 390*097a140dSpatrick unsigned CheckDiagIndex = UINT_MAX; 39109467b48Spatrick auto DiagNext = std::next(DiagItr); 39209467b48Spatrick if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy && 393*097a140dSpatrick DiagItr->CheckLoc == DiagNext->CheckLoc) 394*097a140dSpatrick CheckDiagIndex = CheckDiagCount++; 39509467b48Spatrick else if (CheckDiagCount) { 396*097a140dSpatrick CheckDiagIndex = CheckDiagCount; 39709467b48Spatrick CheckDiagCount = 0; 39809467b48Spatrick } 399*097a140dSpatrick if (CheckDiagIndex != UINT_MAX) 400*097a140dSpatrick Label << "'" << CheckDiagIndex; 40109467b48Spatrick Label.flush(); 40209467b48Spatrick LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size()); 40309467b48Spatrick 40409467b48Spatrick A.Marker = GetMarker(DiagItr->MatchTy); 40509467b48Spatrick A.FoundAndExpectedMatch = 40609467b48Spatrick DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected; 40709467b48Spatrick 40809467b48Spatrick // Compute the mark location, and break annotation into multiple 40909467b48Spatrick // annotations if it spans multiple lines. 410*097a140dSpatrick A.IsFirstLine = true; 41109467b48Spatrick A.InputLine = DiagItr->InputStartLine; 41209467b48Spatrick A.InputStartCol = DiagItr->InputStartCol; 41309467b48Spatrick if (DiagItr->InputStartLine == DiagItr->InputEndLine) { 41409467b48Spatrick // Sometimes ranges are empty in order to indicate a specific point, but 41509467b48Spatrick // that would mean nothing would be marked, so adjust the range to 41609467b48Spatrick // include the following character. 41709467b48Spatrick A.InputEndCol = 41809467b48Spatrick std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol); 41909467b48Spatrick Annotations.push_back(A); 42009467b48Spatrick } else { 42109467b48Spatrick assert(DiagItr->InputStartLine < DiagItr->InputEndLine && 42209467b48Spatrick "expected input range not to be inverted"); 42309467b48Spatrick A.InputEndCol = UINT_MAX; 42409467b48Spatrick Annotations.push_back(A); 42509467b48Spatrick for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine; 42609467b48Spatrick L <= E; ++L) { 42709467b48Spatrick // If a range ends before the first column on a line, then it has no 42809467b48Spatrick // characters on that line, so there's nothing to render. 42909467b48Spatrick if (DiagItr->InputEndCol == 1 && L == E) 43009467b48Spatrick break; 43109467b48Spatrick InputAnnotation B; 432*097a140dSpatrick B.DiagIndex = A.DiagIndex; 43309467b48Spatrick B.Label = A.Label; 434*097a140dSpatrick B.IsFirstLine = false; 43509467b48Spatrick B.InputLine = L; 43609467b48Spatrick B.Marker = A.Marker; 43709467b48Spatrick B.Marker.Lead = '~'; 43809467b48Spatrick B.Marker.Note = ""; 43909467b48Spatrick B.InputStartCol = 1; 44009467b48Spatrick if (L != E) 44109467b48Spatrick B.InputEndCol = UINT_MAX; 44209467b48Spatrick else 44309467b48Spatrick B.InputEndCol = DiagItr->InputEndCol; 44409467b48Spatrick B.FoundAndExpectedMatch = A.FoundAndExpectedMatch; 44509467b48Spatrick Annotations.push_back(B); 44609467b48Spatrick } 44709467b48Spatrick } 44809467b48Spatrick } 44909467b48Spatrick } 45009467b48Spatrick 451*097a140dSpatrick static unsigned FindInputLineInFilter( 452*097a140dSpatrick DumpInputFilterValue DumpInputFilter, unsigned CurInputLine, 453*097a140dSpatrick const std::vector<InputAnnotation>::iterator &AnnotationBeg, 454*097a140dSpatrick const std::vector<InputAnnotation>::iterator &AnnotationEnd) { 455*097a140dSpatrick if (DumpInputFilter == DumpInputFilterAll) 456*097a140dSpatrick return CurInputLine; 457*097a140dSpatrick for (auto AnnotationItr = AnnotationBeg; AnnotationItr != AnnotationEnd; 458*097a140dSpatrick ++AnnotationItr) { 459*097a140dSpatrick switch (DumpInputFilter) { 460*097a140dSpatrick case DumpInputFilterAll: 461*097a140dSpatrick llvm_unreachable("unexpected DumpInputFilterAll"); 462*097a140dSpatrick break; 463*097a140dSpatrick case DumpInputFilterAnnotationFull: 464*097a140dSpatrick return AnnotationItr->InputLine; 465*097a140dSpatrick case DumpInputFilterAnnotation: 466*097a140dSpatrick if (AnnotationItr->IsFirstLine) 467*097a140dSpatrick return AnnotationItr->InputLine; 468*097a140dSpatrick break; 469*097a140dSpatrick case DumpInputFilterError: 470*097a140dSpatrick if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError) 471*097a140dSpatrick return AnnotationItr->InputLine; 472*097a140dSpatrick break; 473*097a140dSpatrick } 474*097a140dSpatrick } 475*097a140dSpatrick return UINT_MAX; 476*097a140dSpatrick } 477*097a140dSpatrick 478*097a140dSpatrick /// To OS, print a vertical ellipsis (right-justified at LabelWidth) if it would 479*097a140dSpatrick /// occupy less lines than ElidedLines, but print ElidedLines otherwise. Either 480*097a140dSpatrick /// way, clear ElidedLines. Thus, if ElidedLines is empty, do nothing. 481*097a140dSpatrick static void DumpEllipsisOrElidedLines(raw_ostream &OS, std::string &ElidedLines, 482*097a140dSpatrick unsigned LabelWidth) { 483*097a140dSpatrick if (ElidedLines.empty()) 484*097a140dSpatrick return; 485*097a140dSpatrick unsigned EllipsisLines = 3; 486*097a140dSpatrick if (EllipsisLines < StringRef(ElidedLines).count('\n')) { 487*097a140dSpatrick for (unsigned i = 0; i < EllipsisLines; ++i) { 488*097a140dSpatrick WithColor(OS, raw_ostream::BLACK, /*Bold=*/true) 489*097a140dSpatrick << right_justify(".", LabelWidth); 490*097a140dSpatrick OS << '\n'; 491*097a140dSpatrick } 492*097a140dSpatrick } else 493*097a140dSpatrick OS << ElidedLines; 494*097a140dSpatrick ElidedLines.clear(); 495*097a140dSpatrick } 496*097a140dSpatrick 49709467b48Spatrick static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req, 498*097a140dSpatrick DumpInputFilterValue DumpInputFilter, 499*097a140dSpatrick unsigned DumpInputContext, 50009467b48Spatrick StringRef InputFileText, 50109467b48Spatrick std::vector<InputAnnotation> &Annotations, 50209467b48Spatrick unsigned LabelWidth) { 503*097a140dSpatrick OS << "Input was:\n<<<<<<\n"; 50409467b48Spatrick 50509467b48Spatrick // Sort annotations. 50609467b48Spatrick std::sort(Annotations.begin(), Annotations.end(), 50709467b48Spatrick [](const InputAnnotation &A, const InputAnnotation &B) { 508*097a140dSpatrick // 1. Sort annotations in the order of the input lines. 509*097a140dSpatrick // 510*097a140dSpatrick // This makes it easier to find relevant annotations while 511*097a140dSpatrick // iterating input lines in the implementation below. FileCheck 512*097a140dSpatrick // does not always produce diagnostics in the order of input 513*097a140dSpatrick // lines due to, for example, CHECK-DAG and CHECK-NOT. 51409467b48Spatrick if (A.InputLine != B.InputLine) 51509467b48Spatrick return A.InputLine < B.InputLine; 516*097a140dSpatrick // 2. Sort annotations in the temporal order FileCheck produced 517*097a140dSpatrick // their associated diagnostics. 518*097a140dSpatrick // 519*097a140dSpatrick // This sort offers several benefits: 520*097a140dSpatrick // 521*097a140dSpatrick // A. On a single input line, the order of annotations reflects 522*097a140dSpatrick // the FileCheck logic for processing directives/patterns. 523*097a140dSpatrick // This can be helpful in understanding cases in which the 524*097a140dSpatrick // order of the associated directives/patterns in the check 525*097a140dSpatrick // file or on the command line either (i) does not match the 526*097a140dSpatrick // temporal order in which FileCheck looks for matches for the 527*097a140dSpatrick // directives/patterns (due to, for example, CHECK-LABEL, 528*097a140dSpatrick // CHECK-NOT, or `--implicit-check-not`) or (ii) does match 529*097a140dSpatrick // that order but does not match the order of those 530*097a140dSpatrick // diagnostics along an input line (due to, for example, 531*097a140dSpatrick // CHECK-DAG). 532*097a140dSpatrick // 533*097a140dSpatrick // On the other hand, because our presentation format presents 534*097a140dSpatrick // input lines in order, there's no clear way to offer the 535*097a140dSpatrick // same benefit across input lines. For consistency, it might 536*097a140dSpatrick // then seem worthwhile to have annotations on a single line 537*097a140dSpatrick // also sorted in input order (that is, by input column). 538*097a140dSpatrick // However, in practice, this appears to be more confusing 539*097a140dSpatrick // than helpful. Perhaps it's intuitive to expect annotations 540*097a140dSpatrick // to be listed in the temporal order in which they were 541*097a140dSpatrick // produced except in cases the presentation format obviously 542*097a140dSpatrick // and inherently cannot support it (that is, across input 543*097a140dSpatrick // lines). 544*097a140dSpatrick // 545*097a140dSpatrick // B. When diagnostics' annotations are split among multiple 546*097a140dSpatrick // input lines, the user must track them from one input line 547*097a140dSpatrick // to the next. One property of the sort chosen here is that 548*097a140dSpatrick // it facilitates the user in this regard by ensuring the 549*097a140dSpatrick // following: when comparing any two input lines, a 550*097a140dSpatrick // diagnostic's annotations are sorted in the same position 551*097a140dSpatrick // relative to all other diagnostics' annotations. 552*097a140dSpatrick return A.DiagIndex < B.DiagIndex; 55309467b48Spatrick }); 55409467b48Spatrick 55509467b48Spatrick // Compute the width of the label column. 55609467b48Spatrick const unsigned char *InputFilePtr = InputFileText.bytes_begin(), 55709467b48Spatrick *InputFileEnd = InputFileText.bytes_end(); 55809467b48Spatrick unsigned LineCount = InputFileText.count('\n'); 55909467b48Spatrick if (InputFileEnd[-1] != '\n') 56009467b48Spatrick ++LineCount; 56109467b48Spatrick unsigned LineNoWidth = std::log10(LineCount) + 1; 56209467b48Spatrick // +3 below adds spaces (1) to the left of the (right-aligned) line numbers 56309467b48Spatrick // on input lines and (2) to the right of the (left-aligned) labels on 56409467b48Spatrick // annotation lines so that input lines and annotation lines are more 56509467b48Spatrick // visually distinct. For example, the spaces on the annotation lines ensure 56609467b48Spatrick // that input line numbers and check directive line numbers never align 56709467b48Spatrick // horizontally. Those line numbers might not even be for the same file. 56809467b48Spatrick // One space would be enough to achieve that, but more makes it even easier 56909467b48Spatrick // to see. 57009467b48Spatrick LabelWidth = std::max(LabelWidth, LineNoWidth) + 3; 57109467b48Spatrick 57209467b48Spatrick // Print annotated input lines. 573*097a140dSpatrick unsigned PrevLineInFilter = 0; // 0 means none so far 574*097a140dSpatrick unsigned NextLineInFilter = 0; // 0 means uncomputed, UINT_MAX means none 575*097a140dSpatrick std::string ElidedLines; 576*097a140dSpatrick raw_string_ostream ElidedLinesOS(ElidedLines); 577*097a140dSpatrick ColorMode TheColorMode = 578*097a140dSpatrick WithColor(OS).colorsEnabled() ? ColorMode::Enable : ColorMode::Disable; 579*097a140dSpatrick if (TheColorMode == ColorMode::Enable) 580*097a140dSpatrick ElidedLinesOS.enable_colors(true); 58109467b48Spatrick auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end(); 58209467b48Spatrick for (unsigned Line = 1; 58309467b48Spatrick InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd; 58409467b48Spatrick ++Line) { 58509467b48Spatrick const unsigned char *InputFileLine = InputFilePtr; 58609467b48Spatrick 587*097a140dSpatrick // Compute the previous and next line included by the filter. 588*097a140dSpatrick if (NextLineInFilter < Line) 589*097a140dSpatrick NextLineInFilter = FindInputLineInFilter(DumpInputFilter, Line, 590*097a140dSpatrick AnnotationItr, AnnotationEnd); 591*097a140dSpatrick assert(NextLineInFilter && "expected NextLineInFilter to be computed"); 592*097a140dSpatrick if (NextLineInFilter == Line) 593*097a140dSpatrick PrevLineInFilter = Line; 594*097a140dSpatrick 595*097a140dSpatrick // Elide this input line and its annotations if it's not within the 596*097a140dSpatrick // context specified by -dump-input-context of an input line included by 597*097a140dSpatrick // -dump-input-filter. However, in case the resulting ellipsis would occupy 598*097a140dSpatrick // more lines than the input lines and annotations it elides, buffer the 599*097a140dSpatrick // elided lines and annotations so we can print them instead. 600*097a140dSpatrick raw_ostream *LineOS = &OS; 601*097a140dSpatrick if ((!PrevLineInFilter || PrevLineInFilter + DumpInputContext < Line) && 602*097a140dSpatrick (NextLineInFilter == UINT_MAX || 603*097a140dSpatrick Line + DumpInputContext < NextLineInFilter)) 604*097a140dSpatrick LineOS = &ElidedLinesOS; 605*097a140dSpatrick else { 606*097a140dSpatrick LineOS = &OS; 607*097a140dSpatrick DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth); 608*097a140dSpatrick } 609*097a140dSpatrick 61009467b48Spatrick // Print right-aligned line number. 611*097a140dSpatrick WithColor(*LineOS, raw_ostream::BLACK, /*Bold=*/true, /*BF=*/false, 612*097a140dSpatrick TheColorMode) 61309467b48Spatrick << format_decimal(Line, LabelWidth) << ": "; 61409467b48Spatrick 61509467b48Spatrick // For the case where -v and colors are enabled, find the annotations for 61609467b48Spatrick // good matches for expected patterns in order to highlight everything 61709467b48Spatrick // else in the line. There are no such annotations if -v is disabled. 61809467b48Spatrick std::vector<InputAnnotation> FoundAndExpectedMatches; 619*097a140dSpatrick if (Req.Verbose && TheColorMode == ColorMode::Enable) { 62009467b48Spatrick for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line; 62109467b48Spatrick ++I) { 62209467b48Spatrick if (I->FoundAndExpectedMatch) 62309467b48Spatrick FoundAndExpectedMatches.push_back(*I); 62409467b48Spatrick } 62509467b48Spatrick } 62609467b48Spatrick 62709467b48Spatrick // Print numbered line with highlighting where there are no matches for 62809467b48Spatrick // expected patterns. 62909467b48Spatrick bool Newline = false; 63009467b48Spatrick { 631*097a140dSpatrick WithColor COS(*LineOS, raw_ostream::SAVEDCOLOR, /*Bold=*/false, 632*097a140dSpatrick /*BG=*/false, TheColorMode); 63309467b48Spatrick bool InMatch = false; 63409467b48Spatrick if (Req.Verbose) 63509467b48Spatrick COS.changeColor(raw_ostream::CYAN, true, true); 63609467b48Spatrick for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) { 63709467b48Spatrick bool WasInMatch = InMatch; 63809467b48Spatrick InMatch = false; 63909467b48Spatrick for (auto M : FoundAndExpectedMatches) { 64009467b48Spatrick if (M.InputStartCol <= Col && Col < M.InputEndCol) { 64109467b48Spatrick InMatch = true; 64209467b48Spatrick break; 64309467b48Spatrick } 64409467b48Spatrick } 64509467b48Spatrick if (!WasInMatch && InMatch) 64609467b48Spatrick COS.resetColor(); 64709467b48Spatrick else if (WasInMatch && !InMatch) 64809467b48Spatrick COS.changeColor(raw_ostream::CYAN, true, true); 64909467b48Spatrick if (*InputFilePtr == '\n') 65009467b48Spatrick Newline = true; 65109467b48Spatrick else 65209467b48Spatrick COS << *InputFilePtr; 65309467b48Spatrick ++InputFilePtr; 65409467b48Spatrick } 65509467b48Spatrick } 656*097a140dSpatrick *LineOS << '\n'; 65709467b48Spatrick unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline; 65809467b48Spatrick 65909467b48Spatrick // Print any annotations. 66009467b48Spatrick while (AnnotationItr != AnnotationEnd && 66109467b48Spatrick AnnotationItr->InputLine == Line) { 662*097a140dSpatrick WithColor COS(*LineOS, AnnotationItr->Marker.Color, /*Bold=*/true, 663*097a140dSpatrick /*BG=*/false, TheColorMode); 66409467b48Spatrick // The two spaces below are where the ": " appears on input lines. 66509467b48Spatrick COS << left_justify(AnnotationItr->Label, LabelWidth) << " "; 66609467b48Spatrick unsigned Col; 66709467b48Spatrick for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col) 66809467b48Spatrick COS << ' '; 66909467b48Spatrick COS << AnnotationItr->Marker.Lead; 67009467b48Spatrick // If InputEndCol=UINT_MAX, stop at InputLineWidth. 67109467b48Spatrick for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth; 67209467b48Spatrick ++Col) 67309467b48Spatrick COS << '~'; 67409467b48Spatrick const std::string &Note = AnnotationItr->Marker.Note; 67509467b48Spatrick if (!Note.empty()) { 67609467b48Spatrick // Put the note at the end of the input line. If we were to instead 67709467b48Spatrick // put the note right after the marker, subsequent annotations for the 67809467b48Spatrick // same input line might appear to mark this note instead of the input 67909467b48Spatrick // line. 68009467b48Spatrick for (; Col <= InputLineWidth; ++Col) 68109467b48Spatrick COS << ' '; 68209467b48Spatrick COS << ' ' << Note; 68309467b48Spatrick } 68409467b48Spatrick COS << '\n'; 68509467b48Spatrick ++AnnotationItr; 68609467b48Spatrick } 68709467b48Spatrick } 688*097a140dSpatrick DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth); 68909467b48Spatrick 69009467b48Spatrick OS << ">>>>>>\n"; 69109467b48Spatrick } 69209467b48Spatrick 69309467b48Spatrick int main(int argc, char **argv) { 69409467b48Spatrick // Enable use of ANSI color codes because FileCheck is using them to 69509467b48Spatrick // highlight text. 69609467b48Spatrick llvm::sys::Process::UseANSIEscapeCodes(true); 69709467b48Spatrick 69809467b48Spatrick InitLLVM X(argc, argv); 69909467b48Spatrick cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr, 70009467b48Spatrick "FILECHECK_OPTS"); 701*097a140dSpatrick 702*097a140dSpatrick // Select -dump-input* values. The -help documentation specifies the default 703*097a140dSpatrick // value and which value to choose if an option is specified multiple times. 704*097a140dSpatrick // In the latter case, the general rule of thumb is to choose the value that 705*097a140dSpatrick // provides the most information. 70609467b48Spatrick DumpInputValue DumpInput = 70709467b48Spatrick DumpInputs.empty() 708*097a140dSpatrick ? DumpInputFail 70909467b48Spatrick : *std::max_element(DumpInputs.begin(), DumpInputs.end()); 710*097a140dSpatrick DumpInputFilterValue DumpInputFilter; 711*097a140dSpatrick if (DumpInputFilters.empty()) 712*097a140dSpatrick DumpInputFilter = DumpInput == DumpInputAlways ? DumpInputFilterAll 713*097a140dSpatrick : DumpInputFilterError; 714*097a140dSpatrick else 715*097a140dSpatrick DumpInputFilter = 716*097a140dSpatrick *std::max_element(DumpInputFilters.begin(), DumpInputFilters.end()); 717*097a140dSpatrick unsigned DumpInputContext = DumpInputContexts.empty() 718*097a140dSpatrick ? 5 719*097a140dSpatrick : *std::max_element(DumpInputContexts.begin(), 720*097a140dSpatrick DumpInputContexts.end()); 721*097a140dSpatrick 72209467b48Spatrick if (DumpInput == DumpInputHelp) { 72309467b48Spatrick DumpInputAnnotationHelp(outs()); 72409467b48Spatrick return 0; 72509467b48Spatrick } 72609467b48Spatrick if (CheckFilename.empty()) { 72709467b48Spatrick errs() << "<check-file> not specified\n"; 72809467b48Spatrick return 2; 72909467b48Spatrick } 73009467b48Spatrick 73109467b48Spatrick FileCheckRequest Req; 732*097a140dSpatrick for (StringRef Prefix : CheckPrefixes) 73309467b48Spatrick Req.CheckPrefixes.push_back(Prefix); 73409467b48Spatrick 735*097a140dSpatrick for (StringRef Prefix : CommentPrefixes) 736*097a140dSpatrick Req.CommentPrefixes.push_back(Prefix); 737*097a140dSpatrick 738*097a140dSpatrick for (StringRef CheckNot : ImplicitCheckNot) 73909467b48Spatrick Req.ImplicitCheckNot.push_back(CheckNot); 74009467b48Spatrick 74109467b48Spatrick bool GlobalDefineError = false; 742*097a140dSpatrick for (StringRef G : GlobalDefines) { 74309467b48Spatrick size_t EqIdx = G.find('='); 74409467b48Spatrick if (EqIdx == std::string::npos) { 74509467b48Spatrick errs() << "Missing equal sign in command-line definition '-D" << G 74609467b48Spatrick << "'\n"; 74709467b48Spatrick GlobalDefineError = true; 74809467b48Spatrick continue; 74909467b48Spatrick } 75009467b48Spatrick if (EqIdx == 0) { 75109467b48Spatrick errs() << "Missing variable name in command-line definition '-D" << G 75209467b48Spatrick << "'\n"; 75309467b48Spatrick GlobalDefineError = true; 75409467b48Spatrick continue; 75509467b48Spatrick } 75609467b48Spatrick Req.GlobalDefines.push_back(G); 75709467b48Spatrick } 75809467b48Spatrick if (GlobalDefineError) 75909467b48Spatrick return 2; 76009467b48Spatrick 76109467b48Spatrick Req.AllowEmptyInput = AllowEmptyInput; 76209467b48Spatrick Req.EnableVarScope = EnableVarScope; 76309467b48Spatrick Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap; 76409467b48Spatrick Req.Verbose = Verbose; 76509467b48Spatrick Req.VerboseVerbose = VerboseVerbose; 76609467b48Spatrick Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace; 76709467b48Spatrick Req.MatchFullLines = MatchFullLines; 76809467b48Spatrick Req.IgnoreCase = IgnoreCase; 76909467b48Spatrick 77009467b48Spatrick if (VerboseVerbose) 77109467b48Spatrick Req.Verbose = true; 77209467b48Spatrick 77309467b48Spatrick FileCheck FC(Req); 774*097a140dSpatrick if (!FC.ValidateCheckPrefixes()) 77509467b48Spatrick return 2; 77609467b48Spatrick 77709467b48Spatrick Regex PrefixRE = FC.buildCheckPrefixRegex(); 77809467b48Spatrick std::string REError; 77909467b48Spatrick if (!PrefixRE.isValid(REError)) { 78009467b48Spatrick errs() << "Unable to combine check-prefix strings into a prefix regular " 78109467b48Spatrick "expression! This is likely a bug in FileCheck's verification of " 78209467b48Spatrick "the check-prefix strings. Regular expression parsing failed " 78309467b48Spatrick "with the following error: " 78409467b48Spatrick << REError << "\n"; 78509467b48Spatrick return 2; 78609467b48Spatrick } 78709467b48Spatrick 78809467b48Spatrick SourceMgr SM; 78909467b48Spatrick 79009467b48Spatrick // Read the expected strings from the check file. 79109467b48Spatrick ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr = 79209467b48Spatrick MemoryBuffer::getFileOrSTDIN(CheckFilename); 79309467b48Spatrick if (std::error_code EC = CheckFileOrErr.getError()) { 79409467b48Spatrick errs() << "Could not open check file '" << CheckFilename 79509467b48Spatrick << "': " << EC.message() << '\n'; 79609467b48Spatrick return 2; 79709467b48Spatrick } 79809467b48Spatrick MemoryBuffer &CheckFile = *CheckFileOrErr.get(); 79909467b48Spatrick 80009467b48Spatrick SmallString<4096> CheckFileBuffer; 80109467b48Spatrick StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer); 80209467b48Spatrick 803*097a140dSpatrick unsigned CheckFileBufferID = 80409467b48Spatrick SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer( 80509467b48Spatrick CheckFileText, CheckFile.getBufferIdentifier()), 80609467b48Spatrick SMLoc()); 80709467b48Spatrick 808*097a140dSpatrick std::pair<unsigned, unsigned> ImpPatBufferIDRange; 809*097a140dSpatrick if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange)) 81009467b48Spatrick return 2; 81109467b48Spatrick 81209467b48Spatrick // Open the file to check and add it to SourceMgr. 81309467b48Spatrick ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr = 81409467b48Spatrick MemoryBuffer::getFileOrSTDIN(InputFilename); 815*097a140dSpatrick if (InputFilename == "-") 816*097a140dSpatrick InputFilename = "<stdin>"; // Overwrite for improved diagnostic messages 81709467b48Spatrick if (std::error_code EC = InputFileOrErr.getError()) { 81809467b48Spatrick errs() << "Could not open input file '" << InputFilename 81909467b48Spatrick << "': " << EC.message() << '\n'; 82009467b48Spatrick return 2; 82109467b48Spatrick } 82209467b48Spatrick MemoryBuffer &InputFile = *InputFileOrErr.get(); 82309467b48Spatrick 82409467b48Spatrick if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) { 82509467b48Spatrick errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; 82609467b48Spatrick DumpCommandLine(argc, argv); 82709467b48Spatrick return 2; 82809467b48Spatrick } 82909467b48Spatrick 83009467b48Spatrick SmallString<4096> InputFileBuffer; 83109467b48Spatrick StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer); 83209467b48Spatrick 83309467b48Spatrick SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer( 83409467b48Spatrick InputFileText, InputFile.getBufferIdentifier()), 83509467b48Spatrick SMLoc()); 83609467b48Spatrick 83709467b48Spatrick std::vector<FileCheckDiag> Diags; 83809467b48Spatrick int ExitCode = FC.checkInput(SM, InputFileText, 83909467b48Spatrick DumpInput == DumpInputNever ? nullptr : &Diags) 84009467b48Spatrick ? EXIT_SUCCESS 84109467b48Spatrick : 1; 84209467b48Spatrick if (DumpInput == DumpInputAlways || 84309467b48Spatrick (ExitCode == 1 && DumpInput == DumpInputFail)) { 84409467b48Spatrick errs() << "\n" 845*097a140dSpatrick << "Input file: " << InputFilename << "\n" 84609467b48Spatrick << "Check file: " << CheckFilename << "\n" 84709467b48Spatrick << "\n" 848*097a140dSpatrick << "-dump-input=help explains the following input dump.\n" 84909467b48Spatrick << "\n"; 85009467b48Spatrick std::vector<InputAnnotation> Annotations; 85109467b48Spatrick unsigned LabelWidth; 852*097a140dSpatrick BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags, 853*097a140dSpatrick Annotations, LabelWidth); 854*097a140dSpatrick DumpAnnotatedInput(errs(), Req, DumpInputFilter, DumpInputContext, 855*097a140dSpatrick InputFileText, Annotations, LabelWidth); 85609467b48Spatrick } 85709467b48Spatrick 85809467b48Spatrick return ExitCode; 85909467b48Spatrick } 860