Use the full-Expr filter to disambiguate equidistant correction

candidates.

llvm-svn: 222549
This commit is contained in:
Kaelyn Takata 2014-11-21 18:47:58 +00:00
parent a126e462c2
commit 5ca2ecd2b2
2 changed files with 52 additions and 26 deletions

View File

@ -5992,7 +5992,7 @@ class TransformTypos : public TreeTransform<TransformTypos> {
typedef TreeTransform<TransformTypos> BaseTransform;
llvm::function_ref<ExprResult(Expr *)> ExprFilter;
llvm::SmallSetVector<TypoExpr *, 2> TypoExprs;
llvm::SmallSetVector<TypoExpr *, 2> TypoExprs, AmbiguousTypoExprs;
llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache;
llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution;
@ -6059,6 +6059,15 @@ class TransformTypos : public TreeTransform<TransformTypos> {
return nullptr;
}
ExprResult TryTransform(Expr *E) {
Sema::SFINAETrap Trap(SemaRef);
ExprResult Res = TransformExpr(E);
if (Trap.hasErrorOccurred() || Res.isInvalid())
return ExprError();
return ExprFilter(Res.get());
}
public:
TransformTypos(Sema &SemaRef, llvm::function_ref<ExprResult(Expr *)> Filter)
: BaseTransform(SemaRef), ExprFilter(Filter) {}
@ -6079,30 +6088,42 @@ public:
ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); }
ExprResult Transform(Expr *E) {
ExprResult res;
bool error = false;
ExprResult Res;
while (true) {
Sema::SFINAETrap Trap(SemaRef);
res = TransformExpr(E);
error = Trap.hasErrorOccurred();
if (!(error || res.isInvalid()))
res = ExprFilter(res.get());
Res = TryTransform(E);
// Exit if either the transform was valid or if there were no TypoExprs
// to transform that still have any untried correction candidates..
if (!(error || res.isInvalid()) ||
if (!Res.isInvalid() ||
!CheckAndAdvanceTypoExprCorrectionStreams())
break;
}
// Ensure none of the TypoExprs have multiple typo correction candidates
// with the same edit length that pass all the checks and filters.
// TODO: Properly handle various permutations of possible corrections when
// there is more than one potentially ambiguous typo correction.
while (!AmbiguousTypoExprs.empty()) {
auto TE = AmbiguousTypoExprs.back();
auto Cached = TransformCache[TE];
AmbiguousTypoExprs.pop_back();
TransformCache.erase(TE);
if (!TryTransform(E).isInvalid()) {
SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream();
TransformCache.erase(TE);
Res = ExprError();
break;
} else
TransformCache[TE] = Cached;
}
// Ensure that all of the TypoExprs within the current Expr have been found.
if (!res.isUsable())
if (!Res.isUsable())
FindTypoExprs(TypoExprs).TraverseStmt(E);
EmitAllDiagnostics();
return res;
return Res;
}
ExprResult TransformTypoExpr(TypoExpr *E) {
@ -6124,21 +6145,15 @@ public:
State.RecoveryHandler(SemaRef, E, TC) :
attemptRecovery(SemaRef, *State.Consumer, TC);
if (!NE.isInvalid()) {
// Check whether there is a second viable correction with the same edit
// distance--in which case do not suggest anything since both are
// equally good candidates for correcting the typo.
Sema::SFINAETrap LocalTrap(SemaRef);
// Check whether there may be a second viable correction with the same
// edit distance; if so, remember this TypoExpr may have an ambiguous
// correction so it can be more thoroughly vetted later.
TypoCorrection Next;
while ((Next = State.Consumer->peekNextCorrection()) &&
Next.getEditDistance(false) == TC.getEditDistance(false)) {
ExprResult Res =
State.RecoveryHandler
? State.RecoveryHandler(SemaRef, E, Next)
: attemptRecovery(SemaRef, *State.Consumer, Next);
if (!Res.isInvalid()) {
NE = ExprError();
State.Consumer->getNextCorrection();
}
if ((Next = State.Consumer->peekNextCorrection()) &&
Next.getEditDistance(false) == TC.getEditDistance(false)) {
AmbiguousTypoExprs.insert(E);
} else {
AmbiguousTypoExprs.remove(E);
}
assert(!NE.isUnset() &&
"Typo was transformed into a valid-but-null ExprResult");

View File

@ -48,3 +48,14 @@ void testNoCandidates() {
callee(xxxxxx, // expected-error-re {{use of undeclared identifier 'xxxxxx'{{$}}}}
zzzzzz); // expected-error-re {{use of undeclared identifier 'zzzzzz'{{$}}}}
}
class string {};
struct Item {
void Nest();
string text();
Item* next(); // expected-note {{'next' declared here}}
};
void testExprFilter(Item *i) {
Item *j;
j = i->Next(); // expected-error {{no member named 'Next' in 'Item'; did you mean 'next'?}}
}