summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaelyn Takata <rikka@google.com>2014-11-21 18:47:58 +0000
committerKaelyn Takata <rikka@google.com>2014-11-21 18:47:58 +0000
commit5ca2ecd2b200360ae33e047e3da418c8852564c2 (patch)
treeab5ce9280c5ec9e4e35ee605b9e2f0b7703d3aaa
parenta126e462c2ab30eb985e95bfada8bd881145a7d2 (diff)
downloadbcm5719-llvm-5ca2ecd2b200360ae33e047e3da418c8852564c2.tar.gz
bcm5719-llvm-5ca2ecd2b200360ae33e047e3da418c8852564c2.zip
Use the full-Expr filter to disambiguate equidistant correction
candidates. llvm-svn: 222549
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp67
-rw-r--r--clang/test/SemaCXX/typo-correction-delayed.cpp11
2 files changed, 52 insertions, 26 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 35211a28a52..93996685105 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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");
diff --git a/clang/test/SemaCXX/typo-correction-delayed.cpp b/clang/test/SemaCXX/typo-correction-delayed.cpp
index 984d68b6b92..c82f865a863 100644
--- a/clang/test/SemaCXX/typo-correction-delayed.cpp
+++ b/clang/test/SemaCXX/typo-correction-delayed.cpp
@@ -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'?}}
+}
OpenPOWER on IntegriCloud