Author: dcoughlin Date: Tue Jan 26 17:58:48 2016 New Revision: 258886 URL: http://llvm.org/viewvc/llvm-project?rev=258886&view=rev Log: [analyzer] Body farm: Look for property ivar in shadowing readwrite property.
After r251874, readonly properties that are shadowed by a readwrite property in a class extension no longer have an instance variable, which caused the body farm to not synthesize getters. Now, if a readonly property does not have an instance variable look for a shadowing property and try to get the instance variable from there. rdar://problem/24060091 Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp cfe/trunk/test/Analysis/properties.m Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=258886&r1=258885&r2=258886&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/BodyFarm.cpp (original) +++ cfe/trunk/lib/Analysis/BodyFarm.cpp Tue Jan 26 17:58:48 2016 @@ -383,10 +383,49 @@ Stmt *BodyFarm::getBody(const FunctionDe return Val.getValue(); } +static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) { + const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl(); + + if (IVar) + return IVar; + + // When a readonly property is shadowed in a class extensions with a + // a readwrite property, the instance variable belongs to the shadowing + // property rather than the shadowed property. If there is no instance + // variable on a readonly property, check to see whether the property is + // shadowed and if so try to get the instance variable from shadowing + // property. + if (!Prop->isReadOnly()) + return nullptr; + + auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext()); + const ObjCInterfaceDecl *PrimaryInterface = nullptr; + if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) { + PrimaryInterface = InterfaceDecl; + } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) { + PrimaryInterface = CategoryDecl->getClassInterface(); + } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) { + PrimaryInterface = ImplDecl->getClassInterface(); + } else { + return nullptr; + } + + // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it + // is guaranteed to find the shadowing property, if it exists, rather than + // the shadowed property. + auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass( + Prop->getIdentifier()); + if (ShadowingProp && ShadowingProp != Prop) { + IVar = ShadowingProp->getPropertyIvarDecl(); + } + + return IVar; +} + static Stmt *createObjCPropertyGetter(ASTContext &Ctx, const ObjCPropertyDecl *Prop) { // First, find the backing ivar. - const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl(); + const ObjCIvarDecl *IVar = findBackingIvar(Prop); if (!IVar) return nullptr; Modified: cfe/trunk/test/Analysis/properties.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/properties.m?rev=258886&r1=258885&r2=258886&view=diff ============================================================================== --- cfe/trunk/test/Analysis/properties.m (original) +++ cfe/trunk/test/Analysis/properties.m Tue Jan 26 17:58:48 2016 @@ -211,6 +211,33 @@ void testConsistencyAssign(Person *p) { clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}} } +@interface ClassWithShadowedReadWriteProperty { + int _f; +} +@property (readonly) int someProp; +@end + +@interface ClassWithShadowedReadWriteProperty () +@property (readwrite) int someProp; +@end + +@implementation ClassWithShadowedReadWriteProperty +- (void)testSynthesisForShadowedReadWriteProperties; { + clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}} + + _f = 1; + + // Read of shadowed property should not invalidate receiver. + (void)self.someProp; + clang_analyzer_eval(_f == 1); // expected-warning{{TRUE}} + + _f = 2; + // Call to getter of shadowed property should not invalidate receiver. + (void)[self someProp]; + clang_analyzer_eval(_f == 2); // expected-warning{{TRUE}} +} +@end + #if !__has_feature(objc_arc) void testOverrelease(Person *p, int coin) { switch (coin) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits