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; typedef TreeTransform<TransformTypos> BaseTransform;
llvm::function_ref<ExprResult(Expr *)> ExprFilter; 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<TypoExpr *, ExprResult, 2> TransformCache;
llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution; llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution;
@ -6059,6 +6059,15 @@ class TransformTypos : public TreeTransform<TransformTypos> {
return nullptr; 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: public:
TransformTypos(Sema &SemaRef, llvm::function_ref<ExprResult(Expr *)> Filter) TransformTypos(Sema &SemaRef, llvm::function_ref<ExprResult(Expr *)> Filter)
: BaseTransform(SemaRef), ExprFilter(Filter) {} : BaseTransform(SemaRef), ExprFilter(Filter) {}
@ -6079,30 +6088,42 @@ public:
ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); } ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); }
ExprResult Transform(Expr *E) { ExprResult Transform(Expr *E) {
ExprResult res; ExprResult Res;
bool error = false;
while (true) { while (true) {
Sema::SFINAETrap Trap(SemaRef); Res = TryTransform(E);
res = TransformExpr(E);
error = Trap.hasErrorOccurred();
if (!(error || res.isInvalid()))
res = ExprFilter(res.get());
// Exit if either the transform was valid or if there were no TypoExprs // Exit if either the transform was valid or if there were no TypoExprs
// to transform that still have any untried correction candidates.. // to transform that still have any untried correction candidates..
if (!(error || res.isInvalid()) || if (!Res.isInvalid() ||
!CheckAndAdvanceTypoExprCorrectionStreams()) !CheckAndAdvanceTypoExprCorrectionStreams())
break; 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. // Ensure that all of the TypoExprs within the current Expr have been found.
if (!res.isUsable()) if (!Res.isUsable())
FindTypoExprs(TypoExprs).TraverseStmt(E); FindTypoExprs(TypoExprs).TraverseStmt(E);
EmitAllDiagnostics(); EmitAllDiagnostics();
return res; return Res;
} }
ExprResult TransformTypoExpr(TypoExpr *E) { ExprResult TransformTypoExpr(TypoExpr *E) {
@ -6124,21 +6145,15 @@ public:
State.RecoveryHandler(SemaRef, E, TC) : State.RecoveryHandler(SemaRef, E, TC) :
attemptRecovery(SemaRef, *State.Consumer, TC); attemptRecovery(SemaRef, *State.Consumer, TC);
if (!NE.isInvalid()) { if (!NE.isInvalid()) {
// Check whether there is a second viable correction with the same edit // Check whether there may be a second viable correction with the same
// distance--in which case do not suggest anything since both are // edit distance; if so, remember this TypoExpr may have an ambiguous
// equally good candidates for correcting the typo. // correction so it can be more thoroughly vetted later.
Sema::SFINAETrap LocalTrap(SemaRef);
TypoCorrection Next; TypoCorrection Next;
while ((Next = State.Consumer->peekNextCorrection()) && if ((Next = State.Consumer->peekNextCorrection()) &&
Next.getEditDistance(false) == TC.getEditDistance(false)) { Next.getEditDistance(false) == TC.getEditDistance(false)) {
ExprResult Res = AmbiguousTypoExprs.insert(E);
State.RecoveryHandler } else {
? State.RecoveryHandler(SemaRef, E, Next) AmbiguousTypoExprs.remove(E);
: attemptRecovery(SemaRef, *State.Consumer, Next);
if (!Res.isInvalid()) {
NE = ExprError();
State.Consumer->getNextCorrection();
}
} }
assert(!NE.isUnset() && assert(!NE.isUnset() &&
"Typo was transformed into a valid-but-null ExprResult"); "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'{{$}}}} callee(xxxxxx, // expected-error-re {{use of undeclared identifier 'xxxxxx'{{$}}}}
zzzzzz); // expected-error-re {{use of undeclared identifier 'zzzzzz'{{$}}}} 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'?}}
}