1 //===- FileCheck.cpp - Check that File's Contents match what is expected --===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
13 // This program exits with an error 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.
17 //===----------------------------------------------------------------------===//
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/PrettyStackTrace.h"
22 #include "llvm/Support/SourceMgr.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include "llvm/System/Signals.h"
27 static cl::opt
<std::string
>
28 CheckFilename(cl::Positional
, cl::desc("<check-file>"), cl::Required
);
30 static cl::opt
<std::string
>
31 InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
32 cl::init("-"), cl::value_desc("filename"));
34 static cl::opt
<std::string
>
35 CheckPrefix("check-prefix", cl::init("CHECK"),
36 cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
39 NoCanonicalizeWhiteSpace("strict-whitespace",
40 cl::desc("Do not treat all horizontal whitespace as equivalent"));
42 /// CheckString - This is a check that we found in the input file.
44 /// Str - The string to match.
47 /// Loc - The location in the match file that the check string was specified.
50 /// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed
51 /// to a CHECK: directive.
54 CheckString(const std::string
&S
, SMLoc L
, bool isCheckNext
)
55 : Str(S
), Loc(L
), IsCheckNext(isCheckNext
) {}
59 /// FindFixedStringInBuffer - This works like strstr, except for two things:
60 /// 1) it handles 'nul' characters in memory buffers. 2) it returns the end of
61 /// the memory buffer on match failure instead of null.
62 static const char *FindFixedStringInBuffer(StringRef Str
, const char *CurPtr
,
63 const MemoryBuffer
&MB
) {
64 assert(!Str
.empty() && "Can't find an empty string");
65 const char *BufEnd
= MB
.getBufferEnd();
68 // Scan for the first character in the match string.
69 CurPtr
= (char*)memchr(CurPtr
, Str
[0], BufEnd
-CurPtr
);
71 // If we didn't find the first character of the string, then we failed to
73 if (CurPtr
== 0) return BufEnd
;
75 // If the match string is one character, then we win.
76 if (Str
.size() == 1) return CurPtr
;
78 // Otherwise, verify that the rest of the string matches.
79 if (Str
.size() <= unsigned(BufEnd
-CurPtr
) &&
80 memcmp(CurPtr
+1, Str
.data()+1, Str
.size()-1) == 0)
83 // If not, advance past this character and try again.
88 /// ReadCheckFile - Read the check file, which specifies the sequence of
89 /// expected strings. The strings are added to the CheckStrings vector.
90 static bool ReadCheckFile(SourceMgr
&SM
,
91 std::vector
<CheckString
> &CheckStrings
) {
92 // Open the check file, and tell SourceMgr about it.
95 MemoryBuffer::getFileOrSTDIN(CheckFilename
.c_str(), &ErrorStr
);
97 errs() << "Could not open check file '" << CheckFilename
<< "': "
101 SM
.AddNewSourceBuffer(F
, SMLoc());
103 // Find all instances of CheckPrefix followed by : in the file.
104 const char *CurPtr
= F
->getBufferStart(), *BufferEnd
= F
->getBufferEnd();
107 // See if Prefix occurs in the memory buffer.
108 const char *Ptr
= FindFixedStringInBuffer(CheckPrefix
, CurPtr
, *F
);
110 // If we didn't find a match, we're done.
111 if (Ptr
== BufferEnd
)
114 const char *CheckPrefixStart
= Ptr
;
116 // When we find a check prefix, keep track of whether we find CHECK: or
120 // Verify that the : is present after the prefix.
121 if (Ptr
[CheckPrefix
.size()] == ':') {
122 Ptr
+= CheckPrefix
.size()+1;
124 } else if (BufferEnd
-Ptr
> 6 &&
125 memcmp(Ptr
+CheckPrefix
.size(), "-NEXT:", 6) == 0) {
126 Ptr
+= CheckPrefix
.size()+7;
133 // Okay, we found the prefix, yay. Remember the rest of the line, but
134 // ignore leading and trailing whitespace.
135 while (*Ptr
== ' ' || *Ptr
== '\t')
138 // Scan ahead to the end of line.
140 while (CurPtr
!= BufferEnd
&& *CurPtr
!= '\n' && *CurPtr
!= '\r')
143 // Ignore trailing whitespace.
144 while (CurPtr
[-1] == ' ' || CurPtr
[-1] == '\t')
147 // Check that there is something on the line.
149 SM
.PrintMessage(SMLoc::getFromPointer(CurPtr
),
150 "found empty check string with prefix '"+CheckPrefix
+":'",
155 // Verify that CHECK-NEXT lines have at least one CHECK line before them.
156 if (IsCheckNext
&& CheckStrings
.empty()) {
157 SM
.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart
),
158 "found '"+CheckPrefix
+"-NEXT:' without previous '"+
159 CheckPrefix
+ ": line", "error");
163 // Okay, add the string we captured to the output vector and move on.
164 CheckStrings
.push_back(CheckString(std::string(Ptr
, CurPtr
),
165 SMLoc::getFromPointer(Ptr
),
169 if (CheckStrings
.empty()) {
170 errs() << "error: no check strings found with prefix '" << CheckPrefix
178 // CanonicalizeCheckStrings - Replace all sequences of horizontal whitespace in
179 // the check strings with a single space.
180 static void CanonicalizeCheckStrings(std::vector
<CheckString
> &CheckStrings
) {
181 for (unsigned i
= 0, e
= CheckStrings
.size(); i
!= e
; ++i
) {
182 std::string
&Str
= CheckStrings
[i
].Str
;
184 for (unsigned C
= 0; C
!= Str
.size(); ++C
) {
185 // If C is not a horizontal whitespace, skip it.
186 if (Str
[C
] != ' ' && Str
[C
] != '\t')
189 // Replace the character with space, then remove any other space
190 // characters after it.
193 while (C
+1 != Str
.size() &&
194 (Str
[C
+1] == ' ' || Str
[C
+1] == '\t'))
195 Str
.erase(Str
.begin()+C
+1);
200 /// CanonicalizeInputFile - Remove duplicate horizontal space from the specified
201 /// memory buffer, free it, and return a new one.
202 static MemoryBuffer
*CanonicalizeInputFile(MemoryBuffer
*MB
) {
203 SmallVector
<char, 16> NewFile
;
204 NewFile
.reserve(MB
->getBufferSize());
206 for (const char *Ptr
= MB
->getBufferStart(), *End
= MB
->getBufferEnd();
208 // If C is not a horizontal whitespace, skip it.
209 if (*Ptr
!= ' ' && *Ptr
!= '\t') {
210 NewFile
.push_back(*Ptr
);
214 // Otherwise, add one space and advance over neighboring space.
215 NewFile
.push_back(' ');
216 while (Ptr
+1 != End
&&
217 (Ptr
[1] == ' ' || Ptr
[1] == '\t'))
221 // Free the old buffer and return a new one.
223 MemoryBuffer::getMemBufferCopy(NewFile
.data(),
224 NewFile
.data() + NewFile
.size(),
225 MB
->getBufferIdentifier());
232 static void PrintCheckFailed(const SourceMgr
&SM
, const CheckString
&CheckStr
,
233 const char *CurPtr
, const char *BufferEnd
) {
234 // Otherwise, we have an error, emit an error message.
235 SM
.PrintMessage(CheckStr
.Loc
, "expected string not found in input",
238 // Print the "scanning from here" line. If the current position is at the
239 // end of a line, advance to the start of the next line.
240 const char *Scan
= CurPtr
;
241 while (Scan
!= BufferEnd
&&
242 (*Scan
== ' ' || *Scan
== '\t'))
244 if (*Scan
== '\n' || *Scan
== '\r')
248 SM
.PrintMessage(SMLoc::getFromPointer(CurPtr
), "scanning from here",
252 static unsigned CountNumNewlinesBetween(const char *Start
, const char *End
) {
253 unsigned NumNewLines
= 0;
254 for (; Start
!= End
; ++Start
) {
256 if (Start
[0] != '\n' && Start
[0] != '\r')
261 // Handle \n\r and \r\n as a single newline.
262 if (Start
+1 != End
&&
263 (Start
[0] == '\n' || Start
[0] == '\r') &&
264 (Start
[0] != Start
[1]))
271 int main(int argc
, char **argv
) {
272 sys::PrintStackTraceOnErrorSignal();
273 PrettyStackTraceProgram
X(argc
, argv
);
274 cl::ParseCommandLineOptions(argc
, argv
);
278 // Read the expected strings from the check file.
279 std::vector
<CheckString
> CheckStrings
;
280 if (ReadCheckFile(SM
, CheckStrings
))
283 // Remove duplicate spaces in the check strings if requested.
284 if (!NoCanonicalizeWhiteSpace
)
285 CanonicalizeCheckStrings(CheckStrings
);
287 // Open the file to check and add it to SourceMgr.
288 std::string ErrorStr
;
290 MemoryBuffer::getFileOrSTDIN(InputFilename
.c_str(), &ErrorStr
);
292 errs() << "Could not open input file '" << InputFilename
<< "': "
297 // Remove duplicate spaces in the input file if requested.
298 if (!NoCanonicalizeWhiteSpace
)
299 F
= CanonicalizeInputFile(F
);
301 SM
.AddNewSourceBuffer(F
, SMLoc());
303 // Check that we have all of the expected strings, in order, in the input
305 const char *CurPtr
= F
->getBufferStart(), *BufferEnd
= F
->getBufferEnd();
307 const char *LastMatch
= 0;
308 for (unsigned StrNo
= 0, e
= CheckStrings
.size(); StrNo
!= e
; ++StrNo
) {
309 const CheckString
&CheckStr
= CheckStrings
[StrNo
];
311 // Find StrNo in the file.
312 const char *Ptr
= FindFixedStringInBuffer(CheckStr
.Str
, CurPtr
, *F
);
314 // If we didn't find a match, reject the input.
315 if (Ptr
== BufferEnd
) {
316 PrintCheckFailed(SM
, CheckStr
, CurPtr
, BufferEnd
);
320 // If this check is a "CHECK-NEXT", verify that the previous match was on
321 // the previous line (i.e. that there is one newline between them).
322 if (CheckStr
.IsCheckNext
) {
323 // Count the number of newlines between the previous match and this one.
324 assert(LastMatch
&& "CHECK-NEXT can't be the first check in a file");
326 unsigned NumNewLines
= CountNumNewlinesBetween(LastMatch
, Ptr
);
327 if (NumNewLines
== 0) {
328 SM
.PrintMessage(CheckStr
.Loc
,
329 CheckPrefix
+"-NEXT: is on the same line as previous match",
331 SM
.PrintMessage(SMLoc::getFromPointer(Ptr
),
332 "'next' match was here", "note");
333 SM
.PrintMessage(SMLoc::getFromPointer(LastMatch
),
334 "previous match was here", "note");
338 if (NumNewLines
!= 1) {
339 SM
.PrintMessage(CheckStr
.Loc
,
341 "-NEXT: is not on the line after the previous match",
343 SM
.PrintMessage(SMLoc::getFromPointer(Ptr
),
344 "'next' match was here", "note");
345 SM
.PrintMessage(SMLoc::getFromPointer(LastMatch
),
346 "previous match was here", "note");
351 // Otherwise, everything is good. Remember this as the last match and move
352 // on to the next one.
354 CurPtr
= Ptr
+ CheckStr
.Str
.size();