r258886 - [analyzer] Body farm: Look for property ivar in shadowing readwrite property.

Devin Coughlin via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 26 15:58:48 PST 2016


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}}
 }
 
+ at interface ClassWithShadowedReadWriteProperty {
+  int _f;
+}
+ at property (readonly) int someProp;
+ at end
+
+ at interface ClassWithShadowedReadWriteProperty ()
+ at property (readwrite) int someProp;
+ at end
+
+ at 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}}
+}
+ at end
+
 #if !__has_feature(objc_arc)
 void testOverrelease(Person *p, int coin) {
   switch (coin) {




More information about the cfe-commits mailing list