]> granicus.if.org Git - clang/commitdiff
Fix lookup for class messages sent to qualified-class
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 6 Apr 2011 18:40:08 +0000 (18:40 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 6 Apr 2011 18:40:08 +0000 (18:40 +0000)
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

include/clang/AST/Type.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/Type.cpp
lib/Sema/SemaExprObjC.cpp
test/SemaObjC/class-message-protocol-lookup.m [new file with mode: 0644]

index 6e8fd4da0dbd526aeab233ec93bbd17056788f12..f2ec27fe31adc24e6331b67fa2d34b31df78c39a 100644 (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;
 
index 4a3391c59eb9d62cd169a96183e73c3f890c1e74..1abffabf8a7654f1ef1f62dbeee820cc40074988 100644 (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<
index 1e2a6c48fddda636025a5f75c6c37cc89e473d64..3224f642bc6f396ee9df00f3e2bf21a0edd4c746 100644 (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())
index 19215c6cfd693ed0e64995faa5339bdccdaa9070..c5c991f22cc774b418d676d2943bd262d658fc77 100644 (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);
+      // 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);
+                  }
+            }
           }
         }
       }
diff --git a/test/SemaObjC/class-message-protocol-lookup.m b/test/SemaObjC/class-message-protocol-lookup.m
new file mode 100644 (file)
index 0000000..ae64ea8
--- /dev/null
@@ -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;
+}