]> granicus.if.org Git - clang/commitdiff
Fix a think-o in handling ambiguous corrections for a TypoExpr.
authorKaelyn Takata <rikka@google.com>
Tue, 27 Jan 2015 22:01:39 +0000 (22:01 +0000)
committerKaelyn Takata <rikka@google.com>
Tue, 27 Jan 2015 22:01:39 +0000 (22:01 +0000)
Under certain circumstances, the identifier mentioned in the diagnostic
won't match the intended correction even though the replacement
expression and the note pointing to the decl are both correct.
Basically, the TreeTransform assumes the TypoExpr's Consumer points to
the correct TypoCorrection, but the handling of typos that appear to be
ambiguous from the point of view of TransformTypoExpr would cause that
assumption to be violated by altering the Consumer's correction stream.
This fix allows the Consumer's correction stream to be reset to the
right TypoCorrection after successfully resolving the percieved ambiguity.

Included is a fix to suppress correcting the RHS of an assignment to the
LHS of that assignment for non-C++ code, to prevent a regression in
test/SemaObjC/provisional-ivar-lookup.m.

This fixes PR22297.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@227251 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/SemaInternal.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/typo-correction-delayed.cpp

index 045bacf213600e5b3a5a6e6113810695a19c5c43..005d882c341b7356bff715c1cca68fb4818bd670 100644 (file)
@@ -101,7 +101,7 @@ public:
                          DeclContext *MemberContext,
                          bool EnteringContext)
       : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0),
-        SemaRef(SemaRef), S(S),
+        SavedTCIndex(0), SemaRef(SemaRef), S(S),
         SS(SS ? llvm::make_unique<CXXScopeSpec>(*SS) : nullptr),
         CorrectionValidator(std::move(CCC)), MemberContext(MemberContext),
         Result(SemaRef, TypoName, LookupKind),
@@ -187,6 +187,17 @@ public:
            CurrentTCIndex >= ValidatedCorrections.size();
   }
 
+  /// \brief Save the current position in the correction stream (overwriting any
+  /// previously saved position).
+  void saveCurrentPosition() {
+    SavedTCIndex = CurrentTCIndex;
+  }
+
+  /// \brief Restore the saved position in the correction stream.
+  void restoreSavedPosition() {
+    CurrentTCIndex = SavedTCIndex;
+  }
+
   ASTContext &getContext() const { return SemaRef.Context; }
   const LookupResult &getLookupResult() const { return Result; }
 
@@ -267,6 +278,7 @@ private:
 
   SmallVector<TypoCorrection, 4> ValidatedCorrections;
   size_t CurrentTCIndex;
+  size_t SavedTCIndex;
 
   Sema &SemaRef;
   Scope *S;
index 2b507141e97544404b7431e8b9c67ee1e110d5eb..e75daa412fb537676d34cbc027150bbdb478a2be 100644 (file)
@@ -9459,6 +9459,18 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R,
   }
 }
 
+static NamedDecl *getDeclFromExpr(Expr *E) {
+  if (!E)
+    return nullptr;
+  if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+    return DRE->getDecl();
+  if (auto *ME = dyn_cast<MemberExpr>(E))
+    return ME->getMemberDecl();
+  if (auto *IRE = dyn_cast<ObjCIvarRefExpr>(E))
+    return IRE->getDecl();
+  return nullptr;
+}
+
 /// CreateBuiltinBinOp - Creates a new built-in binary operation with
 /// operator @p Opc at location @c TokLoc. This routine only supports
 /// built-in operations; ActOnBinOp handles overloaded operators.
@@ -9496,7 +9508,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
     // doesn't handle dependent types properly, so make sure any TypoExprs have
     // been dealt with before checking the operands.
     LHS = CorrectDelayedTyposInExpr(LHSExpr);
-    RHS = CorrectDelayedTyposInExpr(RHSExpr);
+    RHS = CorrectDelayedTyposInExpr(RHSExpr, [Opc, LHS](Expr *E) {
+      if (Opc != BO_Assign)
+        return ExprResult(E);
+      // Avoid correcting the RHS to the same Expr as the LHS.
+      Decl *D = getDeclFromExpr(E);
+      return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
+    });
     if (!LHS.isUsable() || !RHS.isUsable())
       return ExprError();
   }
index bf4ab267a411c5bff5f68f62f9d025ff5d91e470..9477c7f2f9ef1b2d23701674e0339377ebb6942f 100644 (file)
@@ -6165,15 +6165,18 @@ public:
     while (!AmbiguousTypoExprs.empty()) {
       auto TE  = AmbiguousTypoExprs.back();
       auto Cached = TransformCache[TE];
-      AmbiguousTypoExprs.pop_back();
+      auto &State = SemaRef.getTypoExprState(TE);
+      State.Consumer->saveCurrentPosition();
       TransformCache.erase(TE);
       if (!TryTransform(E).isInvalid()) {
-        SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream();
+        State.Consumer->resetCorrectionStream();
         TransformCache.erase(TE);
         Res = ExprError();
         break;
-      } else
-        TransformCache[TE] = Cached;
+      }
+      AmbiguousTypoExprs.remove(TE);
+      State.Consumer->restoreSavedPosition();
+      TransformCache[TE] = Cached;
     }
 
     // Ensure that all of the TypoExprs within the current Expr have been found.
index f09dd330dbb178fa9bf6a9b08c4fade0b32940f1..516b600f422fd9875f6b0aa0d0bfb7b286370c34 100644 (file)
@@ -175,3 +175,13 @@ namespace PR22250 {
 // expected-error@+1 {{expected ';' after top level declarator}}
 int getenv_s(size_t *y, char(&z)) {}
 }
+
+namespace PR22297 {
+double pow(double x, double y);
+struct TimeTicks {
+  static void Now();  // expected-note {{'Now' declared here}}
+};
+void f() {
+  TimeTicks::now();  // expected-error {{no member named 'now' in 'PR22297::TimeTicks'; did you mean 'Now'?}}
+}
+}