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>. +@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits