Allow multiple check prefixes in FileCheck.

This is useful if you want to run multiple variations
of a single test, and the majority of check lines
should be the same.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194343 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matt Arsenault 2013-11-10 02:04:09 +00:00
parent 432bdf6571
commit ee4f5eae1c
15 changed files with 353 additions and 87 deletions

View File

@ -30,11 +30,13 @@ OPTIONS
.. option:: --check-prefix prefix .. option:: --check-prefix prefix
FileCheck searches the contents of ``match-filename`` for patterns to match. FileCheck searches the contents of ``match-filename`` for patterns to
By default, these patterns are prefixed with "``CHECK:``". If you'd like to match. By default, these patterns are prefixed with "``CHECK:``".
use a different prefix (e.g. because the same input file is checking multiple If you'd like to use a different prefix (e.g. because the same input
different tool or options), the :option:`--check-prefix` argument allows you file is checking multiple different tool or options), the
to specify a specific prefix to match. :option:`--check-prefix` argument allows you to specify one or more
prefixes to match. Multiple prefixes are useful for tests which might
change for different run options, but most lines remain the same.
.. option:: --input-file filename .. option:: --input-file filename

View File

@ -0,0 +1,5 @@
; RUN: FileCheck -check-prefix=A -check-prefix=B -input-file %s %s
this is the string to be matched
; B-DAG: this is the string to be {{matched}}

View File

@ -0,0 +1,5 @@
; RUN: FileCheck -check-prefix=B -check-prefix=A -input-file %s %s
this is the string to be matched
; B-DAG: this is the string to be {{matched}}

View File

@ -0,0 +1,7 @@
; RUN: FileCheck -check-prefix=A -input-file %s %s
this should be matched
; B-DAG: foo
; A-DAG: {{this}} should be matched

View File

@ -0,0 +1,27 @@
; RUN: FileCheck -check-prefix=A -check-prefix=B -input-file %s %s
add r10, r1, r2
add r11, r3, r4
mul r5, r10, r11
mul r11, r3, r4
mul r10, r1, r2
add r5, r10, r11
add r11, r3, r4
add r10, r1, r2
mul r5, r10, r11
; B-DAG: add [[REG1:r[0-9]+]], r1, r2
; B-DAG: add [[REG2:r[0-9]+]], r3, r4
; B: mul r5, [[REG1]], [[REG2]]
; A-DAG: mul [[REG1:r[0-9]+]], r1, r2
; A-DAG: mul [[REG2:r[0-9]+]], r3, r4
; A: add r5, [[REG1]], [[REG2]]
; B-DAG: add [[REG1:r[0-9]+]], r1, r2
; B-DAG: add [[REG2:r[0-9]+]], r3, r4
; B-NOT: xor
; B-DAG: mul r5, [[REG1]], [[REG2]]

View File

@ -0,0 +1,7 @@
; RUN: not FileCheck -check-prefix=A -check-prefix=AA -input-file %s %s
this is the string to be matched
this should also be matched
; BAA-DAG: this is the string to be {{matched}}
; BAA-DAG: this should also be {{matched}}

View File

@ -0,0 +1,6 @@
// RUN: FileCheck -check-prefix=ONE -check-prefix=TWO -input-file %s %s
foo
bar
; ONE-LABEL: {{f}}oo
; TWO-NEXT: {{b}}ar

View File

@ -0,0 +1,10 @@
// RUN: FileCheck -check-prefix=B -check-prefix=BOTH -input-file %s %s
// RUN: FileCheck -check-prefix=A -check-prefix=BOTH -input-file %s %s
; A: {{a}}aaaaa
; B: {{b}}bbbb
; BOTH: {{q}}qqqqq
aaaaaa
bbbbb
qqqqqq
ccccc

View File

@ -0,0 +1,11 @@
; RUN: FileCheck -check-prefix=FOO -check-prefix=FOOBAR -check-prefix=BARFOO -input-file %s %s
; RUN: FileCheck -check-prefix=FOOBAR -check-prefix=FOO -check-prefix=BARFOO -input-file %s %s
; RUN: FileCheck -check-prefix=FOOBAR -check-prefix=BARFOO -check-prefix=FOO -input-file %s %s
this is the match
this is another
FOO
FOOBAR
FOOBAR: this is the {{match}}
BARFOO: this is {{another}}

