From: Fariborz Jahanian Date: Wed, 6 Apr 2011 18:40:08 +0000 (+0000) Subject: Fix lookup for class messages sent to qualified-class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=759abb4d9ec14ae32104a9677b60f0542b60d1d8;p=clang Fix lookup for class messages sent to qualified-class types such that protocols are seached first. Fixes // rdar://9224670 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129016 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 6e8fd4da0d..f2ec27fe31 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1327,6 +1327,7 @@ public: // for object declared using an interface. const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; + const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; const CXXRecordDecl *getCXXRecordDeclForPointerType() const; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4a3391c59e..1abffabf8a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2724,6 +2724,8 @@ def warn_root_inst_method_not_found : Warning< "instance method %0 is being used on 'Class' which is not in the root class">; def warn_class_method_not_found : Warning< "class method %objcclass0 not found (return type defaults to 'id')">; +def warn_instance_method_on_class_found : Warning< + "instance method %0 found instead of class method %1">; def warn_inst_method_not_found : Warning< "instance method %objcinstance0 not found (return type defaults to 'id')">; def error_no_super_class_message : Error< diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 1e2a6c48fd..3224f642bc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -408,6 +408,16 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { return 0; } +const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { + // There is no sugar for ObjCQualifiedClassType's, just return the canonical + // type pointer if it is the right class. + if (const ObjCObjectPointerType *OPT = getAs()) { + if (OPT->isObjCQualifiedClassType()) + return OPT; + } + return 0; +} + const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { if (const ObjCObjectPointerType *OPT = getAs()) { if (OPT->getInterfaceType()) diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 19215c6cfd..c5c991f22c 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1059,39 +1059,53 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. - if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { - // First check the public methods in the class interface. - Method = ClassDecl->lookupClassMethod(Sel); - - if (!Method) - Method = LookupPrivateClassMethod(Sel, ClassDecl); + // We allow sending a message to a qualified Class ("Class"), which + // is ok as long as one of the protocols implements the selector (if not, warn). + if (const ObjCObjectPointerType *QClassTy + = ReceiverType->getAsObjCQualifiedClassType()) { + // Search protocols for class methods. + Method = LookupMethodInQualifiedType(Sel, QClassTy, false); + if (!Method) { + Method = LookupMethodInQualifiedType(Sel, QClassTy, true); + // warn if instance method found for a Class message. + if (Method) { + Diag(Loc, diag::warn_instance_method_on_class_found) + << Method->getSelector() << Sel; + Diag(Method->getLocation(), diag::note_method_declared_at); + } + } + } else { + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { + // First check the public methods in the class interface. + Method = ClassDecl->lookupClassMethod(Sel); - // FIXME: if we still haven't found a method, we need to look in - // protocols (if we have qualifiers). + if (!Method) + Method = LookupPrivateClassMethod(Sel, ClassDecl); + } + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); } - if (Method && DiagnoseUseOfDecl(Method, Loc)) - return ExprError(); - } - if (!Method) { - // If not messaging 'self', look for any factory method named 'Sel'. - if (!Receiver || !isSelfExpr(Receiver)) { - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - true); - if (!Method) { - // If no class (factory) method was found, check if an _instance_ - // method of the same name exists in the root class only. - Method = LookupInstanceMethodInGlobalPool(Sel, + if (!Method) { + // If not messaging 'self', look for any factory method named 'Sel'. + if (!Receiver || !isSelfExpr(Receiver)) { + Method = LookupFactoryMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc), + true); + if (!Method) { + // If no class (factory) method was found, check if an _instance_ + // method of the same name exists in the root class only. + Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), - true); - if (Method) - if (const ObjCInterfaceDecl *ID = - dyn_cast(Method->getDeclContext())) { - if (ID->getSuperClass()) - Diag(Loc, diag::warn_root_inst_method_not_found) - << Sel << SourceRange(LBracLoc, RBracLoc); - } + true); + if (Method) + if (const ObjCInterfaceDecl *ID = + dyn_cast(Method->getDeclContext())) { + if (ID->getSuperClass()) + Diag(Loc, diag::warn_root_inst_method_not_found) + << Sel << SourceRange(LBracLoc, RBracLoc); + } + } } } } diff --git a/test/SemaObjC/class-message-protocol-lookup.m b/test/SemaObjC/class-message-protocol-lookup.m new file mode 100644 index 0000000000..ae64ea8680 --- /dev/null +++ b/test/SemaObjC/class-message-protocol-lookup.m @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// rdar://9224670 + +@interface RandomObject { +@private +} ++ (id)alloc; +@end + +@protocol TestProtocol +- (void)nothingInteresting; +@end + +@protocol Test2Protocol ++ (id)alloc; +- (id)alloc2; // expected-note 2 {{method declared here}} +@end + +@implementation RandomObject +- (void) Meth { + Class c = [c alloc]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}} + Class c1 = [c1 alloc2]; // expected-warning {{instance method 'alloc2' found instead of class method 'alloc2'}} + Class c2 = [c2 alloc]; // ok +} ++ (id)alloc { return 0; } +@end + +int main () +{ + Class c = [c alloc]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}} + Class c1 = [c1 alloc2]; // expected-warning {{instance method 'alloc2' found instead of class method 'alloc2'}} + Class c2 = [c2 alloc]; // ok + return 0; +}