Improvements to private method lookup.

Patch by Jean-Daniel Dupas. Thanks!

llvm-svn: 66383
This commit is contained in:
Steve Naroff 2009-03-08 18:56:13 +00:00
parent d5ac9d87b4
commit ed03170d28
3 changed files with 124 additions and 37 deletions

View File

@ -1786,7 +1786,10 @@ public:
// Will search "local" class/category implementations for a method decl.
// Will also search in class's root looking for instance method.
// Returns 0 if no method is found.
ObjCMethodDecl *LookupPrivateOrRootMethod(Selector Sel, ObjCInterfaceDecl *CDecl);
ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel,
ObjCInterfaceDecl *CDecl);
ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl);
// ActOnClassMessage - used for both unary and keyword messages.
// ArgExprs is optional - if it is present, the number of expressions

View File

@ -213,29 +213,56 @@ bool Sema::isSelfExpr(Expr *RExpr) {
// Will search "local" class/category implementations for a method decl.
// If failed, then we search in class's root for an instance method.
// Returns 0 if no method is found.
ObjCMethodDecl *Sema::LookupPrivateOrRootMethod(Selector Sel,
ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl) {
ObjCMethodDecl *Method = 0;
if (ObjCImplementationDecl *ImpDecl =
ObjCImplementations[ClassDecl->getIdentifier()])
Method = ImpDecl->getClassMethod(Sel);
// lookup in class and all superclasses
while (ClassDecl && !Method) {
if (ObjCImplementationDecl *ImpDecl =
ObjCImplementations[ClassDecl->getIdentifier()])
Method = ImpDecl->getClassMethod(Sel);
// Look through local category implementations associated with the class.
if (!Method) {
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
Method = ObjCCategoryImpls[i]->getClassMethod(Sel);
// Look through local category implementations associated with the class.
if (!Method) {
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
Method = ObjCCategoryImpls[i]->getClassMethod(Sel);
}
}
// Before we give up, check if the selector is an instance method.
// But only in the root. This matches gcc's behaviour and what the
// runtime expects.
if (!Method && !ClassDecl->getSuperClass()) {
Method = ClassDecl->lookupInstanceMethod(Sel);
// Look through local category implementations associated
// with the root class.
if (!Method)
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
}
ClassDecl = ClassDecl->getSuperClass();
}
// Before we give up, check if the selector is an instance method.
// But only in the root. This matches gcc's behaviour and what the
// runtime expects.
if (!Method) {
ObjCInterfaceDecl *Root = ClassDecl;
while (Root->getSuperClass())
Root = Root->getSuperClass();
Method = Root->lookupInstanceMethod(Sel);
return Method;
}
ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl) {
ObjCMethodDecl *Method = 0;
while (ClassDecl && !Method) {
// If we have implementations in scope, check "private" methods.
if (ObjCImplementationDecl *ImpDecl =
ObjCImplementations[ClassDecl->getIdentifier()])
Method = ImpDecl->getInstanceMethod(Sel);
// Look through local category implementations associated with the class.
if (!Method) {
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
Method = ObjCCategoryImpls[i]->getInstanceMethod(Sel);
}
}
ClassDecl = ClassDecl->getSuperClass();
}
return Method;
}
@ -321,7 +348,7 @@ Sema::ExprResult Sema::ActOnClassMessage(
// If we have an implementation in scope, check "private" methods.
if (!Method)
Method = LookupPrivateOrRootMethod(Sel, ClassDecl);
Method = LookupPrivateClassMethod(Sel, ClassDecl);
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
return true;
@ -367,8 +394,13 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
// If we have an interface in scope, check 'super' methods.
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass())
if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) {
Method = SuperDecl->lookupInstanceMethod(Sel);
if (!Method)
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, SuperDecl);
}
}
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
@ -405,7 +437,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
Method = ClassDecl->lookupClassMethod(Sel);
if (!Method)
Method = LookupPrivateOrRootMethod(Sel, ClassDecl);
Method = LookupPrivateClassMethod(Sel, ClassDecl);
}
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
return true;
@ -467,24 +499,14 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
}
}
if (!Method) {
// If we have an implementation in scope, check "private" methods.
if (ClassDecl) {
if (ObjCImplementationDecl *ImpDecl =
ObjCImplementations[ClassDecl->getIdentifier()])
Method = ImpDecl->getInstanceMethod(Sel);
// Look through local category implementations associated with the class.
if (!Method) {
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
Method = ObjCCategoryImpls[i]->getInstanceMethod(Sel);
}
}
}
if (!isSelfExpr(RExpr)) {
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
if (!Method && !isSelfExpr(RExpr)) {
// If we still haven't found a method, look in the global pool. This
// behavior isn't very desirable, however we need it for GCC
// compatibility. FIXME: should we deviate??
if (!Method && OCIType->qual_empty()) {
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
if (Method && !OCIType->getDecl()->isForwardDecl())

View File

@ -0,0 +1,62 @@
// RUN: clang -fsyntax-only -verify %s
@interface NSObject {}
@end
@interface MyClass : NSObject {}
@end
@interface MyClass (MyCategorie)
@end
@interface MySubClass : MyClass {}
@end
@interface MySubSubClass : MySubClass {}
@end
@implementation NSObject (NSObjectCategory)
- (void)rootMethod {}
@end
@implementation MyClass
+ (void)myClassMethod { }
- (void)myMethod { }
@end
@implementation MyClass (MyCategorie)
+ (void)myClassCategoryMethod { }
- (void)categoryMethod {}
@end
@implementation MySubClass
- (void)mySubMethod {}
- (void)myTest {
[self mySubMethod];
// should lookup method in superclass implementation if available
[self myMethod];
[super myMethod];
[self categoryMethod];
[super categoryMethod];
// instance method of root class
[MyClass rootMethod];
[MyClass myClassMethod];
[MySubClass myClassMethod];
[MyClass myClassCategoryMethod];
[MySubClass myClassCategoryMethod];
}
@end