View File

@ -0,0 +1,9 @@
// RUN: FileCheck -check-prefix=AAAOVERLAP -check-prefix=OVERLAP -input-file %s %s
foo
bar
buzz
OVERLAP: foo
AAAOVERLAP: bar
OVERLAP: buzz

View File

@ -0,0 +1,2 @@
RUN: FileCheck -check-prefix=RUN -input-file %s %s
// Prefix is at the first character in the file. The run line then matches itself.

View File

@ -0,0 +1,9 @@
// RUN: FileCheck -check-prefix=ANOTHER-PREFIX -input-file %s %s
// RUN: not FileCheck -check-prefix=PREFIX1 -check-prefix=PREFIX2 -input-file %s %s 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK-NONEXISTENT-PREFIX -check-prefix=ALSO-NONEXISTENT %s
foobar
; ANOTHER-PREFIX: foobar
; We use regex to match the colon so that FileCheck won't think it is a check
; prefix.
; CHECK-NONEXISTENT-PREFIX: error: no check strings found with prefixes 'PREFIX1{{:}}', 'PREFIX2{{:}}'

View File

@ -0,0 +1,7 @@
// RUN: not FileCheck -check-prefix=SOMEPREFIX -input-file %s %s
// RUN: FileCheck -check-prefix=ANOTHER -input-file %s %s
asdf
; SOMEPREFIX: {{t}}his_is_not_asdf
; ANOTHER: {{a}}sdf

View File

@ -1,7 +1,9 @@
// RUN: not FileCheck -check-prefix=A! -input-file %s %s 2>&1 | FileCheck -check-prefix=BAD_PREFIX %s // RUN: not FileCheck -check-prefix=A! -input-file %s %s 2>&1 | FileCheck -check-prefix=BAD_PREFIX %s
// RUN: FileCheck -check-prefix=A1a-B_c -input-file %s %s // RUN: FileCheck -check-prefix=A1a-B_c -input-file %s %s
// RUN: not FileCheck -check-prefix=REPEAT -check-prefix=REPEAT -input-file %s %s 2>&1 | FileCheck -check-prefix=BAD_PREFIX %s
// RUN: not FileCheck -check-prefix=VALID -check-prefix=A! -input-file %s %s 2>&1 | FileCheck -check-prefix=BAD_PREFIX %s
foobar foobar
; A1a-B_c: foobar ; A1a-B_c: foobar
; BAD_PREFIX: Supplied check-prefix is invalid! Prefixes must start with a letter and contain only alphanumeric characters, hyphens and underscores ; BAD_PREFIX: Supplied check-prefix is invalid! Prefixes must be
unique and start with a letter and contain only alphanumeric characters, hyphens and underscores

View File

@ -20,6 +20,7 @@
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/PrettyStackTrace.h"
@ -42,14 +43,16 @@ static cl::opt<std::string>
InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
cl::init("-"), cl::value_desc("filename")); cl::init("-"), cl::value_desc("filename"));
static cl::opt<std::string> static cl::list<std::string>
CheckPrefix("check-prefix", cl::init("CHECK"), CheckPrefixes("check-prefix",
cl::desc("Prefix to use from check file (defaults to 'CHECK')")); cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
static cl::opt<bool> static cl::opt<bool>
NoCanonicalizeWhiteSpace("strict-whitespace", NoCanonicalizeWhiteSpace("strict-whitespace",
cl::desc("Do not treat all horizontal whitespace as equivalent")); cl::desc("Do not treat all horizontal whitespace as equivalent"));
typedef cl::list<std::string>::const_iterator prefix_iterator;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Pattern Handling Code. // Pattern Handling Code.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -103,11 +106,15 @@ public:
/// getLoc - Return the location in source code. /// getLoc - Return the location in source code.
SMLoc getLoc() const { return PatternLoc; } SMLoc getLoc() const { return PatternLoc; }
/// ParsePattern - Parse the given string into the Pattern. SM provides the /// ParsePattern - Parse the given string into the Pattern. Prefix provides
/// SourceMgr used for error reports, and LineNumber is the line number in /// which prefix is being matched, SM provides the SourceMgr used for error
/// the input file from which the pattern string was read. /// reports, and LineNumber is the line number in the input file from which
/// Returns true in case of an error, false otherwise. /// the pattern string was read. Returns true in case of an error, false
bool ParsePattern(StringRef PatternStr, SourceMgr &SM, unsigned LineNumber); /// otherwise.
bool ParsePattern(StringRef PatternStr,
StringRef Prefix,
SourceMgr &SM,
unsigned LineNumber);
/// Match - Match the pattern string against the input buffer Buffer. This /// Match - Match the pattern string against the input buffer Buffer. This
/// returns the position that is matched or npos if there is no match. If /// returns the position that is matched or npos if there is no match. If
@ -152,7 +159,9 @@ private:
}; };
bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM, bool Pattern::ParsePattern(StringRef PatternStr,
StringRef Prefix,
SourceMgr &SM,
unsigned LineNumber) { unsigned LineNumber) {
this->LineNumber = LineNumber; this->LineNumber = LineNumber;
PatternLoc = SMLoc::getFromPointer(PatternStr.data()); PatternLoc = SMLoc::getFromPointer(PatternStr.data());
@ -166,7 +175,7 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM,
if (PatternStr.empty()) { if (PatternStr.empty()) {
SM.PrintMessage(PatternLoc, SourceMgr::DK_Error, SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
"found empty check string with prefix '" + "found empty check string with prefix '" +
CheckPrefix+":'"); Prefix + ":'");
return true; return true;
} }
@ -594,6 +603,9 @@ struct CheckString {
/// Pat - The pattern to match. /// Pat - The pattern to match.
Pattern Pat; Pattern Pat;
/// Prefix - Which prefix name this check matched.
StringRef Prefix;
/// Loc - The location in the match file that the check string was specified. /// Loc - The location in the match file that the check string was specified.
SMLoc Loc; SMLoc Loc;
@ -606,8 +618,12 @@ struct CheckString {
/// file). /// file).
std::vector<Pattern> DagNotStrings; std::vector<Pattern> DagNotStrings;
CheckString(const Pattern &P, SMLoc L, Check::CheckType Ty)
: Pat(P), Loc(L), CheckTy(Ty) {} CheckString(const Pattern &P,
StringRef S,
SMLoc L,
Check::CheckType Ty)
: Pat(P), Prefix(S), Loc(L), CheckTy(Ty) {}
/// Check - Match check string and its "not strings" and/or "dag strings". /// Check - Match check string and its "not strings" and/or "dag strings".
size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
@ -670,43 +686,155 @@ static bool IsPartOfWord(char c) {
return (isalnum(c) || c == '-' || c == '_'); return (isalnum(c) || c == '-' || c == '_');
} }
static Check::CheckType FindCheckType(StringRef &Buffer, StringRef Prefix) { // Get the size of the prefix extension.
static size_t CheckTypeSize(Check::CheckType Ty) {
switch (Ty) {
case Check::CheckNone:
return 0;
case Check::CheckPlain:
return sizeof(":") - 1;
case Check::CheckNext:
return sizeof("-NEXT:") - 1;
case Check::CheckNot:
return sizeof("-NOT:") - 1;
case Check::CheckDAG:
return sizeof("-DAG:") - 1;
case Check::CheckLabel:
return sizeof("-LABEL:") - 1;
case Check::CheckEOF:
llvm_unreachable("Should not be using EOF size");
}
llvm_unreachable("Bad check type");
}
static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
char NextChar = Buffer[Prefix.size()]; char NextChar = Buffer[Prefix.size()];
// Verify that the : is present after the prefix. // Verify that the : is present after the prefix.
if (NextChar == ':') { if (NextChar == ':')
Buffer = Buffer.substr(Prefix.size() + 1);
return Check::CheckPlain; return Check::CheckPlain;
}
if (NextChar != '-') { if (NextChar != '-')
Buffer = Buffer.drop_front(1);
return Check::CheckNone; return Check::CheckNone;
}
StringRef Rest = Buffer.drop_front(Prefix.size() + 1); StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
if (Rest.startswith("NEXT:")) { if (Rest.startswith("NEXT:"))
Buffer = Rest.drop_front(sizeof("NEXT:") - 1);
return Check::CheckNext; return Check::CheckNext;
}
if (Rest.startswith("NOT:")) { if (Rest.startswith("NOT:"))
Buffer = Rest.drop_front(sizeof("NOT:") - 1);
return Check::CheckNot; return Check::CheckNot;
}
if (Rest.startswith("DAG:")) { if (Rest.startswith("DAG:"))
Buffer = Rest.drop_front(sizeof("DAG:") - 1);
return Check::CheckDAG; return Check::CheckDAG;
}
if (Rest.startswith("LABEL:")) { if (Rest.startswith("LABEL:"))
Buffer = Rest.drop_front(sizeof("LABEL:") - 1);
return Check::CheckLabel; return Check::CheckLabel;
return Check::CheckNone;
}
// From the given position, find the next character after the word.
static size_t SkipWord(StringRef Str, size_t Loc) {
while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
++Loc;
return Loc;
}
// Try to find the first match in buffer for any prefix. If a valid match is
// found, return that prefix and set its type and location. If there are almost
// matches (e.g. the actual prefix string is found, but is not an actual check
// string), but no valid match, return an empty string and set the position to
// resume searching from. If no partial matches are found, return an empty
// string and the location will be StringRef::npos. If one prefix is a substring
// of another, the maximal match should be found. e.g. if "A" and "AA" are
// prefixes then AA-CHECK: should match the second one.
static StringRef FindFirstCandidateMatch(StringRef &Buffer,
Check::CheckType &CheckTy,
size_t &CheckLoc) {
StringRef FirstPrefix;
size_t FirstLoc = StringRef::npos;
size_t SearchLoc = StringRef::npos;
Check::CheckType FirstTy = Check::CheckNone;
CheckTy = Check::CheckNone;
CheckLoc = StringRef::npos;
for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end();
I != E; ++I) {
StringRef Prefix(*I);
size_t PrefixLoc = Buffer.find(Prefix);
if (PrefixLoc == StringRef::npos)
continue;
// Track where we are searching for invalid prefixes that look almost right.
// We need to only advance to the first partial match on the next attempt
// since a partial match could be a substring of a later, valid prefix.
// Need to skip to the end of the word, otherwise we could end up
// matching a prefix in a substring later.
if (PrefixLoc < SearchLoc)
SearchLoc = SkipWord(Buffer, PrefixLoc);
// We only want to find the first match to avoid skipping some.
if (PrefixLoc > FirstLoc)
continue;
StringRef Rest = Buffer.drop_front(PrefixLoc);
// Make sure we have actually found the prefix, and not a word containing
// it. This should also prevent matching the wrong prefix when one is a
// substring of another.
if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1]))
continue;
Check::CheckType Ty = FindCheckType(Rest, Prefix);
if (Ty == Check::CheckNone)
continue;
FirstLoc = PrefixLoc;
FirstTy = Ty;
FirstPrefix = Prefix;
} }
Buffer = Buffer.drop_front(1); if (FirstPrefix.empty()) {
return Check::CheckNone; CheckLoc = SearchLoc;
} else {
CheckTy = FirstTy;
CheckLoc = FirstLoc;
}
return FirstPrefix;
}
static StringRef FindFirstMatchingPrefix(StringRef &Buffer,
unsigned &LineNumber,
Check::CheckType &CheckTy,
size_t &CheckLoc) {
while (!Buffer.empty()) {
StringRef Prefix = FindFirstCandidateMatch(Buffer, CheckTy, CheckLoc);
// If we found a real match, we are done.
if (!Prefix.empty()) {
LineNumber += Buffer.substr(0, CheckLoc).count('\n');
return Prefix;
}
// We didn't find any almost matches either, we are also done.
if (CheckLoc == StringRef::npos)
return StringRef();
LineNumber += Buffer.substr(0, CheckLoc + 1).count('\n');
// Advance to the last possible match we found and try again.
Buffer = Buffer.drop_front(CheckLoc + 1);
}
return StringRef();
} }
/// ReadCheckFile - Read the check file, which specifies the sequence of /// ReadCheckFile - Read the check file, which specifies the sequence of
@ -738,32 +866,24 @@ static bool ReadCheckFile(SourceMgr &SM,
unsigned LineNumber = 1; unsigned LineNumber = 1;
while (1) { while (1) {
// See if Prefix occurs in the memory buffer. Check::CheckType CheckTy;
size_t PrefixLoc = Buffer.find(CheckPrefix); size_t PrefixLoc;
// If we didn't find a match, we're done.
if (PrefixLoc == StringRef::npos) // See if a prefix occurs in the memory buffer.
StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer,
LineNumber,
CheckTy,
PrefixLoc);
if (UsedPrefix.empty())
break; break;
LineNumber += Buffer.substr(0, PrefixLoc).count('\n'); Buffer = Buffer.drop_front(PrefixLoc);
// Keep the charcter before our prefix so we can validate that we have // Location to use for error messages.
// found our prefix, and account for cases when PrefixLoc is 0. const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1);
Buffer = Buffer.substr(std::min(PrefixLoc-1, PrefixLoc));
const char *CheckPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); // PrefixLoc is to the start of the prefix. Skip to the end.
Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy));
// Make sure we have actually found our prefix, and not a word containing
// our prefix.
if (PrefixLoc != 0 && IsPartOfWord(Buffer[0])) {
Buffer = Buffer.substr(CheckPrefix.size());
continue;
}
// When we find a check prefix, keep track of what kind of type of CHECK we
// have.
Check::CheckType CheckTy = FindCheckType(Buffer, CheckPrefix);
if (CheckTy == Check::CheckNone)
continue;
// Okay, we found the prefix, yay. Remember the rest of the line, but ignore // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
// leading and trailing whitespace. // leading and trailing whitespace.
@ -777,15 +897,15 @@ static bool ReadCheckFile(SourceMgr &SM,
// Parse the pattern. // Parse the pattern.
Pattern P(CheckTy); Pattern P(CheckTy);
if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber)) if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber))
return true; return true;
// Verify that CHECK-LABEL lines do not define or use variables // Verify that CHECK-LABEL lines do not define or use variables
if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {
SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
SourceMgr::DK_Error, SourceMgr::DK_Error,
"found '"+CheckPrefix+"-LABEL:' with variable definition" "found '" + UsedPrefix + "-LABEL:'"
" or use"); " with variable definition or use");
return true; return true;
} }
@ -793,10 +913,10 @@ static bool ReadCheckFile(SourceMgr &SM,
// Verify that CHECK-NEXT lines have at least one CHECK line before them. // Verify that CHECK-NEXT lines have at least one CHECK line before them.
if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) {
SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
SourceMgr::DK_Error, SourceMgr::DK_Error,
"found '"+CheckPrefix+"-NEXT:' without previous '"+ "found '" + UsedPrefix + "-NEXT:' without previous '"
CheckPrefix+ ": line"); + UsedPrefix + ": line");
return true; return true;
} }
@ -808,22 +928,33 @@ static bool ReadCheckFile(SourceMgr &SM,
// Okay, add the string we captured to the output vector and move on. // Okay, add the string we captured to the output vector and move on.
CheckStrings.push_back(CheckString(P, CheckStrings.push_back(CheckString(P,
UsedPrefix,
PatternLoc, PatternLoc,
CheckTy)); CheckTy));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
} }
// Add an EOF pattern for any trailing CHECK-DAG/-NOTs. // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
// prefix as a filler for the error message.
if (!DagNotMatches.empty()) { if (!DagNotMatches.empty()) {
CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF), CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF),
CheckPrefixes[0],
SMLoc::getFromPointer(Buffer.data()), SMLoc::getFromPointer(Buffer.data()),
Check::CheckEOF)); Check::CheckEOF));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
} }
if (CheckStrings.empty()) { if (CheckStrings.empty()) {
errs() << "error: no check strings found with prefix '" << CheckPrefix errs() << "error: no check strings found with prefix"
<< ":'\n"; << (CheckPrefixes.size() > 1 ? "es " : " ");
for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) {
StringRef Prefix(CheckPrefixes[I]);
errs() << '\'' << Prefix << ":'";
if (I != N - 1)
errs() << ", ";
}
errs() << '\n';
return true; return true;
} }
@ -933,7 +1064,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
unsigned NumNewLines = CountNumNewlinesBetween(Buffer); unsigned NumNewLines = CountNumNewlinesBetween(Buffer);
if (NumNewLines == 0) { if (NumNewLines == 0) {
SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+ SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix +
"-NEXT: is on the same line as previous match"); "-NEXT: is on the same line as previous match");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()),
SourceMgr::DK_Note, "'next' match was here"); SourceMgr::DK_Note, "'next' match was here");
@ -943,7 +1074,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
} }
if (NumNewLines != 1) { if (NumNewLines != 1) {
SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+ SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix +
"-NEXT: is not on the line after the previous match"); "-NEXT: is not on the line after the previous match");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()),
SourceMgr::DK_Note, "'next' match was here"); SourceMgr::DK_Note, "'next' match was here");
@ -970,9 +1101,9 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos), SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos),
SourceMgr::DK_Error, SourceMgr::DK_Error,
CheckPrefix+"-NOT: string occurred!"); Prefix + "-NOT: string occurred!");
SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note, SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note,
CheckPrefix+"-NOT: pattern specified here"); Prefix + "-NOT: pattern specified here");
return true; return true;
} }
@ -1022,17 +1153,17 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// Reordered? // Reordered?
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos), SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos),
SourceMgr::DK_Error, SourceMgr::DK_Error,
CheckPrefix+"-DAG: found a match of CHECK-DAG" Prefix + "-DAG: found a match of CHECK-DAG"
" reordering across a CHECK-NOT"); " reordering across a CHECK-NOT");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos), SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos),
SourceMgr::DK_Note, SourceMgr::DK_Note,
CheckPrefix+"-DAG: the farthest match of CHECK-DAG" Prefix + "-DAG: the farthest match of CHECK-DAG"
" is found here"); " is found here");
SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note, SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note,
CheckPrefix+"-NOT: the crossed pattern specified" Prefix + "-NOT: the crossed pattern specified"
" here"); " here");
SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note, SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note,
CheckPrefix+"-DAG: the reordered pattern specified" Prefix + "-DAG: the reordered pattern specified"
" here"); " here");
return StringRef::npos; return StringRef::npos;
} }
@ -1056,10 +1187,34 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
return LastPos; return LastPos;
} }
bool ValidateCheckPrefix() { // A check prefix must contain only alphanumeric, hyphens and underscores.
// The check prefix must contain only alphanumeric, hyphens and underscores. static bool ValidateCheckPrefix(StringRef CheckPrefix) {
Regex prefixValidator("^[a-zA-Z0-9_-]*$"); Regex Validator("^[a-zA-Z0-9_-]*$");
return prefixValidator.match(CheckPrefix); return Validator.match(CheckPrefix);
}
static bool ValidateCheckPrefixes() {
StringSet<> PrefixSet;
for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end();
I != E; ++I) {
StringRef Prefix(*I);
if (!PrefixSet.insert(Prefix))
return false;
if (!ValidateCheckPrefix(Prefix))
return false;
}
return true;
}
// I don't think there's a way to specify an initial value for cl::list,
// so if nothing was specified, add the default
static void AddCheckPrefixIfNeeded() {
if (CheckPrefixes.empty())
CheckPrefixes.push_back("CHECK");
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -1067,13 +1222,15 @@ int main(int argc, char **argv) {
PrettyStackTraceProgram X(argc, argv); PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv); cl::ParseCommandLineOptions(argc, argv);
if (!ValidateCheckPrefix()) { if (!ValidateCheckPrefixes()) {
errs() << "Supplied check-prefix is invalid! Prefixes must start with a " errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
"letter and contain only alphanumeric characters, hyphens and " "start with a letter and contain only alphanumeric characters, "
"underscores\n"; "hyphens and underscores\n";
return 2; return 2;
} }
AddCheckPrefixIfNeeded();
SourceMgr SM; SourceMgr SM;
// Read the expected strings from the check file. // Read the expected strings from the check file.