summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDevin Coughlin <dcoughlin@apple.com>2016-01-26 23:58:48 +0000
committerDevin Coughlin <dcoughlin@apple.com>2016-01-26 23:58:48 +0000
commitb7e810bdc139c6fd48fe1208c719247024753855 (patch)
tree4a2455c5ba92d1d258688a0e31b8def48fa0eda0
parent511328817d259076e549de381c72c19c53f7a6f6 (diff)
downloadbcm5719-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.cpp41
-rw-r--r--clang/test/Analysis/properties.m27
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) {
OpenPOWER on IntegriCloud