aboutsummaryrefslogtreecommitdiffstats
path: root/utils/FileCheck
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-11-22 22:59:26 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-11-22 22:59:26 +0000
commitead2dacc9ee028906cb104c8c3d66ccbbebe6b10 (patch)
treec4d27ba21f217a688212831a32d1c11f546d1eab /utils/FileCheck
parentfafe93c8bcbc538573bc5e890f24f9869a11f846 (diff)
downloadexternal_llvm-ead2dacc9ee028906cb104c8c3d66ccbbebe6b10.zip
external_llvm-ead2dacc9ee028906cb104c8c3d66ccbbebe6b10.tar.gz
external_llvm-ead2dacc9ee028906cb104c8c3d66ccbbebe6b10.tar.bz2
FileCheck, PR5239: Try to find the intended match on failures, but looking for a
good nearby fuzzy match. Frequently the input is nearly correct, and just showing the user the a nearby sensible match is enough to diagnose the problem. - The "fuzzyness" is pretty simple and arbitrary, but worked on my three test cases. If you encounter problems, or places you think FileCheck should have guessed but didn't, please add test cases to PR5239. For example, previously FileCheck would report this: -- t.cpp:21:55: error: expected string not found in input // CHECK: define void @_Z2f25f2_s1([[i64_i64_ty]] %a0) ^ <stdin>:19:30: note: scanning from here define void @_Z2f15f1_s1(%1) nounwind { ^ <stdin>:19:30: note: with variable "i64_i64_ty" equal to "%0" -- and now it also reports this: -- <stdin>:27:1: note: possible intended match here define void @_Z2f25f2_s1(%0) nounwind { ^ -- which makes it clear that the CHECK just has an extra ' %a0' in it, without having to check the input. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@89631 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils/FileCheck')
-rw-r--r--utils/FileCheck/FileCheck.cpp64
1 files changed, 60 insertions, 4 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index c86993d..101ff24 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -92,6 +92,12 @@ public:
private:
static void AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr);
bool AddRegExToRegEx(StringRef RegExStr, unsigned &CurParen, SourceMgr &SM);
+
+ /// ComputeMatchDistance - Compute an arbitrary estimate for the quality of
+ /// matching this pattern at the start of \arg Buffer; a distance of zero
+ /// should correspond to a perfect match.
+ unsigned ComputeMatchDistance(StringRef Buffer,
+ const StringMap<StringRef> &VariableTable) const;
};
@@ -322,12 +328,28 @@ size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
return FullMatch.data()-Buffer.data();
}
+unsigned Pattern::ComputeMatchDistance(StringRef Buffer,
+ const StringMap<StringRef> &VariableTable) const {
+ // Just compute the number of matching characters. For regular expressions, we
+ // just compare against the regex itself and hope for the best.
+ //
+ // FIXME: One easy improvement here is have the regex lib generate a single
+ // example regular expression which matches, and use that as the example
+ // string.
+ StringRef ExampleString(FixedStr);
+ if (ExampleString.empty())
+ ExampleString = RegExStr;
+
+ unsigned Distance = 0;
+ for (unsigned i = 0, e = ExampleString.size(); i != e; ++i)
+ if (Buffer.substr(i, 1) != ExampleString.substr(i, 1))
+ ++Distance;
+
+ return Distance;
+}
+
void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable) const{
- // If this is a fixed string, do nothing.
- if (!FixedStr.empty())
- return;
-
// If this was a regular expression using variables, print the current
// variable values.
if (!VariableUses.empty()) {
@@ -351,6 +373,40 @@ void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
/*ShowLine=*/false);
}
}
+
+ // 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
+ // save them having to actually check the input manually.
+ size_t NumLinesForward = 0;
+ size_t Best = StringRef::npos;
+ double BestQuality = 0;
+
+ // Use an arbitrary 4k limit on how far we will search.
+ for (size_t i = 0, e = std::min(4096, int(Buffer.size())); i != e; ++i) {
+ if (Buffer[i] == '\n')
+ ++NumLinesForward;
+
+ // Compute the "quality" of this match as an arbitrary combination of the
+ // match distance and the number of lines skipped to get to this match.
+ unsigned Distance = ComputeMatchDistance(Buffer.substr(i), VariableTable);
+ double Quality = Distance + (NumLinesForward / 100.);
+
+ if (Quality < BestQuality || Best == StringRef::npos) {
+ Best = i;
+ BestQuality = Quality;
+ }
+ }
+
+ if (BestQuality < 50) {
+ // Print the "possible intended match here" line if we found something
+ // reasonable.
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Best),
+ "possible intended match here", "note");
+
+ // FIXME: If we wanted to be really friendly we would show why the match
+ // failed, as it can be hard to spot simple one character differences.
+ }
}
//===----------------------------------------------------------------------===//