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