diff options
| author | Devin Coughlin <dcoughlin@apple.com> | 2016-01-26 23:58:48 +0000 |
|---|---|---|
| committer | Devin Coughlin <dcoughlin@apple.com> | 2016-01-26 23:58:48 +0000 |
| commit | b7e810bdc139c6fd48fe1208c719247024753855 (patch) | |
| tree | 4a2455c5ba92d1d258688a0e31b8def48fa0eda0 | |
| parent | 511328817d259076e549de381c72c19c53f7a6f6 (diff) | |
| download | bcm5719-llvm-b7e810bdc139c6fd48fe1208c719247024753855.tar.gz bcm5719-llvm-b7e810bdc139c6fd48fe1208c719247024753855.zip | |
[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
llvm-svn: 258886
| -rw-r--r-- | clang/lib/Analysis/BodyFarm.cpp | 41 | ||||
| -rw-r--r-- | clang/test/Analysis/properties.m | 27 |
2 files changed, 67 insertions, 1 deletions
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index 09904369ba9..325c3261374 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -383,10 +383,49 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) { 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; diff --git a/clang/test/Analysis/properties.m b/clang/test/Analysis/properties.m index bf9424c8c20..4fdbb69d87a 100644 --- a/clang/test/Analysis/properties.m +++ b/clang/test/Analysis/properties.m @@ -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) { |

