r313323 - [Sema] Correct typos in LHS, RHS before building a binop expression.

Volodymyr Sapsai via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 14 17:08:37 PDT 2017


Author: vsapsai
Date: Thu Sep 14 17:08:37 2017
New Revision: 313323

URL: http://llvm.org/viewvc/llvm-project?rev=313323&view=rev
Log:
[Sema] Correct typos in LHS, RHS before building a binop expression.

Specifically, typo correction should be done before dispatching between
different kinds of binary operations like pseudo-object assignment,
overloaded binary operation, etc.

Without this change we hit an assertion

    Assertion failed: (!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject)), function CheckAssignmentOperands

when in Objective-C we reference a property without `self` and there are
2 equally good typo correction candidates: ivar and a class name. In
this case LHS expression in `BuildBinOp` is

    CXXDependentScopeMemberExpr
    `-TypoExpr

and instead of handling Obj-C property assignment as pseudo-object
assignment, we call `CreateBuiltinBinOp` which corrects typo to

    ObjCPropertyRefExpr '<pseudo-object type>'

but cannot handle pseudo-objects and asserts about it (indirectly,
through `CheckAssignmentOperands`).

rdar://problem/33102722

Reviewers: rsmith, ahatanak, majnemer

Reviewed By: ahatanak

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D37322

Modified:
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/SemaObjC/typo-correction.m
    cfe/trunk/test/SemaObjCXX/typo-correction.mm

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=313323&r1=313322&r2=313323&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep 14 17:08:37 2017
@@ -11269,6 +11269,26 @@ static NamedDecl *getDeclFromExpr(Expr *
   return nullptr;
 }
 
+static std::pair<ExprResult, ExprResult>
+CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr,
+                           Expr *RHSExpr) {
+  ExprResult LHS = LHSExpr, RHS = RHSExpr;
+  if (!S.getLangOpts().CPlusPlus) {
+    // C cannot handle TypoExpr nodes on either side of a binop because it
+    // doesn't handle dependent types properly, so make sure any TypoExprs have
+    // been dealt with before checking the operands.
+    LHS = S.CorrectDelayedTyposInExpr(LHS);
+    RHS = S.CorrectDelayedTyposInExpr(RHS, [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;
+    });
+  }
+  return std::make_pair(LHS, RHS);
+}
+
 /// 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.
@@ -11301,21 +11321,9 @@ ExprResult Sema::CreateBuiltinBinOp(Sour
   ExprValueKind VK = VK_RValue;
   ExprObjectKind OK = OK_Ordinary;
 
-  if (!getLangOpts().CPlusPlus) {
-    // C cannot handle TypoExpr nodes on either side of a binop because it
-    // 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, [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();
-  }
+  std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
+  if (!LHS.isUsable() || !RHS.isUsable())
+    return ExprError();
 
   if (getLangOpts().OpenCL) {
     QualType LHSTy = LHSExpr->getType();
@@ -11729,6 +11737,13 @@ static ExprResult BuildOverloadedBinOp(S
 ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
                             BinaryOperatorKind Opc,
                             Expr *LHSExpr, Expr *RHSExpr) {
+  ExprResult LHS, RHS;
+  std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
+  if (!LHS.isUsable() || !RHS.isUsable())
+    return ExprError();
+  LHSExpr = LHS.get();
+  RHSExpr = RHS.get();
+
   // We want to end up calling one of checkPseudoObjectAssignment
   // (if the LHS is a pseudo-object), BuildOverloadedBinOp (if
   // both expressions are overloadable or either is type-dependent),

Modified: cfe/trunk/test/SemaObjC/typo-correction.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/typo-correction.m?rev=313323&r1=313322&r2=313323&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/typo-correction.m (original)
+++ cfe/trunk/test/SemaObjC/typo-correction.m Thu Sep 14 17:08:37 2017
@@ -51,3 +51,23 @@ __attribute__ (( __objc_root_class__ ))
 }
 @end
 
+// rdar://problem/33102722
+// Typo correction for a property when it has as correction candidates
+// synthesized ivar and a class name, both at the same edit distance.
+ at class TypoCandidate;
+
+__attribute__ (( __objc_root_class__ ))
+ at interface PropertyType
+ at property int x;
+ at end
+
+__attribute__ (( __objc_root_class__ ))
+ at interface InterfaceC
+ at property(assign) PropertyType *typoCandidate; // expected-note {{'_typoCandidate' declared here}}
+ at end
+
+ at implementation InterfaceC
+-(void)method {
+  typoCandidate.x = 0; // expected-error {{use of undeclared identifier 'typoCandidate'; did you mean '_typoCandidate'?}}
+}
+ at end

Modified: cfe/trunk/test/SemaObjCXX/typo-correction.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/typo-correction.mm?rev=313323&r1=313322&r2=313323&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/typo-correction.mm (original)
+++ cfe/trunk/test/SemaObjCXX/typo-correction.mm Thu Sep 14 17:08:37 2017
@@ -36,3 +36,22 @@ void invalidNameInIvarAndPropertyBase()
   float a = ((InvalidNameInIvarAndPropertyBase*)node)->_a; // expected-error {{use of undeclared identifier 'node'}}
   float b = ((InvalidNameInIvarAndPropertyBase*)node)._b; // expected-error {{use of undeclared identifier 'node'}}
 }
+
+// rdar://problem/33102722
+// Typo correction for a property when it has as correction candidates
+// synthesized ivar and a class name, both at the same edit distance.
+ at class TypoCandidate;
+
+ at interface PropertyType : NSObject
+ at property int x;
+ at end
+
+ at interface InterfaceC : NSObject
+ at property(assign) PropertyType *typoCandidate; // expected-note {{'_typoCandidate' declared here}}
+ at end
+
+ at implementation InterfaceC
+-(void)method {
+  typoCandidate.x = 0; // expected-error {{use of undeclared identifier 'typoCandidate'; did you mean '_typoCandidate'?}}
+}
+ at end




More information about the cfe-commits mailing list