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