[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

llvm-svn: 265103
This commit is contained in:
Devin Coughlin 2016-04-01 03:24:13 +00:00
parent 85fb9e058e
commit c239dd1349
2 changed files with 73 additions and 2 deletions

View File

@ -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<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();

View File

@ -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