Backport important features of recent FileCheck to the 3.5-3.8 versions.

(CHECK-SAME and erroring on unsupported "-NOT" check combinations)
This commit is contained in:
Johan Engelen 2016-04-19 23:24:42 +02:00
parent 3493b0640b
commit cd769a4736
4 changed files with 173 additions and 12 deletions

View file

@ -73,13 +73,16 @@ namespace Check {
CheckNone = 0,
CheckPlain,
CheckNext,
CheckSame,
CheckNot,
CheckDAG,
CheckLabel,
/// MatchEOF - When set, this pattern only matches the end of file. This is
/// used for trailing CHECK-NOTs.
CheckEOF
CheckEOF,
/// CheckBadNot - Found -NOT combined with another CHECK suffix.
CheckBadNot
};
}
@ -620,6 +623,9 @@ struct CheckString {
/// CheckNext - Verify there is a single line in the given buffer.
bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
/// CheckSame - Verify there is no newline in the given buffer.
bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
/// CheckNot - Verify there's no "not strings" in the given buffer.
bool CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const Pattern *> &NotStrings,
@ -675,6 +681,7 @@ static bool IsPartOfWord(char c) {
static size_t CheckTypeSize(Check::CheckType Ty) {
switch (Ty) {
case Check::CheckNone:
case Check::CheckBadNot:
return 0;
case Check::CheckPlain:
@ -683,6 +690,9 @@ static size_t CheckTypeSize(Check::CheckType Ty) {
case Check::CheckNext:
return sizeof("-NEXT:") - 1;
case Check::CheckSame:
return sizeof("-SAME:") - 1;
case Check::CheckNot:
return sizeof("-NOT:") - 1;
@ -713,6 +723,9 @@ static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
if (Rest.startswith("NEXT:"))
return Check::CheckNext;
if (Rest.startswith("SAME:"))
return Check::CheckSame;
if (Rest.startswith("NOT:"))
return Check::CheckNot;
@ -722,6 +735,12 @@ static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
if (Rest.startswith("LABEL:"))
return Check::CheckLabel;
// You can't combine -NOT with another suffix.
if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:"))
return Check::CheckBadNot;
return Check::CheckNone;
}
@ -892,6 +911,14 @@ static bool ReadCheckFile(SourceMgr &SM,
// PrefixLoc is to the start of the prefix. Skip to the end.
Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy));
// Complain about useful-looking but unsupported suffixes.
if (CheckTy == Check::CheckBadNot) {
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
SourceMgr::DK_Error,
"unsupported -NOT combo on prefix '" + UsedPrefix + "'");
return true;
}
// Okay, we found the prefix, yay. Remember the rest of the line, but ignore
// leading and trailing whitespace.
Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
@ -919,10 +946,12 @@ static bool ReadCheckFile(SourceMgr &SM,
Buffer = Buffer.substr(EOL);
// Verify that CHECK-NEXT lines have at least one CHECK line before them.
if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) {
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) &&
CheckStrings.empty()) {
StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME";
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
SourceMgr::DK_Error,
"found '" + UsedPrefix + "-NEXT:' without previous '"
"found '" + UsedPrefix + "-" + Type + "' without previous '"
+ UsedPrefix + ": line");
return true;
}
@ -1041,7 +1070,6 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
PrintCheckFailed(SM, *this, MatchBuffer, VariableTable);
return StringRef::npos;
}
MatchPos += LastPos;
// Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
// or CHECK-NOT
@ -1053,13 +1081,18 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
if (CheckNext(SM, SkippedRegion))
return StringRef::npos;
// If this check is a "CHECK-SAME", verify that the previous match was on
// the same line (i.e. that there is no newline between them).
if (CheckSame(SM, SkippedRegion))
return StringRef::npos;
// If this match had "not strings", verify that they don't exist in the
// skipped region.
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
return StringRef::npos;
}
return MatchPos;
return LastPos + MatchPos;
}
bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
@ -1101,6 +1134,34 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
return false;
}
bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
if (CheckTy != Check::CheckSame)
return false;
// Count the number of newlines between the previous match and this one.
assert(Buffer.data() !=
SM.getMemoryBuffer(SM.FindBufferContainingLoc(
SMLoc::getFromPointer(Buffer.data())))
->getBufferStart() &&
"CHECK-SAME can't be the first check in a file");
const char *FirstNewLine = nullptr;
unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
if (NumNewLines != 0) {
SM.PrintMessage(Loc, SourceMgr::DK_Error,
Prefix +
"-SAME: is not on the same line as the previous match");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
"'next' match was here");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
"previous match ended here");
return true;
}
return false;
}
bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const Pattern *> &NotStrings,
StringMap<StringRef> &VariableTable) const {