Fix lookup for class messages sent to qualified-class

types such that protocols are seached first. Fixes
// rdar://9224670

llvm-svn: 129016
This commit is contained in:
Fariborz Jahanian 2011-04-06 18:40:08 +00:00
parent 8bca174f48
commit 3b9819b4a2
5 changed files with 92 additions and 31 deletions

View File

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

View File

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

View File

@ -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<ObjCObjectPointerType>()) {
if (OPT->isObjCQualifiedClassType())
return OPT;
}
return 0;
}
const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
if (OPT->getInterfaceType())

View File

@ -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);
// FIXME: if we still haven't found a method, we need to look in
// protocols (if we have qualifiers).
// We allow sending a message to a qualified Class ("Class<foo>"), 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);
}
}
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,
} else {
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);
}
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,
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<ObjCInterfaceDecl>(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<ObjCInterfaceDecl>(Method->getDeclContext())) {
if (ID->getSuperClass())
Diag(Loc, diag::warn_root_inst_method_not_found)
<< Sel << SourceRange(LBracLoc, RBracLoc);
}
}
}
}
}

View File

@ -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<TestProtocol> c = [c alloc]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}}
Class<Test2Protocol> c1 = [c1 alloc2]; // expected-warning {{instance method 'alloc2' found instead of class method 'alloc2'}}
Class<Test2Protocol> c2 = [c2 alloc]; // ok
}
+ (id)alloc { return 0; }
@end
int main ()
{
Class<TestProtocol> c = [c alloc]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}}
Class<Test2Protocol> c1 = [c1 alloc2]; // expected-warning {{instance method 'alloc2' found instead of class method 'alloc2'}}
Class<Test2Protocol> c2 = [c2 alloc]; // ok
return 0;
}