} 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<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);
+ }
+ }
+ } 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<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);
+ }
+ }
}
}
}
--- /dev/null
+// 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;
+}