1 //===- FileCheck.cpp - Check that File's Contents match what is expected --===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // FileCheck does a line-by line check of a file that validates whether it
11 // contains the expected content.  This is useful for regression tests etc.
12 //
13 // This program exits with an exit status of 2 on error, exit status of 0 if
14 // the file matched the expected contents, and exit status of 1 if it did not
15 // contain the expected contents.
16 //
17 //===----------------------------------------------------------------------===//
18 
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Support/InitLLVM.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include "llvm/Support/FileCheck.h"
23 using namespace llvm;
24 
25 static cl::opt<std::string>
26     CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Required);
27 
28 static cl::opt<std::string>
29     InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
30                   cl::init("-"), cl::value_desc("filename"));
31 
32 static cl::list<std::string> CheckPrefixes(
33     "check-prefix",
34     cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
35 static cl::alias CheckPrefixesAlias(
36     "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
37     cl::NotHidden,
38     cl::desc(
39         "Alias for -check-prefix permitting multiple comma separated values"));
40 
41 static cl::opt<bool> NoCanonicalizeWhiteSpace(
42     "strict-whitespace",
43     cl::desc("Do not treat all horizontal whitespace as equivalent"));
44 
45 static cl::list<std::string> ImplicitCheckNot(
46     "implicit-check-not",
47     cl::desc("Add an implicit negative check with this pattern to every\n"
48              "positive check. This can be used to ensure that no instances of\n"
49              "this pattern occur which are not matched by a positive pattern"),
50     cl::value_desc("pattern"));
51 
52 static cl::list<std::string> GlobalDefines("D", cl::Prefix,
53     cl::desc("Define a variable to be used in capture patterns."),
54     cl::value_desc("VAR=VALUE"));
55 
56 static cl::opt<bool> AllowEmptyInput(
57     "allow-empty", cl::init(false),
58     cl::desc("Allow the input file to be empty. This is useful when making\n"
59              "checks that some error message does not occur, for example."));
60 
61 static cl::opt<bool> MatchFullLines(
62     "match-full-lines", cl::init(false),
63     cl::desc("Require all positive matches to cover an entire input line.\n"
64              "Allows leading and trailing whitespace if --strict-whitespace\n"
65              "is not also passed."));
66 
67 static cl::opt<bool> EnableVarScope(
68     "enable-var-scope", cl::init(false),
69     cl::desc("Enables scope for regex variables. Variables with names that\n"
70              "do not start with '$' will be reset at the beginning of\n"
71              "each CHECK-LABEL block."));
72 
73 static cl::opt<bool> AllowDeprecatedDagOverlap(
74     "allow-deprecated-dag-overlap", cl::init(false),
75     cl::desc("Enable overlapping among matches in a group of consecutive\n"
76              "CHECK-DAG directives.  This option is deprecated and is only\n"
77              "provided for convenience as old tests are migrated to the new\n"
78              "non-overlapping CHECK-DAG implementation.\n"));
79 
80 static cl::opt<bool> Verbose("v", cl::init(false),
81                              cl::desc("Print directive pattern matches.\n"));
82 
83 static cl::opt<bool> VerboseVerbose(
84     "vv", cl::init(false),
85     cl::desc("Print information helpful in diagnosing internal FileCheck\n"
86              "issues.  Implies -v.\n"));
87 static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";
88 
89 static cl::opt<bool> DumpInputOnFailure(
90     "dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)),
91     cl::desc("Dump original input to stderr before failing.\n"
92              "The value can be also controlled using\n"
93              "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"));
94 
95 typedef cl::list<std::string>::const_iterator prefix_iterator;
96 
97 
98 
99 
100 
101 
102 
103 static void DumpCommandLine(int argc, char **argv) {
104   errs() << "FileCheck command line: ";
105   for (int I = 0; I < argc; I++)
106     errs() << " " << argv[I];
107   errs() << "\n";
108 }
109 
110 int main(int argc, char **argv) {
111   InitLLVM X(argc, argv);
112   cl::ParseCommandLineOptions(argc, argv);
113 
114   FileCheckRequest Req;
115   for (auto Prefix : CheckPrefixes)
116     Req.CheckPrefixes.push_back(Prefix);
117 
118   for (auto CheckNot : ImplicitCheckNot)
119     Req.ImplicitCheckNot.push_back(CheckNot);
120 
121   for (auto G : GlobalDefines)
122     Req.GlobalDefines.push_back(G);
123 
124   Req.AllowEmptyInput = AllowEmptyInput;
125   Req.EnableVarScope = EnableVarScope;
126   Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
127   Req.Verbose = Verbose;
128   Req.VerboseVerbose = VerboseVerbose;
129   Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
130   Req.MatchFullLines = MatchFullLines;
131 
132   if (VerboseVerbose)
133     Req.Verbose = true;
134 
135   FileCheck FC(Req);
136   if (!FC.ValidateCheckPrefixes()) {
137     errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
138               "start with a letter and contain only alphanumeric characters, "
139               "hyphens and underscores\n";
140     return 2;
141   }
142 
143   Regex PrefixRE = FC.buildCheckPrefixRegex();
144   std::string REError;
145   if (!PrefixRE.isValid(REError)) {
146     errs() << "Unable to combine check-prefix strings into a prefix regular "
147               "expression! This is likely a bug in FileCheck's verification of "
148               "the check-prefix strings. Regular expression parsing failed "
149               "with the following error: "
150            << REError << "\n";
151     return 2;
152   }
153 
154 
155   SourceMgr SM;
156 
157   // Read the expected strings from the check file.
158   ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
159       MemoryBuffer::getFileOrSTDIN(CheckFilename);
160   if (std::error_code EC = CheckFileOrErr.getError()) {
161     errs() << "Could not open check file '" << CheckFilename
162            << "': " << EC.message() << '\n';
163     return 2;
164   }
165   MemoryBuffer &CheckFile = *CheckFileOrErr.get();
166 
167   SmallString<4096> CheckFileBuffer;
168   StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
169 
170   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
171                             CheckFileText, CheckFile.getBufferIdentifier()),
172                         SMLoc());
173 
174   std::vector<FileCheckString> CheckStrings;
175   if (FC.ReadCheckFile(SM, CheckFileText, PrefixRE, CheckStrings))
176     return 2;
177 
178   // Open the file to check and add it to SourceMgr.
179   ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
180       MemoryBuffer::getFileOrSTDIN(InputFilename);
181   if (std::error_code EC = InputFileOrErr.getError()) {
182     errs() << "Could not open input file '" << InputFilename
183            << "': " << EC.message() << '\n';
184     return 2;
185   }
186   MemoryBuffer &InputFile = *InputFileOrErr.get();
187 
188   if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
189     errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
190     DumpCommandLine(argc, argv);
191     return 2;
192   }
193 
194   SmallString<4096> InputFileBuffer;
195   StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
196 
197   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
198                             InputFileText, InputFile.getBufferIdentifier()),
199                         SMLoc());
200 
201   int ExitCode =
202       FC.CheckInput(SM, InputFileText, CheckStrings) ? EXIT_SUCCESS : 1;
203   if (ExitCode == 1 && DumpInputOnFailure)
204     errs() << "Full input was:\n<<<<<<\n" << InputFileText << "\n>>>>>>\n";
205 
206   return ExitCode;
207 }
208