summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/FileCheck/FileCheck.cpp170
1 files changed, 137 insertions, 33 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index cd3175f13f0..4efe535cecf 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -90,6 +90,14 @@ static cl::opt<bool> AllowDeprecatedDagOverlap(
"provided for convenience as old tests are migrated to the new\n"
"non-overlapping CHECK-DAG implementation.\n"));
+static cl::opt<bool> Verbose("v", cl::init(false),
+ cl::desc("Print directive pattern matches.\n"));
+
+static cl::opt<bool> VerboseVerbose(
+ "vv", cl::init(false),
+ cl::desc("Print information helpful in diagnosing internal FileCheck\n"
+ "issues. Implies -v.\n"));
+
typedef cl::list<std::string>::const_iterator prefix_iterator;
//===----------------------------------------------------------------------===//
@@ -154,8 +162,11 @@ public:
unsigned LineNumber);
size_t Match(StringRef Buffer, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const;
- void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
- const StringMap<StringRef> &VariableTable) const;
+ void PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
+ const StringMap<StringRef> &VariableTable,
+ SMRange MatchRange = None) const;
+ void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
+ const StringMap<StringRef> &VariableTable) const;
bool hasVariable() const {
return !(VariableUses.empty() && VariableDefs.empty());
@@ -484,8 +495,12 @@ size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
VariableTable[VariableDef.first] = MatchInfo[VariableDef.second];
}
- MatchLen = FullMatch.size();
- return FullMatch.data() - Buffer.data();
+ // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
+ // the required preceding newline, which is consumed by the pattern in the
+ // case of CHECK-EMPTY but not CHECK-NEXT.
+ size_t MatchStartSkip = CheckTy == Check::CheckEmpty;
+ MatchLen = FullMatch.size() - MatchStartSkip;
+ return FullMatch.data() - Buffer.data() + MatchStartSkip;
}
@@ -511,11 +526,9 @@ Pattern::ComputeMatchDistance(StringRef Buffer,
return BufferPrefix.edit_distance(ExampleString);
}
-/// Prints additional information about a failure to match involving this
-/// pattern.
-void Pattern::PrintFailureInfo(
- const SourceMgr &SM, StringRef Buffer,
- const StringMap<StringRef> &VariableTable) const {
+void Pattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
+ const StringMap<StringRef> &VariableTable,
+ SMRange MatchRange) const {
// If this was a regular expression using variables, print the current
// variable values.
if (!VariableUses.empty()) {
@@ -547,11 +560,19 @@ void Pattern::PrintFailureInfo(
}
}
- SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
- OS.str());
+ if (MatchRange.isValid())
+ SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(),
+ {MatchRange});
+ else
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
+ SourceMgr::DK_Note, OS.str());
}
}
+}
+void Pattern::PrintFuzzyMatch(
+ const SourceMgr &SM, StringRef Buffer,
+ const StringMap<StringRef> &VariableTable) const {
// Attempt to find the closest/best fuzzy match. Usually an error happens
// because some string in the output didn't exactly match. In these cases, we
// would like to show the user a best guess at what "should have" matched, to
@@ -741,6 +762,33 @@ static size_t CheckTypeSize(Check::CheckType Ty) {
llvm_unreachable("Bad check type");
}
+// Get a description of the type.
+static std::string CheckTypeName(StringRef Prefix, Check::CheckType Ty) {
+ switch (Ty) {
+ case Check::CheckNone:
+ return "invalid";
+ case Check::CheckPlain:
+ return Prefix;
+ case Check::CheckNext:
+ return Prefix.str() + "-NEXT";
+ case Check::CheckSame:
+ return Prefix.str() + "-SAME";
+ case Check::CheckNot:
+ return Prefix.str() + "-NOT";
+ case Check::CheckDAG:
+ return Prefix.str() + "-DAG";
+ case Check::CheckLabel:
+ return Prefix.str() + "-LABEL";
+ case Check::CheckEmpty:
+ return Prefix.str() + "-EMPTY";
+ case Check::CheckEOF:
+ return "implicit EOF";
+ case Check::CheckBadNot:
+ return "bad NOT";
+ }
+ llvm_unreachable("unknown CheckType");
+}
+
static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
if (Buffer.size() <= Prefix.size())
return Check::CheckNone;
@@ -990,12 +1038,49 @@ static bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
return false;
}
-static void PrintCheckFailed(const SourceMgr &SM, SMLoc Loc, const Pattern &Pat,
- StringRef Buffer,
- StringMap<StringRef> &VariableTable) {
+static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
+ StringRef Prefix, SMLoc Loc, const Pattern &Pat,
+ StringRef Buffer, StringMap<StringRef> &VariableTable,
+ size_t MatchPos, size_t MatchLen) {
+ if (ExpectedMatch) {
+ if (!Verbose)
+ return;
+ if (!VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)
+ return;
+ }
+ SMLoc MatchStart = SMLoc::getFromPointer(Buffer.data() + MatchPos);
+ SMLoc MatchEnd = SMLoc::getFromPointer(Buffer.data() + MatchPos + MatchLen);
+ SMRange MatchRange(MatchStart, MatchEnd);
+ SM.PrintMessage(
+ Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error,
+ CheckTypeName(Prefix, Pat.getCheckTy()) + ": " +
+ (ExpectedMatch ? "expected" : "excluded") +
+ " string found in input");
+ SM.PrintMessage(MatchStart, SourceMgr::DK_Note, "found here", {MatchRange});
+ Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange);
+}
+
+static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
+ const CheckString &CheckStr, StringRef Buffer,
+ StringMap<StringRef> &VariableTable, size_t MatchPos,
+ size_t MatchLen) {
+ PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
+ Buffer, VariableTable, MatchPos, MatchLen);
+}
+
+static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
+ StringRef Prefix, SMLoc Loc, const Pattern &Pat,
+ StringRef Buffer,
+ StringMap<StringRef> &VariableTable) {
+ if (!ExpectedMatch && !VerboseVerbose)
+ return;
+
// Otherwise, we have an error, emit an error message.
- SM.PrintMessage(Loc, SourceMgr::DK_Error,
- "expected string not found in input");
+ SM.PrintMessage(Loc,
+ ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark,
+ CheckTypeName(Prefix, Pat.getCheckTy()) + ": " +
+ (ExpectedMatch ? "expected" : "excluded") +
+ " string not found in input");
// Print the "scanning from here" line. If the current position is at the
// end of a line, advance to the start of the next line.
@@ -1005,13 +1090,16 @@ static void PrintCheckFailed(const SourceMgr &SM, SMLoc Loc, const Pattern &Pat,
"scanning from here");
// Allow the pattern to print additional information if desired.
- Pat.PrintFailureInfo(SM, Buffer, VariableTable);
+ Pat.PrintVariableUses(SM, Buffer, VariableTable);
+ if (ExpectedMatch)
+ Pat.PrintFuzzyMatch(SM, Buffer, VariableTable);
}
-static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
- StringRef Buffer,
- StringMap<StringRef> &VariableTable) {
- PrintCheckFailed(SM, CheckStr.Loc, CheckStr.Pat, Buffer, VariableTable);
+static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
+ const CheckString &CheckStr, StringRef Buffer,
+ StringMap<StringRef> &VariableTable) {
+ PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
+ Buffer, VariableTable);
}
/// Count the number of newlines in the specified range.
@@ -1059,9 +1147,10 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
StringRef MatchBuffer = Buffer.substr(LastPos);
size_t MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable);
if (MatchPos == StringRef::npos) {
- PrintCheckFailed(SM, *this, MatchBuffer, VariableTable);
+ PrintNoMatch(true, SM, *this, MatchBuffer, VariableTable);
return StringRef::npos;
}
+ PrintMatch(true, SM, *this, MatchBuffer, VariableTable, MatchPos, MatchLen);
// Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
// or CHECK-NOT
@@ -1107,11 +1196,6 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
const char *FirstNewLine = nullptr;
unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
- // For CHECK-EMPTY, the preceding new line is consumed by the pattern, so
- // this needs to be re-added.
- if (Pat.getCheckTy() == Check::CheckEmpty)
- ++NumNewLines;
-
if (NumNewLines == 0) {
SM.PrintMessage(Loc, SourceMgr::DK_Error,
CheckName + ": is on the same line as previous match");
@@ -1177,13 +1261,15 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
size_t MatchLen = 0;
size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
- if (Pos == StringRef::npos)
+ if (Pos == StringRef::npos) {
+ PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer,
+ VariableTable);
continue;
+ }
+
+ PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer, VariableTable,
+ Pos, MatchLen);
- SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Pos),
- SourceMgr::DK_Error, Prefix + "-NOT: string occurred!");
- SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note,
- Prefix + "-NOT: pattern specified here");
return true;
}
@@ -1230,11 +1316,15 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// With a group of CHECK-DAGs, a single mismatching means the match on
// that group of CHECK-DAGs fails immediately.
if (MatchPosBuf == StringRef::npos) {
- PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable);
+ PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, MatchBuffer,
+ VariableTable);
return StringRef::npos;
}
// Re-calc it as the offset relative to the start of the original string.
MatchPos += MatchPosBuf;
+ if (VerboseVerbose)
+ PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
+ MatchPos, MatchLen);
if (AllowDeprecatedDagOverlap)
break;
// Iterate previous matches until overlapping match or insertion point.
@@ -1253,8 +1343,19 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
Matches.insert(MI, M);
break;
}
+ if (VerboseVerbose) {
+ SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);
+ SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);
+ SMRange OldRange(OldStart, OldEnd);
+ SM.PrintMessage(OldStart, SourceMgr::DK_Note,
+ "match discarded, overlaps earlier DAG match here",
+ {OldRange});
+ }
MatchPos = MI->End;
}
+ if (!VerboseVerbose)
+ PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
+ MatchPos, MatchLen);
if (!NotStrings.empty()) {
if (MatchPos < LastPos) {
@@ -1455,6 +1556,9 @@ int main(int argc, char **argv) {
return 2;
}
+ if (VerboseVerbose)
+ Verbose = true;
+
SourceMgr SM;
// Read the expected strings from the check file.