зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
8f1cc075c3
Коммит
759abb4d9e
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
Загрузка…
Ссылка в новой задаче