From ed03170d28872bcbb2de9ae6df76e41d19f72e7d Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Sun, 8 Mar 2009 18:56:13 +0000 Subject: [PATCH] Improvements to private method lookup. Patch by Jean-Daniel Dupas. Thanks! llvm-svn: 66383 --- clang/lib/Sema/Sema.h | 5 +- clang/lib/Sema/SemaExprObjC.cpp | 94 +++++++++++++++++---------- clang/test/SemaObjC/method-lookup-4.m | 62 ++++++++++++++++++ 3 files changed, 124 insertions(+), 37 deletions(-) create mode 100644 clang/test/SemaObjC/method-lookup-4.m diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 28cb9bf7153c..1ef579f687e2 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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 diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 5c8b7b745df2..ef397ca771c1 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -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()) diff --git a/clang/test/SemaObjC/method-lookup-4.m b/clang/test/SemaObjC/method-lookup-4.m new file mode 100644 index 000000000000..f5a20f5a7416 --- /dev/null +++ b/clang/test/SemaObjC/method-lookup-4.m @@ -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