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
This commit is contained in:
Daniel Dunbar 2009-11-22 22:59:26 +00:00
parent fafe93c8bc
commit ead2dacc9e

View File

@ -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.
}
}
//===----------------------------------------------------------------------===//