]> granicus.if.org Git - clang/commitdiff
Warn for any kind of initialization if initializer does not
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 8 Apr 2011 18:25:29 +0000 (18:25 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 8 Apr 2011 18:25:29 +0000 (18:25 +0000)
implement lhs's protocols. // rdar://9091389.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129142 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclObjC.h
lib/AST/ASTContext.cpp
test/CodeGenObjCXX/references.mm
test/SemaObjC/comptypes-4.m
test/SemaObjC/unqualified-to-qualified-class-warn.m [new file with mode: 0644]
test/SemaObjCXX/references.mm

index 84e7a63b029905f17e870da5aa6eea5bd1708bda..241d76c4487246635da0641fe0efae89ef1d9a51 100644 (file)
@@ -629,6 +629,27 @@ public:
     return false;
   }
 
+  /// getImmSubClassOf - Returns Immediate sub-class of the specified interface class
+  /// if 'Super' is a superclass of this class. null if no such super class.
+  /// So in this example if 'this' is 'BClass' and 'Super' is 'AClass' then 'BClass'
+  /// is returned.
+  /// \code
+  /// @interface BClass : AClass <SubFooable>
+  /// @end
+  /// \endcode
+  
+  ObjCInterfaceDecl *getImmSubClassOf(const ObjCInterfaceDecl *Super) {
+    ObjCInterfaceDecl *ImmSubClass = this;
+    ObjCInterfaceDecl *I = this->getSuperClass();
+    while (I != NULL) {
+      if (Super == I)
+        return ImmSubClass;
+      ImmSubClass = I;
+      I = I->getSuperClass();
+    }
+    return NULL;
+  }
+
   ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName,
                                        ObjCInterfaceDecl *&ClassDeclared);
   ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName) {
index 01e8f8e396760df4bbd510bf4fca473633777abc..39229a7b731e4b2bb31a493e2c83e013f68aa689 100644 (file)
@@ -4981,10 +4981,47 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
   if (LHS->getNumProtocols() == 0)
     return true;
 
-  // Okay, we know the LHS has protocol qualifiers.  If the RHS doesn't, then it
-  // isn't a superset.
-  if (RHS->getNumProtocols() == 0)
-    return true;  // FIXME: should return false!
+  // Okay, we know the LHS has protocol qualifiers.  If the RHS doesn't, 
+  // more detailed analysis is required.
+  if (RHS->getNumProtocols() == 0) {
+    // OK, if LHS is a superclass of RHS *and*
+    // this superclass is assignment compatible with LHS.
+    // false otherwise.
+    ObjCInterfaceDecl *SuperClass = 
+      RHS->getInterface()->getImmSubClassOf(LHS->getInterface());
+    if (SuperClass) {
+      // OK if conversion of LHS to SuperClass results in narrowing of types
+      // ; i.e., SuperClass may implement at least one of the protocols
+      // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
+      // But not SuperObj<P1,P2,P3> = lhs<P1,P2>.
+      llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols;
+      CollectInheritedProtocols(SuperClass, SuperClassInheritedProtocols);
+      // If super class has no protocols, it is not a match.
+      if (SuperClassInheritedProtocols.empty())
+        return false;
+      
+      for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
+           LHSPE = LHS->qual_end();
+           LHSPI != LHSPE; LHSPI++) {
+        bool SuperImplementsProtocol = false;
+        ObjCProtocolDecl *LHSProto = (*LHSPI);
+        
+        for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
+             SuperClassInheritedProtocols.begin(),
+             E = SuperClassInheritedProtocols.end(); I != E; ++I) {
+          ObjCProtocolDecl *SuperClassProto = (*I);
+          if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) {
+            SuperImplementsProtocol = true;
+            break;
+          }
+        }
+        if (!SuperImplementsProtocol)
+          return false;
+      }
+      return true;
+    }
+    return false;
+  }
 
   for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
                                      LHSPE = LHS->qual_end();
index 8875fd62407440359b1e21d0a00f8058f0f3a94b..6265c7be7613fc970f0486b4e8c40f928f02c706 100644 (file)
@@ -30,7 +30,7 @@ void f(B* b) {
 @protocol P2 @end
 @protocol P3 @end
 @interface foo<P1> {} @end
-@interface bar : foo <P1, P2> {} @end
+@interface bar : foo <P1, P2, P3> {} @end
 typedef bar baz;
 void f5(foo&);
 void f5b(foo<P1>&);
index 56b23b22458fe2f8bec353ccd197e3d415a242ba..adc324c91ee5cb96e066dc241cbfe8b89d03fa0b 100644 (file)
@@ -12,7 +12,7 @@ int main()
   MyClass *obj_cp;
 
   obj_cp = obj_p;  
-  obj_p = obj_cp;
+  obj_p = obj_cp;      // expected-warning {{incompatible pointer types assigning to 'MyClass<MyProtocol> *' from 'MyClass *'}}
 
   if (obj_cp == obj_p)
     foo();
diff --git a/test/SemaObjC/unqualified-to-qualified-class-warn.m b/test/SemaObjC/unqualified-to-qualified-class-warn.m
new file mode 100644 (file)
index 0000000..5bbbfd9
--- /dev/null
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1  -fsyntax-only -verify %s
+// rdar://9091389
+
+@protocol Fooable
+- (void)foo;
+@end
+
+@protocol SubFooable <Fooable>
+@end
+
+@interface AClass
+@end
+
+@interface BClass : AClass <SubFooable>
+@end
+
+@implementation BClass
+- (void)foo {
+}
+@end
+
+void functionTakingAClassConformingToAProtocol(AClass <Fooable> *instance) { // expected-note {{passing argument to parameter 'instance' here}}
+}
+
+int main () {
+    AClass *aobject = 0;
+    BClass *bobject = 0;
+    functionTakingAClassConformingToAProtocol(aobject);  // expected-warning {{incompatible pointer types passing 'AClass *' to parameter of type 'AClass<Fooable> *'}}
+    functionTakingAClassConformingToAProtocol(bobject); // Shouldn't warn -  does implement Fooable
+    return 0;
+}
index 585c75f3cdf9567e2652a98d89c449538cdd5496..3a522005abee44c66b222d464637b5aaa7542419 100644 (file)
@@ -37,7 +37,7 @@ void f4(NSString &tmpstr) {
 @protocol P2 @end
 @protocol P3 @end
 @interface foo<P1> {} @end
-@interface bar : foo <P1, P2> {} @end
+@interface bar : foo <P1, P2, P3> {} @end
 typedef bar baz;
 
 struct ToBar {