diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index af756c52ef..745b7888d5 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -139,10 +139,10 @@ namespace { llvm::DenseMap RewrittenBlockExprs; // This maps a property to it's assignment statement. - llvm::DenseMap PropSetters; + llvm::DenseMap PropSetters; // This maps a property to it's synthesied message expression. // This allows us to rewrite chained getters (e.g. o.a.b.c). - llvm::DenseMap PropGetters; + llvm::DenseMap PropGetters; // This maps an original source AST to it's rewritten form. This allows // us to avoid rewriting the same node twice (which is very uncommon). @@ -281,8 +281,8 @@ namespace { Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart, bool &replaced); Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced); - Stmt *RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr); - Stmt *RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, + Stmt *RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr); + Stmt *RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt, SourceRange SrcRange); Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); @@ -1203,40 +1203,55 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { "/* @end */"); } -Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, +Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt, SourceRange SrcRange) { - // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr. + ObjCMethodDecl *OMD = 0; + QualType Ty; + Selector Sel; + Stmt *Receiver; + // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ObjCImplicitSetterGetterRefExpr. // This allows us to reuse all the fun and games in SynthMessageExpr(). - ObjCPropertyRefExpr *PropRefExpr = dyn_cast(BinOp->getLHS()); - ObjCMessageExpr *MsgExpr; - ObjCPropertyDecl *PDecl = PropRefExpr->getProperty(); + if (ObjCPropertyRefExpr *PropRefExpr = dyn_cast(BinOp->getLHS())) { + ObjCPropertyDecl *PDecl = PropRefExpr->getProperty(); + OMD = PDecl->getSetterMethodDecl(); + Ty = PDecl->getType(); + Sel = PDecl->getSetterName(); + Receiver = PropRefExpr->getBase(); + } + else if (ObjCImplicitSetterGetterRefExpr *ImplicitRefExpr = + dyn_cast(BinOp->getLHS())) { + OMD = ImplicitRefExpr->getSetterMethod(); + Sel = OMD->getSelector(); + Ty = ImplicitRefExpr->getType(); + Receiver = ImplicitRefExpr->getBase(); + } + + assert(OMD && "RewritePropertyOrImplicitSetter - null OMD"); llvm::SmallVector ExprVec; ExprVec.push_back(newStmt); - Stmt *Receiver = PropRefExpr->getBase(); - ObjCPropertyRefExpr *PRE = dyn_cast(Receiver); - if (PRE && PropGetters[PRE]) { - // This allows us to handle chain/nested property getters. - Receiver = PropGetters[PRE]; - } + if (Expr *Exp = dyn_cast(Receiver)) + if (PropGetters[Exp]) + // This allows us to handle chain/nested property/implicit getters. + Receiver = PropGetters[Exp]; + + ObjCMessageExpr *MsgExpr; if (isa(Receiver)) MsgExpr = ObjCMessageExpr::Create(*Context, - PDecl->getType().getNonReferenceType(), + Ty.getNonReferenceType(), /*FIXME?*/SourceLocation(), Receiver->getLocStart(), /*IsInstanceSuper=*/true, cast(Receiver)->getType(), - PDecl->getSetterName(), - PDecl->getSetterMethodDecl(), + Sel, OMD, &ExprVec[0], 1, /*FIXME:*/SourceLocation()); else MsgExpr = ObjCMessageExpr::Create(*Context, - PDecl->getType().getNonReferenceType(), + Ty.getNonReferenceType(), /*FIXME: */SourceLocation(), cast(Receiver), - PDecl->getSetterName(), - PDecl->getSetterMethodDecl(), + Sel, OMD, &ExprVec[0], 1, /*FIXME:*/SourceLocation()); Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr); @@ -1250,38 +1265,53 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, return ReplacingStmt; } -Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { - // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr. +Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) { + // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ImplicitGetter. // This allows us to reuse all the fun and games in SynthMessageExpr(). - ObjCMessageExpr *MsgExpr; - ObjCPropertyDecl *PDecl = PropRefExpr->getProperty(); - - Stmt *Receiver = PropRefExpr->getBase(); - - ObjCPropertyRefExpr *PRE = dyn_cast(Receiver); - if (PRE && PropGetters[PRE]) { - // This allows us to handle chain/nested property getters. - Receiver = PropGetters[PRE]; + Stmt *Receiver; + ObjCMethodDecl *OMD = 0; + QualType Ty; + Selector Sel; + if (ObjCPropertyRefExpr *PropRefExpr = + dyn_cast(PropOrGetterRefExpr)) { + ObjCPropertyDecl *PDecl = PropRefExpr->getProperty(); + OMD = PDecl->getGetterMethodDecl(); + Receiver = PropRefExpr->getBase(); + Ty = PDecl->getType(); + Sel = PDecl->getGetterName(); } - + else if (ObjCImplicitSetterGetterRefExpr *ImplicitRefExpr = + dyn_cast(PropOrGetterRefExpr)) { + OMD = ImplicitRefExpr->getGetterMethod(); + Receiver = ImplicitRefExpr->getBase(); + Sel = OMD->getSelector(); + Ty = ImplicitRefExpr->getType(); + } + + assert (OMD && "RewritePropertyOrImplicitGetter - OMD is null"); + + if (Expr *Exp = dyn_cast(Receiver)) + if (PropGetters[Exp]) + // This allows us to handle chain/nested property/implicit getters. + Receiver = PropGetters[Exp]; + + ObjCMessageExpr *MsgExpr; if (isa(Receiver)) MsgExpr = ObjCMessageExpr::Create(*Context, - PDecl->getType().getNonReferenceType(), + Ty.getNonReferenceType(), /*FIXME:*/SourceLocation(), Receiver->getLocStart(), /*IsInstanceSuper=*/true, cast(Receiver)->getType(), - PDecl->getGetterName(), - PDecl->getGetterMethodDecl(), + Sel, OMD, 0, 0, /*FIXME:*/SourceLocation()); else MsgExpr = ObjCMessageExpr::Create(*Context, - PDecl->getType().getNonReferenceType(), + Ty.getNonReferenceType(), /*FIXME:*/SourceLocation(), cast(Receiver), - PDecl->getGetterName(), - PDecl->getGetterMethodDecl(), + Sel, OMD, 0, 0, /*FIXME:*/SourceLocation()); @@ -1290,17 +1320,18 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { if (!PropParentMap) PropParentMap = new ParentMap(CurrentBody); - Stmt *Parent = PropParentMap->getParent(PropRefExpr); - if (Parent && isa(Parent)) { + Stmt *Parent = PropParentMap->getParent(PropOrGetterRefExpr); + if (Parent && (isa(Parent) || + isa(Parent))) { // We stash away the ReplacingStmt since actually doing the // replacement/rewrite won't work for nested getters (e.g. obj.p.i) - PropGetters[PropRefExpr] = ReplacingStmt; + PropGetters[PropOrGetterRefExpr] = ReplacingStmt; // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references // to things that stay around. Context->Deallocate(MsgExpr); - return PropRefExpr; // return the original... + return PropOrGetterRefExpr; // return the original... } else { - ReplaceStmt(PropRefExpr, ReplacingStmt); + ReplaceStmt(PropOrGetterRefExpr, ReplacingStmt); // delete PropRefExpr; elsewhere... // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references // to things that stay around. @@ -1346,7 +1377,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, MemberExpr *ME = new (Context) MemberExpr(PE, true, D, IV->getLocation(), D->getType()); - // delete IV; leak for now, see RewritePropertySetter() usage for more info. + // delete IV; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return ME; } // Get the new text @@ -2024,7 +2055,7 @@ Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { ReplaceStmt(Exp, Replacement); // Replace this subexpr in the parent. - // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return Replacement; } @@ -2042,7 +2073,7 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, &SelExprs[0], SelExprs.size()); ReplaceStmt(Exp, SelExp); - // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return SelExp; } @@ -2588,7 +2619,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CK_Unknown, Unop); ReplaceStmt(Exp, cast); - // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return cast; } @@ -2930,7 +2961,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, MsgExprs.push_back(userExpr); // We've transferred the ownership to MsgExprs. For now, we *don't* null // out the argument in the original expression (since we aren't deleting - // the ObjCMessageExpr). See RewritePropertySetter() usage for more info. + // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info. //Exp->setArg(i, 0); } // Generate the funky cast. @@ -3054,7 +3085,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), CondExpr); } - // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return ReplacingStmt; } @@ -3065,7 +3096,7 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { // Now do the actual rewrite. ReplaceStmt(Exp, ReplacingStmt); - // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return ReplacingStmt; } @@ -3101,7 +3132,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { DerefExpr); ReplaceStmt(Exp, castExpr); ProtocolExprDecls.insert(Exp->getProtocol()); - // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info. return castExpr; } @@ -5325,8 +5356,12 @@ void RewriteObjC::CollectPropertySetters(Stmt *S) { if (BinaryOperator *BinOp = dyn_cast(S)) { if (BinOp->isAssignmentOp()) { - if (ObjCPropertyRefExpr *PRE = dyn_cast(BinOp->getLHS())) + if (ObjCPropertyRefExpr *PRE = + dyn_cast(BinOp->getLHS())) PropSetters[PRE] = BinOp; + else if (ObjCImplicitSetterGetterRefExpr *ISE = + dyn_cast(BinOp->getLHS())) + PropSetters[ISE] = BinOp; } } } @@ -5372,6 +5407,12 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { ++CI; continue; } + if (ObjCImplicitSetterGetterRefExpr *ISE = + dyn_cast(S)) + if (PropSetters[ISE]) { + ++CI; + continue; + } } if (BlockExpr *BE = dyn_cast(S)) { @@ -5398,8 +5439,11 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { if (ObjCEncodeExpr *AtEncode = dyn_cast(S)) return RewriteAtEncode(AtEncode); - if (ObjCPropertyRefExpr *PropRefExpr = dyn_cast(S)) { - BinaryOperator *BinOp = PropSetters[PropRefExpr]; + if (isa(S) || isa(S)) { + Expr *PropOrImplicitRefExpr = dyn_cast(S); + assert(PropOrImplicitRefExpr && "Property or implicit setter/getter is null"); + + BinaryOperator *BinOp = PropSetters[PropOrImplicitRefExpr]; if (BinOp) { // Because the rewriter doesn't allow us to rewrite rewritten code, // we need to rewrite the right hand side prior to rewriting the setter. @@ -5437,18 +5481,19 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { // (CStyleCastExpr 0x231d220 'void *' // (DeclRefExpr 0x231d200 'id (id, SEL, ...)' FunctionDecl='objc_msgSend' 0x231cdc0)))) // - // Note that 'newStmt' is passed to RewritePropertySetter so that it + // Note that 'newStmt' is passed to RewritePropertyOrImplicitSetter so that it // can be used as the setter argument. ReplaceStmt() will still 'see' // the original RHS (since we haven't altered BinOp). // // This implies the Rewrite* routines can no longer delete the original // node. As a result, we now leak the original AST nodes. // - return RewritePropertySetter(BinOp, dyn_cast(newStmt), SrcRange); + return RewritePropertyOrImplicitSetter(BinOp, dyn_cast(newStmt), SrcRange); } else { - return RewritePropertyGetter(PropRefExpr); + return RewritePropertyOrImplicitGetter(PropOrImplicitRefExpr); } } + if (ObjCSelectorExpr *AtSelector = dyn_cast(S)) return RewriteAtSelector(AtSelector); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 38287e4929..92997ecafd 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2531,38 +2531,39 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, return VT; // should never get here (a typedef type should always be found). } -static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, +static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, IdentifierInfo *Member, const Selector &Sel, ASTContext &Context) { - - if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) - return PD; + if (Member) + if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) + return PD; if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) return OMD; for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), E = PDecl->protocol_end(); I != E; ++I) { - if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel, - Context)) + if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, + Context)) return D; } return 0; } -static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, - IdentifierInfo *Member, - const Selector &Sel, - ASTContext &Context) { +static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, + IdentifierInfo *Member, + const Selector &Sel, + ASTContext &Context) { // Check protocols on qualified interfaces. Decl *GDecl = 0; for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), E = QIdTy->qual_end(); I != E; ++I) { - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { - GDecl = PD; - break; - } - // Also must look for a getter name which uses property syntax. + if (Member) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { + GDecl = PD; + break; + } + // Also must look for a getter or setter name which uses property syntax. if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) { GDecl = OMD; break; @@ -2572,7 +2573,8 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), E = QIdTy->qual_end(); I != E; ++I) { // Search in the protocol-qualifier list of current protocol. - GDecl = FindGetterNameDeclFromProtocolList(*I, Member, Sel, Context); + GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, + Context); if (GDecl) return GDecl; } @@ -3273,7 +3275,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Check protocols on qualified interfaces. Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) { + if (Decl *PMDecl = FindGetterSetterNameDecl(QIdTy, Member, Sel, + Context)) { if (ObjCPropertyDecl *PD = dyn_cast(PMDecl)) { // Check the use of this declaration if (DiagnoseUseOfDecl(PD, MemberLoc)) @@ -3286,14 +3289,18 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Check the use of this method. if (DiagnoseUseOfDecl(OMD, MemberLoc)) return ExprError(); - // It is important that start and end position is the first character - // and last character position of the property-dot syntax expression. - SourceLocation MemberEndLoc = PP.getLocForEndOfToken(MemberLoc, 1); - return Owned(ObjCMessageExpr::Create(Context, - OMD->getSendResultType(), - BaseExpr->getExprLoc(), - BaseExpr, Sel, - OMD, NULL, 0, MemberEndLoc)); + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); + ObjCMethodDecl *SMD = 0; + if (Decl *SDecl = FindGetterSetterNameDecl(QIdTy, /*Property id*/0, + SetterSel, Context)) + SMD = dyn_cast(SDecl); + QualType PType = OMD->getSendResultType(); + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(OMD, PType, + SMD, + MemberLoc, + BaseExpr)); } } diff --git a/test/SemaObjC/access-property-getter.m b/test/SemaObjC/access-property-getter.m index 331bb30dd5..afaf82e731 100644 --- a/test/SemaObjC/access-property-getter.m +++ b/test/SemaObjC/access-property-getter.m @@ -30,7 +30,7 @@ @implementation XCWorkQueueCommandCacheFetchInvocation - (id)harvestPredictivelyProcessedOutputFiles { - _outputStream.release; + _outputStream.release; // expected-warning {{property access result unused - getters should not be used for side effects}} return 0; } @end diff --git a/test/SemaObjC/setter-dotsyntax.m b/test/SemaObjC/setter-dotsyntax.m new file mode 100644 index 0000000000..1097464e6c --- /dev/null +++ b/test/SemaObjC/setter-dotsyntax.m @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// rdar: //8528170 + +@interface NSObject @end + +@protocol MyProtocol +- (int) level; +- (void) setLevel:(int)inLevel; +@end + +@interface MyClass : NSObject +@end + +int main () +{ + id c; + c.level = 10; + return 0; +}