turn a std::pair into a real class.
[oota-llvm.git] / utils / FileCheck / FileCheck.cpp
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 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.
16 //
17 //===----------------------------------------------------------------------===//
18
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/PrettyStackTrace.h"
22 #include "llvm/Support/Regex.h"
23 #include "llvm/Support/SourceMgr.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include "llvm/System/Signals.h"
26 using namespace llvm;
27
28 static cl::opt<std::string>
29 CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Required);
30
31 static cl::opt<std::string>
32 InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
33               cl::init("-"), cl::value_desc("filename"));
34
35 static cl::opt<std::string>
36 CheckPrefix("check-prefix", cl::init("CHECK"),
37             cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
38
39 static cl::opt<bool>
40 NoCanonicalizeWhiteSpace("strict-whitespace",
41               cl::desc("Do not treat all horizontal whitespace as equivalent"));
42
43 //===----------------------------------------------------------------------===//
44 // Pattern Handling Code.
45 //===----------------------------------------------------------------------===//
46
47 class PatternChunk {
48   StringRef Str;
49   bool isRegEx;
50 public:
51   PatternChunk(StringRef S, bool isRE) : Str(S), isRegEx(isRE) {}
52   
53   
54   size_t Match(StringRef Buffer, size_t &MatchLen) const {
55     if (!isRegEx) {
56       // Fixed string match.
57       MatchLen = Str.size();
58       return Buffer.find(Str);
59     }
60      
61     // Regex match.
62     SmallVector<StringRef, 4> MatchInfo;
63     if (!Regex(Str, Regex::Sub).match(Buffer, &MatchInfo))
64       return StringRef::npos;
65     
66     // Successful regex match.
67     assert(!MatchInfo.empty() && "Didn't get any match");
68     StringRef FullMatch = MatchInfo[0];
69     
70     MatchLen = FullMatch.size();
71     return FullMatch.data()-Buffer.data();
72   }
73   
74 };
75
76 class Pattern {
77   /// Chunks - The pattern chunks to match.  If the bool is false, it is a fixed
78   /// string match, if it is true, it is a regex match.
79   SmallVector<PatternChunk, 4> Chunks;
80 public:
81   
82   Pattern() { }
83   
84   bool ParsePattern(StringRef PatternStr, SourceMgr &SM);
85   
86   /// Match - Match the pattern string against the input buffer Buffer.  This
87   /// returns the position that is matched or npos if there is no match.  If
88   /// there is a match, the size of the matched string is returned in MatchLen.
89   size_t Match(StringRef Buffer, size_t &MatchLen) const;
90 };
91
92 bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
93   // Ignore trailing whitespace.
94   while (!PatternStr.empty() &&
95          (PatternStr.back() == ' ' || PatternStr.back() == '\t'))
96     PatternStr = PatternStr.substr(0, PatternStr.size()-1);
97   
98   // Check that there is something on the line.
99   if (PatternStr.empty()) {
100     SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
101                     "found empty check string with prefix '"+CheckPrefix+":'",
102                     "error");
103     return true;
104   }
105   
106   // Scan the pattern to break it into regex and non-regex pieces.
107   while (!PatternStr.empty()) {
108     // Handle fixed string matches.
109     if (PatternStr.size() < 2 ||
110         PatternStr[0] != '{' || PatternStr[1] != '{') {
111       // Find the end, which is the start of the next regex.
112       size_t FixedMatchEnd = PatternStr.find("{{");
113       
114       Chunks.push_back(PatternChunk(PatternStr.substr(0, FixedMatchEnd),false));
115       PatternStr = PatternStr.substr(FixedMatchEnd);
116       continue;
117     }
118     
119     // Otherwise, this is the start of a regex match.  Scan for the }}.
120     size_t End = PatternStr.find("}}");
121     if (End == StringRef::npos) {
122       SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
123                       "found start of regex string with no end '}}'", "error");
124       return true;
125     }
126     
127     Regex R(PatternStr.substr(2, End-2));
128     std::string Error;
129     if (!R.isValid(Error)) {
130       SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()+2),
131                       "invalid regex: " + Error, "error");
132       return true;
133     }
134     
135     Chunks.push_back(PatternChunk(PatternStr.substr(2, End-2), true));
136     PatternStr = PatternStr.substr(End+2);
137   }
138
139   return false;
140 }
141
142 /// Match - Match the pattern string against the input buffer Buffer.  This
143 /// returns the position that is matched or npos if there is no match.  If
144 /// there is a match, the size of the matched string is returned in MatchLen.
145 size_t Pattern::Match(StringRef Buffer, size_t &MatchLen) const {
146   size_t FirstMatch = StringRef::npos;
147   MatchLen = 0;
148   
149   while (!Buffer.empty()) {
150     StringRef MatchAttempt = Buffer;
151     
152     unsigned ChunkNo = 0, e = Chunks.size();
153     for (; ChunkNo != e; ++ChunkNo) {
154       size_t ThisMatch, ThisLength = StringRef::npos;
155       ThisMatch = Chunks[ChunkNo].Match(MatchAttempt, ThisLength);
156       
157       // Otherwise, what we do depends on if this is the first match or not.  If
158       // this is the first match, it doesn't match to match at the start of
159       // MatchAttempt.
160       if (ChunkNo == 0) {
161         // If the first match fails then this pattern will never match in
162         // Buffer.
163         if (ThisMatch == StringRef::npos)
164           return ThisMatch;
165         
166         FirstMatch = ThisMatch;
167         MatchAttempt = MatchAttempt.substr(FirstMatch);
168         ThisMatch = 0;
169       }
170       
171       // If this chunk didn't match, then the entire pattern didn't match from
172       // FirstMatch, try later in the buffer.
173       if (ThisMatch == StringRef::npos)
174         break;
175       
176       // Ok, if the match didn't match at the beginning of MatchAttempt, then we
177       // have something like "ABC{{DEF}} and something was in-between.  Reject
178       // the match.
179       if (ThisMatch != 0)
180         break;
181       
182       // Otherwise, match the string and move to the next chunk.
183       MatchLen += ThisLength;
184       MatchAttempt = MatchAttempt.substr(ThisLength);
185     }
186
187     // If the whole thing matched, we win.
188     if (ChunkNo == e)
189       return FirstMatch;
190     
191     // Otherwise, try matching again after FirstMatch to see if this pattern
192     // matches later in the buffer.
193     Buffer = Buffer.substr(FirstMatch+1);
194   }
195   
196   // If we ran out of stuff to scan, then we didn't match.
197   return StringRef::npos;
198 }
199
200
201 //===----------------------------------------------------------------------===//
202 // Check Strings.
203 //===----------------------------------------------------------------------===//
204
205 /// CheckString - This is a check that we found in the input file.
206 struct CheckString {
207   /// Pat - The pattern to match.
208   Pattern Pat;
209   
210   /// Loc - The location in the match file that the check string was specified.
211   SMLoc Loc;
212   
213   /// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed
214   /// to a CHECK: directive.
215   bool IsCheckNext;
216   
217   /// NotStrings - These are all of the strings that are disallowed from
218   /// occurring between this match string and the previous one (or start of
219   /// file).
220   std::vector<std::pair<SMLoc, Pattern> > NotStrings;
221   
222   CheckString(const Pattern &P, SMLoc L, bool isCheckNext)
223     : Pat(P), Loc(L), IsCheckNext(isCheckNext) {}
224 };
225
226 /// CanonicalizeInputFile - Remove duplicate horizontal space from the specified
227 /// memory buffer, free it, and return a new one.
228 static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
229   SmallVector<char, 16> NewFile;
230   NewFile.reserve(MB->getBufferSize());
231   
232   for (const char *Ptr = MB->getBufferStart(), *End = MB->getBufferEnd();
233        Ptr != End; ++Ptr) {
234     // If C is not a horizontal whitespace, skip it.
235     if (*Ptr != ' ' && *Ptr != '\t') {
236       NewFile.push_back(*Ptr);
237       continue;
238     }
239     
240     // Otherwise, add one space and advance over neighboring space.
241     NewFile.push_back(' ');
242     while (Ptr+1 != End &&
243            (Ptr[1] == ' ' || Ptr[1] == '\t'))
244       ++Ptr;
245   }
246   
247   // Free the old buffer and return a new one.
248   MemoryBuffer *MB2 =
249     MemoryBuffer::getMemBufferCopy(NewFile.data(), 
250                                    NewFile.data() + NewFile.size(),
251                                    MB->getBufferIdentifier());
252   
253   delete MB;
254   return MB2;
255 }
256
257
258 /// ReadCheckFile - Read the check file, which specifies the sequence of
259 /// expected strings.  The strings are added to the CheckStrings vector.
260 static bool ReadCheckFile(SourceMgr &SM,
261                           std::vector<CheckString> &CheckStrings) {
262   // Open the check file, and tell SourceMgr about it.
263   std::string ErrorStr;
264   MemoryBuffer *F =
265     MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), &ErrorStr);
266   if (F == 0) {
267     errs() << "Could not open check file '" << CheckFilename << "': " 
268            << ErrorStr << '\n';
269     return true;
270   }
271   
272   // If we want to canonicalize whitespace, strip excess whitespace from the
273   // buffer containing the CHECK lines.
274   if (!NoCanonicalizeWhiteSpace)
275     F = CanonicalizeInputFile(F);
276   
277   SM.AddNewSourceBuffer(F, SMLoc());
278
279   // Find all instances of CheckPrefix followed by : in the file.
280   StringRef Buffer = F->getBuffer();
281
282   std::vector<std::pair<SMLoc, Pattern> > NotMatches;
283   
284   while (1) {
285     // See if Prefix occurs in the memory buffer.
286     Buffer = Buffer.substr(Buffer.find(CheckPrefix));
287     
288     // If we didn't find a match, we're done.
289     if (Buffer.empty())
290       break;
291     
292     const char *CheckPrefixStart = Buffer.data();
293     
294     // When we find a check prefix, keep track of whether we find CHECK: or
295     // CHECK-NEXT:
296     bool IsCheckNext = false, IsCheckNot = false;
297     
298     // Verify that the : is present after the prefix.
299     if (Buffer[CheckPrefix.size()] == ':') {
300       Buffer = Buffer.substr(CheckPrefix.size()+1);
301     } else if (Buffer.size() > CheckPrefix.size()+6 &&
302                memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) {
303       Buffer = Buffer.substr(CheckPrefix.size()+7);
304       IsCheckNext = true;
305     } else if (Buffer.size() > CheckPrefix.size()+5 &&
306                memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) {
307       Buffer = Buffer.substr(CheckPrefix.size()+6);
308       IsCheckNot = true;
309     } else {
310       Buffer = Buffer.substr(1);
311       continue;
312     }
313     
314     // Okay, we found the prefix, yay.  Remember the rest of the line, but
315     // ignore leading and trailing whitespace.
316     Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
317     
318     // Scan ahead to the end of line.
319     size_t EOL = Buffer.find_first_of("\n\r");
320
321     // Parse the pattern.
322     Pattern P;
323     if (P.ParsePattern(Buffer.substr(0, EOL), SM))
324       return true;
325     
326     Buffer = Buffer.substr(EOL);
327
328     
329     // Verify that CHECK-NEXT lines have at least one CHECK line before them.
330     if (IsCheckNext && CheckStrings.empty()) {
331       SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
332                       "found '"+CheckPrefix+"-NEXT:' without previous '"+
333                       CheckPrefix+ ": line", "error");
334       return true;
335     }
336     
337     // Handle CHECK-NOT.
338     if (IsCheckNot) {
339       NotMatches.push_back(std::make_pair(SMLoc::getFromPointer(Buffer.data()),
340                                           P));
341       continue;
342     }
343     
344     
345     // Okay, add the string we captured to the output vector and move on.
346     CheckStrings.push_back(CheckString(P,
347                                        SMLoc::getFromPointer(Buffer.data()),
348                                        IsCheckNext));
349     std::swap(NotMatches, CheckStrings.back().NotStrings);
350   }
351   
352   if (CheckStrings.empty()) {
353     errs() << "error: no check strings found with prefix '" << CheckPrefix
354            << ":'\n";
355     return true;
356   }
357   
358   if (!NotMatches.empty()) {
359     errs() << "error: '" << CheckPrefix
360            << "-NOT:' not supported after last check line.\n";
361     return true;
362   }
363   
364   return false;
365 }
366
367 static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
368                              StringRef Buffer) {
369   // Otherwise, we have an error, emit an error message.
370   SM.PrintMessage(CheckStr.Loc, "expected string not found in input",
371                   "error");
372   
373   // Print the "scanning from here" line.  If the current position is at the
374   // end of a line, advance to the start of the next line.
375   Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));
376   
377   SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), "scanning from here",
378                   "note");
379 }
380
381 /// CountNumNewlinesBetween - Count the number of newlines in the specified
382 /// range.
383 static unsigned CountNumNewlinesBetween(StringRef Range) {
384   unsigned NumNewLines = 0;
385   while (1) {
386     // Scan for newline.
387     Range = Range.substr(Range.find_first_of("\n\r"));
388     if (Range.empty()) return NumNewLines;
389     
390     ++NumNewLines;
391     
392     // Handle \n\r and \r\n as a single newline.
393     if (Range.size() > 1 &&
394         (Range[1] == '\n' || Range[1] == '\r') &&
395         (Range[0] != Range[1]))
396       Range = Range.substr(1);
397     Range = Range.substr(1);
398   }
399 }
400
401 int main(int argc, char **argv) {
402   sys::PrintStackTraceOnErrorSignal();
403   PrettyStackTraceProgram X(argc, argv);
404   cl::ParseCommandLineOptions(argc, argv);
405
406   SourceMgr SM;
407   
408   // Read the expected strings from the check file.
409   std::vector<CheckString> CheckStrings;
410   if (ReadCheckFile(SM, CheckStrings))
411     return 2;
412
413   // Open the file to check and add it to SourceMgr.
414   std::string ErrorStr;
415   MemoryBuffer *F =
416     MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), &ErrorStr);
417   if (F == 0) {
418     errs() << "Could not open input file '" << InputFilename << "': " 
419            << ErrorStr << '\n';
420     return true;
421   }
422   
423   // Remove duplicate spaces in the input file if requested.
424   if (!NoCanonicalizeWhiteSpace)
425     F = CanonicalizeInputFile(F);
426   
427   SM.AddNewSourceBuffer(F, SMLoc());
428   
429   // Check that we have all of the expected strings, in order, in the input
430   // file.
431   StringRef Buffer = F->getBuffer();
432   
433   const char *LastMatch = Buffer.data();
434   
435   for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) {
436     const CheckString &CheckStr = CheckStrings[StrNo];
437     
438     StringRef SearchFrom = Buffer;
439     
440     // Find StrNo in the file.
441     size_t MatchLen = 0;
442     Buffer = Buffer.substr(CheckStr.Pat.Match(Buffer, MatchLen));
443     
444     // If we didn't find a match, reject the input.
445     if (Buffer.empty()) {
446       PrintCheckFailed(SM, CheckStr, SearchFrom);
447       return 1;
448     }
449
450     StringRef SkippedRegion(LastMatch, Buffer.data()-LastMatch);
451
452     // If this check is a "CHECK-NEXT", verify that the previous match was on
453     // the previous line (i.e. that there is one newline between them).
454     if (CheckStr.IsCheckNext) {
455       // Count the number of newlines between the previous match and this one.
456       assert(LastMatch != F->getBufferStart() &&
457              "CHECK-NEXT can't be the first check in a file");
458
459       unsigned NumNewLines = CountNumNewlinesBetween(SkippedRegion);
460       if (NumNewLines == 0) {
461         SM.PrintMessage(CheckStr.Loc,
462                     CheckPrefix+"-NEXT: is on the same line as previous match",
463                         "error");
464         SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
465                         "'next' match was here", "note");
466         SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
467                         "previous match was here", "note");
468         return 1;
469       }
470       
471       if (NumNewLines != 1) {
472         SM.PrintMessage(CheckStr.Loc,
473                         CheckPrefix+
474                         "-NEXT: is not on the line after the previous match",
475                         "error");
476         SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
477                         "'next' match was here", "note");
478         SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
479                         "previous match was here", "note");
480         return 1;
481       }
482     }
483     
484     // If this match had "not strings", verify that they don't exist in the
485     // skipped region.
486     for (unsigned ChunkNo = 0, e = CheckStr.NotStrings.size(); ChunkNo != e; ++ChunkNo) {
487       size_t MatchLen = 0;
488       size_t Pos = CheckStr.NotStrings[ChunkNo].second.Match(SkippedRegion, MatchLen);
489       if (Pos == StringRef::npos) continue;
490      
491       SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos),
492                       CheckPrefix+"-NOT: string occurred!", "error");
493       SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first,
494                       CheckPrefix+"-NOT: pattern specified here", "note");
495       return 1;
496     }
497     
498
499     // Otherwise, everything is good.  Step over the matched text and remember
500     // the position after the match as the end of the last match.
501     Buffer = Buffer.substr(MatchLen);
502     LastMatch = Buffer.data();
503   }
504   
505   return 0;
506 }