FileCheck.cpp revision fafe93c8bcbc538573bc5e890f24f9869a11f846
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#include "llvm/ADT/SmallString.h"
27#include "llvm/ADT/StringMap.h"
28#include <algorithm>
29using namespace llvm;
30
31static cl::opt<std::string>
32CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Required);
33
34static cl::opt<std::string>
35InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
36              cl::init("-"), cl::value_desc("filename"));
37
38static cl::opt<std::string>
39CheckPrefix("check-prefix", cl::init("CHECK"),
40            cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
41
42static cl::opt<bool>
43NoCanonicalizeWhiteSpace("strict-whitespace",
44              cl::desc("Do not treat all horizontal whitespace as equivalent"));
45
46//===----------------------------------------------------------------------===//
47// Pattern Handling Code.
48//===----------------------------------------------------------------------===//
49
50class Pattern {
51  SMLoc PatternLoc;
52
53  /// FixedStr - If non-empty, this pattern is a fixed string match with the
54  /// specified fixed string.
55  StringRef FixedStr;
56
57  /// RegEx - If non-empty, this is a regex pattern.
58  std::string RegExStr;
59
60  /// VariableUses - Entries in this vector map to uses of a variable in the
61  /// pattern, e.g. "foo[[bar]]baz".  In this case, the RegExStr will contain
62  /// "foobaz" and we'll get an entry in this vector that tells us to insert the
63  /// value of bar at offset 3.
64  std::vector<std::pair<StringRef, unsigned> > VariableUses;
65
66  /// VariableDefs - Entries in this vector map to definitions of a variable in
67  /// the pattern, e.g. "foo[[bar:.*]]baz".  In this case, the RegExStr will
68  /// contain "foo(.*)baz" and VariableDefs will contain the pair "bar",1.  The
69  /// index indicates what parenthesized value captures the variable value.
70  std::vector<std::pair<StringRef, unsigned> > VariableDefs;
71
72public:
73
74  Pattern() { }
75
76  bool ParsePattern(StringRef PatternStr, SourceMgr &SM);
77
78  /// Match - Match the pattern string against the input buffer Buffer.  This
79  /// returns the position that is matched or npos if there is no match.  If
80  /// there is a match, the size of the matched string is returned in MatchLen.
81  ///
82  /// The VariableTable StringMap provides the current values of filecheck
83  /// variables and is updated if this match defines new values.
84  size_t Match(StringRef Buffer, size_t &MatchLen,
85               StringMap<StringRef> &VariableTable) const;
86
87  /// PrintFailureInfo - Print additional information about a failure to match
88  /// involving this pattern.
89  void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
90                        const StringMap<StringRef> &VariableTable) const;
91
92private:
93  static void AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr);
94  bool AddRegExToRegEx(StringRef RegExStr, unsigned &CurParen, SourceMgr &SM);
95};
96
97
98bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
99  PatternLoc = SMLoc::getFromPointer(PatternStr.data());
100
101  // Ignore trailing whitespace.
102  while (!PatternStr.empty() &&
103         (PatternStr.back() == ' ' || PatternStr.back() == '\t'))
104    PatternStr = PatternStr.substr(0, PatternStr.size()-1);
105
106  // Check that there is something on the line.
107  if (PatternStr.empty()) {
108    SM.PrintMessage(PatternLoc, "found empty check string with prefix '" +
109                    CheckPrefix+":'", "error");
110    return true;
111  }
112
113  // Check to see if this is a fixed string, or if it has regex pieces.
114  if (PatternStr.size() < 2 ||
115      (PatternStr.find("{{") == StringRef::npos &&
116       PatternStr.find("[[") == StringRef::npos)) {
117    FixedStr = PatternStr;
118    return false;
119  }
120
121  // Paren value #0 is for the fully matched string.  Any new parenthesized
122  // values add from their.
123  unsigned CurParen = 1;
124
125  // Otherwise, there is at least one regex piece.  Build up the regex pattern
126  // by escaping scary characters in fixed strings, building up one big regex.
127  while (!PatternStr.empty()) {
128    // RegEx matches.
129    if (PatternStr.size() >= 2 &&
130        PatternStr[0] == '{' && PatternStr[1] == '{') {
131
132      // Otherwise, this is the start of a regex match.  Scan for the }}.
133      size_t End = PatternStr.find("}}");
134      if (End == StringRef::npos) {
135        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
136                        "found start of regex string with no end '}}'", "error");
137        return true;
138      }
139
140      if (AddRegExToRegEx(PatternStr.substr(2, End-2), CurParen, SM))
141        return true;
142      PatternStr = PatternStr.substr(End+2);
143      continue;
144    }
145
146    // Named RegEx matches.  These are of two forms: [[foo:.*]] which matches .*
147    // (or some other regex) and assigns it to the FileCheck variable 'foo'. The
148    // second form is [[foo]] which is a reference to foo.  The variable name
149    // itself must be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject
150    // it.  This is to catch some common errors.
151    if (PatternStr.size() >= 2 &&
152        PatternStr[0] == '[' && PatternStr[1] == '[') {
153      // Verify that it is terminated properly.
154      size_t End = PatternStr.find("]]");
155      if (End == StringRef::npos) {
156        SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
157                        "invalid named regex reference, no ]] found", "error");
158        return true;
159      }
160
161      StringRef MatchStr = PatternStr.substr(2, End-2);
162      PatternStr = PatternStr.substr(End+2);
163
164      // Get the regex name (e.g. "foo").
165      size_t NameEnd = MatchStr.find(':');
166      StringRef Name = MatchStr.substr(0, NameEnd);
167
168      if (Name.empty()) {
169        SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
170                        "invalid name in named regex: empty name", "error");
171        return true;
172      }
173
174      // Verify that the name is well formed.
175      for (unsigned i = 0, e = Name.size(); i != e; ++i)
176        if (Name[i] != '_' &&
177            (Name[i] < 'a' || Name[i] > 'z') &&
178            (Name[i] < 'A' || Name[i] > 'Z') &&
179            (Name[i] < '0' || Name[i] > '9')) {
180          SM.PrintMessage(SMLoc::getFromPointer(Name.data()+i),
181                          "invalid name in named regex", "error");
182          return true;
183        }
184
185      // Name can't start with a digit.
186      if (isdigit(Name[0])) {
187        SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
188                        "invalid name in named regex", "error");
189        return true;
190      }
191
192      // Handle [[foo]].
193      if (NameEnd == StringRef::npos) {
194        VariableUses.push_back(std::make_pair(Name, RegExStr.size()));
195        continue;
196      }
197
198      // Handle [[foo:.*]].
199      VariableDefs.push_back(std::make_pair(Name, CurParen));
200      RegExStr += '(';
201      ++CurParen;
202
203      if (AddRegExToRegEx(MatchStr.substr(NameEnd+1), CurParen, SM))
204        return true;
205
206      RegExStr += ')';
207    }
208
209    // Handle fixed string matches.
210    // Find the end, which is the start of the next regex.
211    size_t FixedMatchEnd = PatternStr.find("{{");
212    FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));
213    AddFixedStringToRegEx(PatternStr.substr(0, FixedMatchEnd), RegExStr);
214    PatternStr = PatternStr.substr(FixedMatchEnd);
215    continue;
216  }
217
218  return false;
219}
220
221void Pattern::AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr) {
222  // Add the characters from FixedStr to the regex, escaping as needed.  This
223  // avoids "leaning toothpicks" in common patterns.
224  for (unsigned i = 0, e = FixedStr.size(); i != e; ++i) {
225    switch (FixedStr[i]) {
226    // These are the special characters matched in "p_ere_exp".
227    case '(':
228    case ')':
229    case '^':
230    case '$':
231    case '|':
232    case '*':
233    case '+':
234    case '?':
235    case '.':
236    case '[':
237    case '\\':
238    case '{':
239      TheStr += '\\';
240      // FALL THROUGH.
241    default:
242      TheStr += FixedStr[i];
243      break;
244    }
245  }
246}
247
248bool Pattern::AddRegExToRegEx(StringRef RegexStr, unsigned &CurParen,
249                              SourceMgr &SM) {
250  Regex R(RegexStr);
251  std::string Error;
252  if (!R.isValid(Error)) {
253    SM.PrintMessage(SMLoc::getFromPointer(RegexStr.data()),
254                    "invalid regex: " + Error, "error");
255    return true;
256  }
257
258  RegExStr += RegexStr.str();
259  CurParen += R.getNumMatches();
260  return false;
261}
262
263/// Match - Match the pattern string against the input buffer Buffer.  This
264/// returns the position that is matched or npos if there is no match.  If
265/// there is a match, the size of the matched string is returned in MatchLen.
266size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
267                      StringMap<StringRef> &VariableTable) const {
268  // If this is a fixed string pattern, just match it now.
269  if (!FixedStr.empty()) {
270    MatchLen = FixedStr.size();
271    return Buffer.find(FixedStr);
272  }
273
274  // Regex match.
275
276  // If there are variable uses, we need to create a temporary string with the
277  // actual value.
278  StringRef RegExToMatch = RegExStr;
279  std::string TmpStr;
280  if (!VariableUses.empty()) {
281    TmpStr = RegExStr;
282
283    unsigned InsertOffset = 0;
284    for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
285      StringMap<StringRef>::iterator it =
286        VariableTable.find(VariableUses[i].first);
287      // If the variable is undefined, return an error.
288      if (it == VariableTable.end())
289        return StringRef::npos;
290
291      // Look up the value and escape it so that we can plop it into the regex.
292      std::string Value;
293      AddFixedStringToRegEx(it->second, Value);
294
295      // Plop it into the regex at the adjusted offset.
296      TmpStr.insert(TmpStr.begin()+VariableUses[i].second+InsertOffset,
297                    Value.begin(), Value.end());
298      InsertOffset += Value.size();
299    }
300
301    // Match the newly constructed regex.
302    RegExToMatch = TmpStr;
303  }
304
305
306  SmallVector<StringRef, 4> MatchInfo;
307  if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo))
308    return StringRef::npos;
309
310  // Successful regex match.
311  assert(!MatchInfo.empty() && "Didn't get any match");
312  StringRef FullMatch = MatchInfo[0];
313
314  // If this defines any variables, remember their values.
315  for (unsigned i = 0, e = VariableDefs.size(); i != e; ++i) {
316    assert(VariableDefs[i].second < MatchInfo.size() &&
317           "Internal paren error");
318    VariableTable[VariableDefs[i].first] = MatchInfo[VariableDefs[i].second];
319  }
320
321  MatchLen = FullMatch.size();
322  return FullMatch.data()-Buffer.data();
323}
324
325void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
326                               const StringMap<StringRef> &VariableTable) const{
327  // If this is a fixed string, do nothing.
328  if (!FixedStr.empty())
329    return;
330
331  // If this was a regular expression using variables, print the current
332  // variable values.
333  if (!VariableUses.empty()) {
334    for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
335      StringRef Var = VariableUses[i].first;
336      StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
337      SmallString<256> Msg;
338      raw_svector_ostream OS(Msg);
339
340      // Check for undefined variable references.
341      if (it == VariableTable.end()) {
342        OS << "uses undefined variable \"";
343        OS.write_escaped(Var) << "\"";;
344      } else {
345        OS << "with variable \"";
346        OS.write_escaped(Var) << "\" equal to \"";
347        OS.write_escaped(it->second) << "\"";
348      }
349
350      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), OS.str(), "note",
351                      /*ShowLine=*/false);
352    }
353  }
354}
355
356//===----------------------------------------------------------------------===//
357// Check Strings.
358//===----------------------------------------------------------------------===//
359
360/// CheckString - This is a check that we found in the input file.
361struct CheckString {
362  /// Pat - The pattern to match.
363  Pattern Pat;
364
365  /// Loc - The location in the match file that the check string was specified.
366  SMLoc Loc;
367
368  /// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed
369  /// to a CHECK: directive.
370  bool IsCheckNext;
371
372  /// NotStrings - These are all of the strings that are disallowed from
373  /// occurring between this match string and the previous one (or start of
374  /// file).
375  std::vector<std::pair<SMLoc, Pattern> > NotStrings;
376
377  CheckString(const Pattern &P, SMLoc L, bool isCheckNext)
378    : Pat(P), Loc(L), IsCheckNext(isCheckNext) {}
379};
380
381/// CanonicalizeInputFile - Remove duplicate horizontal space from the specified
382/// memory buffer, free it, and return a new one.
383static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
384  SmallVector<char, 16> NewFile;
385  NewFile.reserve(MB->getBufferSize());
386
387  for (const char *Ptr = MB->getBufferStart(), *End = MB->getBufferEnd();
388       Ptr != End; ++Ptr) {
389    // If C is not a horizontal whitespace, skip it.
390    if (*Ptr != ' ' && *Ptr != '\t') {
391      NewFile.push_back(*Ptr);
392      continue;
393    }
394
395    // Otherwise, add one space and advance over neighboring space.
396    NewFile.push_back(' ');
397    while (Ptr+1 != End &&
398           (Ptr[1] == ' ' || Ptr[1] == '\t'))
399      ++Ptr;
400  }
401
402  // Free the old buffer and return a new one.
403  MemoryBuffer *MB2 =
404    MemoryBuffer::getMemBufferCopy(NewFile.data(),
405                                   NewFile.data() + NewFile.size(),
406                                   MB->getBufferIdentifier());
407
408  delete MB;
409  return MB2;
410}
411
412
413/// ReadCheckFile - Read the check file, which specifies the sequence of
414/// expected strings.  The strings are added to the CheckStrings vector.
415static bool ReadCheckFile(SourceMgr &SM,
416                          std::vector<CheckString> &CheckStrings) {
417  // Open the check file, and tell SourceMgr about it.
418  std::string ErrorStr;
419  MemoryBuffer *F =
420    MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), &ErrorStr);
421  if (F == 0) {
422    errs() << "Could not open check file '" << CheckFilename << "': "
423           << ErrorStr << '\n';
424    return true;
425  }
426
427  // If we want to canonicalize whitespace, strip excess whitespace from the
428  // buffer containing the CHECK lines.
429  if (!NoCanonicalizeWhiteSpace)
430    F = CanonicalizeInputFile(F);
431
432  SM.AddNewSourceBuffer(F, SMLoc());
433
434  // Find all instances of CheckPrefix followed by : in the file.
435  StringRef Buffer = F->getBuffer();
436
437  std::vector<std::pair<SMLoc, Pattern> > NotMatches;
438
439  while (1) {
440    // See if Prefix occurs in the memory buffer.
441    Buffer = Buffer.substr(Buffer.find(CheckPrefix));
442
443    // If we didn't find a match, we're done.
444    if (Buffer.empty())
445      break;
446
447    const char *CheckPrefixStart = Buffer.data();
448
449    // When we find a check prefix, keep track of whether we find CHECK: or
450    // CHECK-NEXT:
451    bool IsCheckNext = false, IsCheckNot = false;
452
453    // Verify that the : is present after the prefix.
454    if (Buffer[CheckPrefix.size()] == ':') {
455      Buffer = Buffer.substr(CheckPrefix.size()+1);
456    } else if (Buffer.size() > CheckPrefix.size()+6 &&
457               memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) {
458      Buffer = Buffer.substr(CheckPrefix.size()+7);
459      IsCheckNext = true;
460    } else if (Buffer.size() > CheckPrefix.size()+5 &&
461               memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) {
462      Buffer = Buffer.substr(CheckPrefix.size()+6);
463      IsCheckNot = true;
464    } else {
465      Buffer = Buffer.substr(1);
466      continue;
467    }
468
469    // Okay, we found the prefix, yay.  Remember the rest of the line, but
470    // ignore leading and trailing whitespace.
471    Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
472
473    // Scan ahead to the end of line.
474    size_t EOL = Buffer.find_first_of("\n\r");
475
476    // Parse the pattern.
477    Pattern P;
478    if (P.ParsePattern(Buffer.substr(0, EOL), SM))
479      return true;
480
481    Buffer = Buffer.substr(EOL);
482
483
484    // Verify that CHECK-NEXT lines have at least one CHECK line before them.
485    if (IsCheckNext && CheckStrings.empty()) {
486      SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
487                      "found '"+CheckPrefix+"-NEXT:' without previous '"+
488                      CheckPrefix+ ": line", "error");
489      return true;
490    }
491
492    // Handle CHECK-NOT.
493    if (IsCheckNot) {
494      NotMatches.push_back(std::make_pair(SMLoc::getFromPointer(Buffer.data()),
495                                          P));
496      continue;
497    }
498
499
500    // Okay, add the string we captured to the output vector and move on.
501    CheckStrings.push_back(CheckString(P,
502                                       SMLoc::getFromPointer(Buffer.data()),
503                                       IsCheckNext));
504    std::swap(NotMatches, CheckStrings.back().NotStrings);
505  }
506
507  if (CheckStrings.empty()) {
508    errs() << "error: no check strings found with prefix '" << CheckPrefix
509           << ":'\n";
510    return true;
511  }
512
513  if (!NotMatches.empty()) {
514    errs() << "error: '" << CheckPrefix
515           << "-NOT:' not supported after last check line.\n";
516    return true;
517  }
518
519  return false;
520}
521
522static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
523                             StringRef Buffer,
524                             StringMap<StringRef> &VariableTable) {
525  // Otherwise, we have an error, emit an error message.
526  SM.PrintMessage(CheckStr.Loc, "expected string not found in input",
527                  "error");
528
529  // Print the "scanning from here" line.  If the current position is at the
530  // end of a line, advance to the start of the next line.
531  Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));
532
533  SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), "scanning from here",
534                  "note");
535
536  // Allow the pattern to print additional information if desired.
537  CheckStr.Pat.PrintFailureInfo(SM, Buffer, VariableTable);
538}
539
540/// CountNumNewlinesBetween - Count the number of newlines in the specified
541/// range.
542static unsigned CountNumNewlinesBetween(StringRef Range) {
543  unsigned NumNewLines = 0;
544  while (1) {
545    // Scan for newline.
546    Range = Range.substr(Range.find_first_of("\n\r"));
547    if (Range.empty()) return NumNewLines;
548
549    ++NumNewLines;
550
551    // Handle \n\r and \r\n as a single newline.
552    if (Range.size() > 1 &&
553        (Range[1] == '\n' || Range[1] == '\r') &&
554        (Range[0] != Range[1]))
555      Range = Range.substr(1);
556    Range = Range.substr(1);
557  }
558}
559
560int main(int argc, char **argv) {
561  sys::PrintStackTraceOnErrorSignal();
562  PrettyStackTraceProgram X(argc, argv);
563  cl::ParseCommandLineOptions(argc, argv);
564
565  SourceMgr SM;
566
567  // Read the expected strings from the check file.
568  std::vector<CheckString> CheckStrings;
569  if (ReadCheckFile(SM, CheckStrings))
570    return 2;
571
572  // Open the file to check and add it to SourceMgr.
573  std::string ErrorStr;
574  MemoryBuffer *F =
575    MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), &ErrorStr);
576  if (F == 0) {
577    errs() << "Could not open input file '" << InputFilename << "': "
578           << ErrorStr << '\n';
579    return true;
580  }
581
582  // Remove duplicate spaces in the input file if requested.
583  if (!NoCanonicalizeWhiteSpace)
584    F = CanonicalizeInputFile(F);
585
586  SM.AddNewSourceBuffer(F, SMLoc());
587
588  /// VariableTable - This holds all the current filecheck variables.
589  StringMap<StringRef> VariableTable;
590
591  // Check that we have all of the expected strings, in order, in the input
592  // file.
593  StringRef Buffer = F->getBuffer();
594
595  const char *LastMatch = Buffer.data();
596
597  for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) {
598    const CheckString &CheckStr = CheckStrings[StrNo];
599
600    StringRef SearchFrom = Buffer;
601
602    // Find StrNo in the file.
603    size_t MatchLen = 0;
604    Buffer = Buffer.substr(CheckStr.Pat.Match(Buffer, MatchLen, VariableTable));
605
606    // If we didn't find a match, reject the input.
607    if (Buffer.empty()) {
608      PrintCheckFailed(SM, CheckStr, SearchFrom, VariableTable);
609      return 1;
610    }
611
612    StringRef SkippedRegion(LastMatch, Buffer.data()-LastMatch);
613
614    // If this check is a "CHECK-NEXT", verify that the previous match was on
615    // the previous line (i.e. that there is one newline between them).
616    if (CheckStr.IsCheckNext) {
617      // Count the number of newlines between the previous match and this one.
618      assert(LastMatch != F->getBufferStart() &&
619             "CHECK-NEXT can't be the first check in a file");
620
621      unsigned NumNewLines = CountNumNewlinesBetween(SkippedRegion);
622      if (NumNewLines == 0) {
623        SM.PrintMessage(CheckStr.Loc,
624                    CheckPrefix+"-NEXT: is on the same line as previous match",
625                        "error");
626        SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
627                        "'next' match was here", "note");
628        SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
629                        "previous match was here", "note");
630        return 1;
631      }
632
633      if (NumNewLines != 1) {
634        SM.PrintMessage(CheckStr.Loc,
635                        CheckPrefix+
636                        "-NEXT: is not on the line after the previous match",
637                        "error");
638        SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
639                        "'next' match was here", "note");
640        SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
641                        "previous match was here", "note");
642        return 1;
643      }
644    }
645
646    // If this match had "not strings", verify that they don't exist in the
647    // skipped region.
648    for (unsigned ChunkNo = 0, e = CheckStr.NotStrings.size();
649         ChunkNo != e; ++ChunkNo) {
650      size_t MatchLen = 0;
651      size_t Pos = CheckStr.NotStrings[ChunkNo].second.Match(SkippedRegion,
652                                                             MatchLen,
653                                                             VariableTable);
654      if (Pos == StringRef::npos) continue;
655
656      SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos),
657                      CheckPrefix+"-NOT: string occurred!", "error");
658      SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first,
659                      CheckPrefix+"-NOT: pattern specified here", "note");
660      return 1;
661    }
662
663
664    // Otherwise, everything is good.  Step over the matched text and remember
665    // the position after the match as the end of the last match.
666    Buffer = Buffer.substr(MatchLen);
667    LastMatch = Buffer.data();
668  }
669
670  return 0;
671}
672