From 9a9ef84ee01c50e33dd065bb549a030b79c61beb Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Fri, 1 Apr 2016 03:24:13 +0000 Subject: [PATCH] [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@265103 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/CallEvent.cpp | 26 ++++++++++++-- test/Analysis/properties.m | 49 +++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 2c7b5302dd..626775846b 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -958,8 +958,30 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { // 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(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(); diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m index d79643f8b6..3b0312507e 100644 --- a/test/Analysis/properties.m +++ b/test/Analysis/properties.m @@ -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 . +@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory +@end + +@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory () +@end + +@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory () +@property (readwrite) int someProp; +@property (readonly) int otherProp; +@end + +@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory (MyCat) +@property (readonly) int someProp; +@property (readonly) int otherProp; +@end + +@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}} +} +@end + +// The relative order of the extension and the category matter, so test both. +@interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension +@end + +@interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension () +@property (readwrite) int someProp; +@end + +@interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension (MyCat) +@property (readonly) int someProp; +@end + +@implementation ClassWithRedeclaredPropertyInCategoryFollowedByExtension +- (void)testSynthesisForRedeclaredProperties; { + clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}} + clang_analyzer_eval([self someProp] == self.someProp); // expected-warning{{TRUE}} +} +@end + @interface ClassWithSynthesizedPropertyAndGetter @property (readonly) int someProp; @end -- 2.40.0