r265103 - [analyzer] Prefer accessor method in extension over category in CallEvent.

Devin Coughlin via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 31 20:24:14 PDT 2016


Author: dcoughlin
Date: Thu Mar 31 22:24:13 2016
New Revision: 265103

URL: http://llvm.org/viewvc/llvm-project?rev=265103&view=rev
Log:
[analyzer] Prefer accessor method in extension over category in CallEvent.

In ObjCMethodCall:getRuntimeDefinition(), if the method is an accessor in a
category, and it doesn't have a self declaration, first try to find the method
in a class extension. This works around a bug in Sema where multiple accessors
are synthesized for properties in class extensions that are redeclared in a
category. The implicit parameters are not filled in for the method on the
category, which causes a crash when trying to synthesize a getter for the
property in BodyFarm. The Sema bug is tracked as rdar://problem/25481164.

rdar://problem/25056531

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
    cfe/trunk/test/Analysis/properties.m

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=265103&r1=265102&r2=265103&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Thu Mar 31 22:24:13 2016
@@ -958,8 +958,30 @@ RuntimeDefinition ObjCMethodCall::getRun
           // even if we don't actually have an implementation.
           if (!*Val)
             if (const ObjCMethodDecl *CompileTimeMD = E->getMethodDecl())
-              if (CompileTimeMD->isPropertyAccessor())
-                Val = IDecl->lookupInstanceMethod(Sel);
+              if (CompileTimeMD->isPropertyAccessor()) {
+                if (!CompileTimeMD->getSelfDecl() &&
+                    isa<ObjCCategoryDecl>(CompileTimeMD->getDeclContext())) {
+                  // If the method is an accessor in a category, and it doesn't
+                  // have a self declaration, first
+                  // try to find the method in a class extension. This
+                  // works around a bug in Sema where multiple accessors
+                  // are synthesized for properties in class
+                  // extensions that are redeclared in a category and the
+                  // the implicit parameters are not filled in for
+                  // the method on the category.
+                  // This ensures we find the accessor in the extension, which
+                  // has the implicit parameters filled in.
+                  auto *ID = CompileTimeMD->getClassInterface();
+                  for (auto *CatDecl : ID->visible_extensions()) {
+                    Val = CatDecl->getMethod(Sel,
+                                             CompileTimeMD->isInstanceMethod());
+                    if (*Val)
+                      break;
+                  }
+                }
+                if (!*Val)
+                  Val = IDecl->lookupInstanceMethod(Sel);
+              }
         }
 
         const ObjCMethodDecl *MD = Val.getValue();

Modified: cfe/trunk/test/Analysis/properties.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/properties.m?rev=265103&r1=265102&r2=265103&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/properties.m (original)
+++ cfe/trunk/test/Analysis/properties.m Thu Mar 31 22:24:13 2016
@@ -247,6 +247,55 @@ void testConsistencyAssign(Person *p) {
 }
 @end
 
+// Tests for the analyzer fix that works around a Sema bug
+// where multiple methods are created for properties in class extensions that
+// are redeclared in a category method.
+// The Sema bug is tracked as <rdar://problem/25481164>.
+ at interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory
+ at end
+
+ at interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory ()
+ at end
+
+ at interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory ()
+ at property (readwrite) int someProp;
+ at property (readonly) int otherProp;
+ at end
+
+ at interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory (MyCat)
+ at property (readonly) int someProp;
+ at property (readonly) int otherProp;
+ at end
+
+ at implementation ClassWithRedeclaredPropertyInExtensionFollowedByCategory
+- (void)testSynthesisForRedeclaredProperties; {
+  clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}}
+  clang_analyzer_eval([self someProp] == self.someProp); // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(self.otherProp == self.otherProp); // expected-warning{{TRUE}}
+  clang_analyzer_eval([self otherProp] == self.otherProp); // expected-warning{{TRUE}}
+}
+ at end
+
+// The relative order of the extension and the category matter, so test both.
+ at interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension
+ at end
+
+ at interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension ()
+ at property (readwrite) int someProp;
+ at end
+
+ at interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension (MyCat)
+ at property (readonly) int someProp;
+ at end
+
+ at implementation ClassWithRedeclaredPropertyInCategoryFollowedByExtension
+- (void)testSynthesisForRedeclaredProperties; {
+  clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}}
+  clang_analyzer_eval([self someProp] == self.someProp); // expected-warning{{TRUE}}
+}
+ at end
+
 @interface ClassWithSynthesizedPropertyAndGetter
 @property (readonly) int someProp;
 @end




More information about the cfe-commits mailing list