r222549 - Use the full-Expr filter to disambiguate equidistant correction

David Blaikie dblaikie at gmail.com
Fri Nov 21 11:17:49 PST 2014


On Fri, Nov 21, 2014 at 10:47 AM, Kaelyn Takata <rikka at google.com> wrote:

> Author: rikka
> Date: Fri Nov 21 12:47:58 2014
> New Revision: 222549
>
> URL: http://llvm.org/viewvc/llvm-project?rev=222549&view=rev
> Log:
> Use the full-Expr filter to disambiguate equidistant correction
> candidates.
>
> Modified:
>     cfe/trunk/lib/Sema/SemaExprCXX.cpp
>     cfe/trunk/test/SemaCXX/typo-correction-delayed.cpp
>
> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=222549&r1=222548&r2=222549&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Nov 21 12:47:58 2014
> @@ -5992,7 +5992,7 @@ class TransformTypos : public TreeTransf
>    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 TreeTransf
>      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");
>
> Modified: cfe/trunk/test/SemaCXX/typo-correction-delayed.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typo-correction-delayed.cpp?rev=222549&r1=222548&r2=222549&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/typo-correction-delayed.cpp (original)
> +++ cfe/trunk/test/SemaCXX/typo-correction-delayed.cpp Fri Nov 21 12:47:58
> 2014
> @@ -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'?}}
> +}
>

I imagine this test should pass by picking the best candidate (the edit
distance from Next -> next is shorter than Next->text or Next-Nest), right?
If that's the case, is that not addressed (are we not picking the best
candidate?)? Once it is, we might need a different test case to verify this
tie handling - presumably a test where the best candidate has a tie?

(but I'm guessing your example had something else to test - since only the
return type of 'next' would make this compile - the other two return types
don't match - what was that about? Clearly I'm missing something here)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141121/e96273f6/attachment.html>


More information about the cfe-commits mailing list