xref: /openbsd-src/gnu/llvm/llvm/utils/FileCheck/FileCheck.cpp (revision 097a140d792de8b2bbe59ad827d39eabf9b4280a)
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