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