Treat hidden Objective-C protocol definitions as if they were
authorDouglas Gregor <dgregor@apple.com>
Thu, 17 Jan 2013 00:38:46 +0000 (00:38 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 17 Jan 2013 00:38:46 +0000 (00:38 +0000)
undefined, and don't find methods or protocols within those protocol
definitions. This completes <rdar://problem/10634711>.

llvm-svn: 172686

clang/lib/AST/DeclObjC.cpp
clang/lib/Sema/SemaDeclObjC.cpp
clang/test/Modules/Inputs/category_left_sub.h
clang/test/Modules/Inputs/category_right_sub.h
clang/test/Modules/Inputs/category_top.h
clang/test/Modules/objc-categories.m

index 0b1a1ec..b99c45c 100644 (file)
@@ -66,6 +66,14 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
 // Get the local instance/class method declared in this interface.
 ObjCMethodDecl *
 ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
+  // If this context is a hidden protocol definition, don't find any
+  // methods there.
+  if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+    if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+      if (Def->isHidden())
+        return 0;
+  }
+
   // Since instance & class methods can have the same name, the loop below
   // ensures we get the correct method.
   //
@@ -87,6 +95,13 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
 ObjCPropertyDecl *
 ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
                                    IdentifierInfo *propertyID) {
+  // If this context is a hidden protocol definition, don't find any
+  // property.
+  if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
+    if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+      if (Def->isHidden())
+        return 0;
+  }
 
   DeclContext::lookup_const_result R = DC->lookup(propertyID);
   for (DeclContext::lookup_const_iterator I = R.begin(), E = R.end(); I != E;
@@ -111,6 +126,12 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
 /// in 'PropertyId' and returns it. It returns 0, if not found.
 ObjCPropertyDecl *
 ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
+  // Don't find properties within hidden protocol definitions.
+  if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+    if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+      if (Def->isHidden())
+        return 0;
+  }
 
   if (ObjCPropertyDecl *PD =
         ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
@@ -1343,6 +1364,12 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
                                                bool isInstance) const {
   ObjCMethodDecl *MethodDecl = NULL;
 
+  // If there is no definition or the definition is hidden, we don't find
+  // anything.
+  const ObjCProtocolDecl *Def = getDefinition();
+  if (!Def || Def->isHidden())
+    return NULL;
+
   if ((MethodDecl = getMethod(Sel, isInstance)))
     return MethodDecl;
 
index 54cf1c2..0ffdceb 100644 (file)
@@ -743,7 +743,9 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
 
     // If this is a forward declaration and we are supposed to warn in this
     // case, do it.
-    if (WarnOnDeclarations && !PDecl->hasDefinition())
+    // FIXME: Recover nicely in the hidden case.
+    if (WarnOnDeclarations &&
+        (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()))
       Diag(ProtocolId[i].second, diag::warn_undef_protocolref)
         << ProtocolId[i].first;
     Protocols.push_back(PDecl);
index bee8617..d92a873 100644 (file)
@@ -1,3 +1,11 @@
 @interface Foo(LeftSub) <P1>
 - (void)left_sub;
 @end
+
+@protocol P3 
+- (void)p3_method;
+@property (retain) id p3_prop;
+@end
+
+@interface Foo(LeftP3) <P3>
+@end
index 696b6ca..231f65f 100644 (file)
@@ -7,3 +7,11 @@
   int right_sub_ivar;
 }
 @end
+
+@protocol P4
+- (void)p4_method;
+@property (retain) id p4_prop;
+@end
+
+@interface Foo(LeftP4) <P4>
+@end
index 05a66ca..ba4cce2 100644 (file)
@@ -47,6 +47,14 @@ void test_hidden_all_errors(Foo *foo) {
   int i = foo->right_sub_ivar; // expected-error{{'Foo' does not have a member named 'right_sub_ivar'}}
   id<P1> p1 = foo; // expected-warning{{initializing 'id<P1>' with an expression of incompatible type 'Foo *'}}
   id<P2> p2 = foo; // expected-warning{{initializing 'id<P2>' with an expression of incompatible type 'Foo *'}}
+  id<P3> p3;
+  [p3 p3_method]; // expected-warning{{instance method '-p3_method' not found (return type defaults to 'id')}}
+  id<P4> p4;
+  [p4 p4_method]; // expected-warning{{instance method '-p4_method' not found (return type defaults to 'id')}}
+  id p3p = p3.p3_prop; // expected-error{{property 'p3_prop' not found on object of type 'id<P3>'}}
+  p3p = foo.p3_prop; // expected-error{{property 'p3_prop' not found on object of type 'Foo *'}}
+  id p4p = p4.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'id<P4>'}}
+  p4p = foo.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'Foo *'}}
 }
 
 @import category_left.sub;
@@ -55,10 +63,19 @@ void test_hidden_right_errors(Foo *foo) {
   // These are okay
   [foo left_sub]; // okay
   id<P1> p1 = foo;
-  // FIXME: these should fail
+  id<P3> p3;
+  [p3 p3_method];
+  id p3p = p3.p3_prop;
+  p3p = foo.p3_prop;
+  // These should fail
   foo.right_sub_prop = foo; // expected-error{{property 'right_sub_prop' not found on object of type 'Foo *'}}
   int i = foo->right_sub_ivar; // expected-error{{'Foo' does not have a member named 'right_sub_ivar'}}
   id<P2> p2 = foo; // expected-warning{{initializing 'id<P2>' with an expression of incompatible type 'Foo *'}}
+  id<P4> p4;
+  [p4 p4_method]; // expected-warning{{instance method '-p4_method' not found (return type defaults to 'id')}}
+  id p4p = p4.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'id<P4>'}}
+  p4p = foo.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'Foo *'; did you mean 'p3_prop'?}}
+  // expected-note@7{{'p3_prop' declared here}}
 }
 
 @import category_right.sub;
@@ -69,4 +86,12 @@ void test_hidden_okay(Foo *foo) {
   int i = foo->right_sub_ivar;
   id<P1> p1 = foo;
   id<P2> p2 = foo;
+  id<P3> p3;
+  [p3 p3_method];
+  id<P4> p4;
+  [p4 p4_method];
+  id p3p = p3.p3_prop;
+  p3p = foo.p3_prop;
+  id p4p = p4.p4_prop;
+  p4p = foo.p4_prop;
 }