]> granicus.if.org Git - clang/commitdiff
Patch to implemented objective-c's dynamic object pointer qualified with
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 17 Dec 2007 21:03:50 +0000 (21:03 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 17 Dec 2007 21:03:50 +0000 (21:03 +0000)
the protocol list (id<P,...> types).

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

14 files changed:
AST/ASTContext.cpp
AST/Type.cpp
AST/TypeSerialization.cpp
CodeGen/CodeGenTypes.cpp
Driver/RewriteTest.cpp
Sema/SemaExpr.cpp
Sema/SemaType.cpp
clang.xcodeproj/project.pbxproj
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
include/clang/Basic/DiagnosticKinds.def
test/Sema/id-test-3.m [new file with mode: 0644]
test/Sema/protocol-id-test-1.m [new file with mode: 0644]
test/Sema/protocol-id-test-2.m [new file with mode: 0644]

index 4351b89e9609151e0a3e66cb06ea03f3fc5831fa..92b691ee9017a69eb89852c79a6310d3c0ddf141 100644 (file)
@@ -49,6 +49,7 @@ void ASTContext::PrintStats() const {
   
   unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0;
   unsigned NumObjcInterfaces = 0, NumObjcQualifiedInterfaces = 0;
+  unsigned NumObjcQualifiedIds = 0;
   
   for (unsigned i = 0, e = Types.size(); i != e; ++i) {
     Type *T = Types[i];
@@ -83,6 +84,8 @@ void ASTContext::PrintStats() const {
       ++NumObjcInterfaces;
     else if (isa<ObjcQualifiedInterfaceType>(T))
       ++NumObjcQualifiedInterfaces;
+    else if (isa<ObjcQualifiedIdType>(T))
+      ++NumObjcQualifiedIds;
     else {
       QualType(T, 0).dump();
       assert(0 && "Unknown type!");
@@ -106,6 +109,8 @@ void ASTContext::PrintStats() const {
   fprintf(stderr, "    %d interface types\n", NumObjcInterfaces);
   fprintf(stderr, "    %d protocol qualified interface types\n",
           NumObjcQualifiedInterfaces);
+  fprintf(stderr, "    %d protocol qualified id types\n",
+          NumObjcQualifiedIds);
   fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
     NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
     NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+
@@ -677,7 +682,7 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
   if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
   
   QualType Canonical = Decl->getUnderlyingType().getCanonicalType();
-  Decl->TypeForDecl = new TypedefType(Decl, Canonical);
+  Decl->TypeForDecl = new TypedefType(Type::TypeName, Decl, Canonical);
   Types.push_back(Decl->TypeForDecl);
   return QualType(Decl->TypeForDecl, 0);
 }
@@ -713,6 +718,29 @@ QualType ASTContext::getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl,
   return QualType(QType, 0);
 }
 
+/// getObjcQualifiedIdType - Return a 
+/// getObjcQualifiedIdType type for the given interface decl and
+/// the conforming protocol list.
+QualType ASTContext::getObjcQualifiedIdType(TypedefDecl *Decl,
+                                            ObjcProtocolDecl **Protocols, 
+                                            unsigned NumProtocols) {
+  llvm::FoldingSetNodeID ID;
+  ObjcQualifiedIdType::Profile(ID, Protocols, NumProtocols);
+  
+  void *InsertPos = 0;
+  if (ObjcQualifiedIdType *QT =
+      ObjcQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos))
+    return QualType(QT, 0);
+  
+  // No Match;
+  QualType Canonical = Decl->getUnderlyingType().getCanonicalType();
+  ObjcQualifiedIdType *QType =
+  new ObjcQualifiedIdType(Decl, Canonical, Protocols, NumProtocols);
+  Types.push_back(QType);
+  ObjcQualifiedIdTypes.InsertNode(QType, InsertPos);
+  return QualType(QType, 0);
+}
+
 /// getTypeOfExpr - Unlike many "get<Type>" functions, we can't unique
 /// TypeOfExpr AST's (since expression's are never shared). For example,
 /// multiple declarations that refer to "typeof(x)" all contain different
@@ -1043,7 +1071,13 @@ void ASTContext::getObjcEncodingForType(QualType T, std::string& S) const
     }
     
     S += encoding;
-  } else if (const PointerType *PT = T->getAsPointerType()) {
+  }
+  else if (const ObjcQualifiedIdType *QIT = dyn_cast<ObjcQualifiedIdType>(T)) {
+    // Treat id<P...> same as 'id' for encoding purposes.
+    return getObjcEncodingForType(QIT->getDecl()->getUnderlyingType(), S);
+    
+  }
+  else if (const PointerType *PT = T->getAsPointerType()) {
     QualType PointeeTy = PT->getPointeeType();
     if (isObjcIdType(PointeeTy) || PointeeTy->isObjcInterfaceType()) {
       S += '@';
@@ -1221,6 +1255,13 @@ bool ASTContext::QualifiedInterfaceTypesAreCompatible(QualType lhs,
   return true;
 }
 
+// TODO: id<P1,...> vs. id<P,...>
+#if 0
+bool ASTContext::QualifiedIdTypesAreCompatible(QualType lhs, 
+                                                      QualType rhs) {
+}
+#endif
+
 bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) {
   const VectorType *lVector = lhs->getAsVectorType();
   const VectorType *rVector = rhs->getAsVectorType();
index b1da04b0a310a34ac47de8e8c6d0459e9f9def04..63f3589769552e9096f5f652f6a6d62a2654be41 100644 (file)
@@ -539,6 +539,17 @@ void ObjcQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
   Profile(ID, &Protocols[0], getNumProtocols());
 }
 
+void ObjcQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID,
+                                         ObjcProtocolDecl **protocols, 
+                                         unsigned NumProtocols) {
+  for (unsigned i = 0; i != NumProtocols; i++)
+    ID.AddPointer(protocols[i]);
+}
+
+void ObjcQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) {
+  Profile(ID, &Protocols[0], getNumProtocols());
+}
+
 /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
 /// potentially looking through *all* consequtive typedefs.  This returns the
 /// sum of the type qualifiers, so if you have:
@@ -780,6 +791,22 @@ void ObjcQualifiedInterfaceType::getAsStringInternal(
   InnerString = ObjcQIString + InnerString;
 }
 
+void ObjcQualifiedIdType::getAsStringInternal(
+                                              std::string &InnerString) const {
+  if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
+    InnerString = ' ' + InnerString;
+  std::string ObjcQIString = "id";
+  ObjcQIString += '<';
+  int num = getNumProtocols();
+  for (int i = 0; i < num; i++) {
+    ObjcQIString += getProtocols(i)->getName();
+    if (i < num-1)
+      ObjcQIString += ',';
+  }
+  ObjcQIString += '>';
+  InnerString = ObjcQIString + InnerString;
+}
+
 void TagType::getAsStringInternal(std::string &InnerString) const {
   if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
     InnerString = ' ' + InnerString;
index 10965c24219af87d7dd8d15c81fd48273e43d11d..a3b99ed8a5a54472e6381bbd9dc7040158073a45 100644 (file)
@@ -224,7 +224,7 @@ Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) {
   std::vector<Type*>& Types = 
     const_cast<std::vector<Type*>&>(Context.getTypes());
   
-  TypedefType* T = new TypedefType(NULL,QualType::ReadVal(D));
+  TypedefType* T = new TypedefType(Type::TypeName, NULL,QualType::ReadVal(D));
   Types.push_back(T);
   
   D.ReadPtr(T->Decl); // May be backpatched.
index cc40af8f941a962b10c72cc8e1ba23528ffe70a1..ac223bcd246c781fc86ff7b6b2f33c41c618d817 100644 (file)
@@ -251,6 +251,10 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
     assert(0 && "FIXME: add missing functionality here");
     break;
 
+  case Type::ObjcQualifiedId:
+    assert(0 && "FIXME: add missing functionality here");
+    break;
+
   case Type::Tagged:
     const TagType &TT = cast<TagType>(Ty);
     const TagDecl *TD = TT.getDecl();
index 37f2901ad26aeac384ce78506f8d5024b616e94a..30b1e98af07e489a30495644110a825661584f3e 100644 (file)
@@ -490,7 +490,10 @@ void RewriteTest::RewriteForwardProtocolDecl(ObjcForwardProtocolDecl *PDecl) {
 void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD, 
                                         std::string &ResultStr) {
   ResultStr += "\nstatic ";
-  ResultStr += OMD->getResultType().getAsString();
+  if (isa<ObjcQualifiedIdType>(OMD->getResultType()))
+    ResultStr += "id";
+  else
+    ResultStr += OMD->getResultType().getAsString();
   ResultStr += "\n";
   
   // Unique method name
@@ -548,7 +551,10 @@ void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD,
   for (int i = 0; i < OMD->getNumParams(); i++) {
     ParmVarDecl *PDecl = OMD->getParamDecl(i);
     ResultStr += ", ";
-    ResultStr += PDecl->getType().getAsString();
+    if (isa<ObjcQualifiedIdType>(PDecl->getType()))
+      ResultStr += "id";
+    else
+      ResultStr += PDecl->getType().getAsString();
     ResultStr += " ";
     ResultStr += PDecl->getName();
   }
@@ -989,10 +995,13 @@ static void scanToNextArgument(const char *&argRef) {
 }
 
 bool RewriteTest::needToScanForQualifiers(QualType T) {
-  // FIXME: we don't currently represent "id <Protocol>" in the type system.
+  
   if (T == Context->getObjcIdType())
     return true;
     
+  if (isa<ObjcQualifiedIdType>(T))
+    return true;
+  
   if (const PointerType *pType = T->getAsPointerType()) {
     Type *pointeeType = pType->getPointeeType().getTypePtr();
     if (isa<ObjcQualifiedInterfaceType>(pointeeType))
@@ -1311,6 +1320,9 @@ ObjcInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) {
       if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
         if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
           if (!strcmp(PVD->getName(), "self")) {
+            // is this id<P1..> type?
+            if (isa<ObjcQualifiedIdType>(CE->getType()))
+              return 0;
             if (const PointerType *PT = CE->getType()->getAsPointerType()) {
               if (ObjcInterfaceType *IT = 
                     dyn_cast<ObjcInterfaceType>(PT->getPointeeType())) {
@@ -1504,7 +1516,9 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
     // Make all implicit casts explicit...ICE comes in handy:-)
     if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
       // Reuse the ICE type, it is exactly what the doctor ordered.
-      userExpr = new CastExpr(ICE->getType(), userExpr, SourceLocation());
+      userExpr = new CastExpr(isa<ObjcQualifiedIdType>(ICE->getType()) 
+                                ? Context->getObjcIdType()
+                                : ICE->getType(), userExpr, SourceLocation());
     } 
     MsgExprs.push_back(userExpr);
     // We've transferred the ownership to MsgExprs. Null out the argument in
@@ -1525,10 +1539,13 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
   if (ObjcMethodDecl *mDecl = Exp->getMethodDecl()) {
     // Push any user argument types.
     for (int i = 0; i < mDecl->getNumParams(); i++) {
-      QualType t = mDecl->getParamDecl(i)->getType();
+      QualType t = isa<ObjcQualifiedIdType>(mDecl->getParamDecl(i)->getType()) 
+                     ? Context->getObjcIdType() 
+                     : mDecl->getParamDecl(i)->getType();
       ArgTypes.push_back(t);
     }
-    returnType = mDecl->getResultType();
+    returnType = isa<ObjcQualifiedIdType>(mDecl->getResultType()) 
+                   ? Context->getObjcIdType() : mDecl->getResultType();
   } else {
     returnType = Context->getObjcIdType();
   }
index dae5325ac40837ba05b800880bfee5671500b9ee..45d04705447b98a8f10a861cfa1e66e641c8646c 100644 (file)
@@ -2292,13 +2292,16 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
           return true;
     }
   } else {
+    bool receiverIsQualId = 
+           dyn_cast<ObjcQualifiedIdType>(RExpr->getType()) != 0;
     // FIXME (snaroff): checking in this code from Patrick. Needs to be
     // revisited. how do we get the ClassDecl from the receiver expression?
-    while (receiverType->isPointerType()) {
-      PointerType *pointerType =
-        static_cast<PointerType*>(receiverType.getTypePtr());
-      receiverType = pointerType->getPointeeType();
-    }
+    if (!receiverIsQualId)
+      while (receiverType->isPointerType()) {
+        PointerType *pointerType =
+          static_cast<PointerType*>(receiverType.getTypePtr());
+        receiverType = pointerType->getPointeeType();
+      }
     ObjcInterfaceDecl* ClassDecl;
     if (ObjcQualifiedInterfaceType *QIT = 
         dyn_cast<ObjcQualifiedInterfaceType>(receiverType)) {
@@ -2312,6 +2315,23 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
             break;
         }
       }
+      if (!Method)
+        Diag(lbrac, diag::warn_method_not_found_in_protocol, 
+             std::string("-"), Sel.getName(),
+             SourceRange(lbrac, rbrac));
+    }
+    else if (ObjcQualifiedIdType *QIT = 
+             dyn_cast<ObjcQualifiedIdType>(receiverType)) {
+      // search protocols
+      for (unsigned i = 0; i < QIT->getNumProtocols(); i++) {
+        ObjcProtocolDecl *PDecl = QIT->getProtocols(i);
+        if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
+          break;
+      }
+      if (!Method)
+        Diag(lbrac, diag::warn_method_not_found_in_protocol, 
+             std::string("-"), Sel.getName(),
+             SourceRange(lbrac, rbrac));
     }
     else {
       assert(ObjcInterfaceType::classof(receiverType.getTypePtr()) &&
index 4eefabfe6c28eeeb8bb9a0469552c9e50b1a237e..c89018a6772644195b55c084e5d7fa2eda9fa442 100644 (file)
@@ -113,6 +113,16 @@ static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) {
                reinterpret_cast<ObjcProtocolDecl**>(PPDecl),
               DS.NumProtocolQualifiers());
     }
+    else if (TypedefDecl *typeDecl = dyn_cast<TypedefDecl>(D)) {
+      if (Ctx.getObjcIdType() == Ctx.getTypedefType(typeDecl)
+          && DS.getProtocolQualifiers()) {
+          // id<protocol-list>
+        Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0];
+        return Ctx.getObjcQualifiedIdType(typeDecl,
+                 reinterpret_cast<ObjcProtocolDecl**>(PPDecl),
+                 DS.NumProtocolQualifiers());
+      }
+    }
     // TypeQuals handled by caller.
     return Ctx.getTypedefType(cast<TypedefDecl>(D));
   }
index 892e53b2a1f9a468cacc8299bf28cba0ad82efec..26353e5b1f83f49c8b7553ab217d0856c8248768 100644 (file)
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
                        projectDirPath = "";
index f28ae3f4c2b408cabdfb519b7d88b8d5f76e4eaa..058127544e5dfd95a87d46b626c3467f11567b5c 100644 (file)
@@ -42,6 +42,7 @@ class ASTContext {
   llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
   llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
   llvm::FoldingSet<ObjcQualifiedInterfaceType> ObjcQualifiedInterfaceTypes;
+  llvm::FoldingSet<ObjcQualifiedIdType> ObjcQualifiedIdTypes;
   /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
   ///  This is lazily created.  This is intentionally not serialized.
   llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
@@ -168,6 +169,13 @@ public:
   /// the conforming protocol list.
   QualType getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl,
              ObjcProtocolDecl **ProtocolList, unsigned NumProtocols);
+  
+  /// getObjcQualifiedIdType - Return an ObjcQualifiedIdType for a 
+  /// given 'id' and conforming protocol list.
+  QualType getObjcQualifiedIdType(TypedefDecl *Decl,
+                                  ObjcProtocolDecl **ProtocolList, 
+                                  unsigned NumProtocols);
+                                  
 
   /// getTypeOfType - GCC extension.
   QualType getTypeOfExpr(Expr *e);
index da448917804649ed65c037e97537f1757af1651a..0661f57e69043ef71c4aa2aaf78902d494953555 100644 (file)
@@ -220,6 +220,7 @@ public:
     FunctionNoProto, FunctionProto,
     TypeName, Tagged, 
     ObjcInterface, ObjcQualifiedInterface,
+    ObjcQualifiedId,
     TypeOfExp, TypeOfTyp // GNU typeof extension.
   };
 private:
@@ -819,7 +820,9 @@ protected:
 
 class TypedefType : public Type {
   TypedefDecl *Decl;
-  TypedefType(TypedefDecl *D, QualType can) : Type(TypeName, can), Decl(D) {
+protected:
+  TypedefType(TypeClass tc, TypedefDecl *D, QualType can) 
+    : Type(tc, can), Decl(D) {
     assert(!isa<TypedefType>(can) && "Invalid canonical type");
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -951,6 +954,40 @@ public:
   }
   static bool classof(const ObjcQualifiedInterfaceType *) { return true; }
 };
+
+/// ObjcQualifiedIdType - to represent id<protocol-list>
+class ObjcQualifiedIdType : public TypedefType,
+                            public llvm::FoldingSetNode {
+  // List of protocols for this protocol conforming 'id' type
+  // List is sorted on protocol name. No protocol is enterred more than once.
+  llvm::SmallVector<ObjcProtocolDecl*, 8> Protocols;
+    
+  ObjcQualifiedIdType(TypedefDecl *TD, QualType can,
+                      ObjcProtocolDecl **Protos,  unsigned NumP) : 
+  TypedefType(ObjcQualifiedId, TD, can), 
+  Protocols(Protos, Protos+NumP) { }
+  friend class ASTContext;  // ASTContext creates these.
+public:
+    
+  ObjcProtocolDecl *getProtocols(unsigned i) const {
+    return Protocols[i];
+  }
+  unsigned getNumProtocols() const {
+    return Protocols.size();
+  }
+    
+  virtual void getAsStringInternal(std::string &InnerString) const;
+    
+  void Profile(llvm::FoldingSetNodeID &ID);
+  static void Profile(llvm::FoldingSetNodeID &ID, 
+                      ObjcProtocolDecl **protocols, unsigned NumProtocols);
+    
+  static bool classof(const Type *T) { 
+    return T->getTypeClass() == ObjcQualifiedId; 
+  }
+  static bool classof(const ObjcQualifiedIdType *) { return true; }
+    
+};
   
 /// RecordType - This is a helper class that allows the use of isa/cast/dyncast
 /// to detect TagType objects of structs/unions/classes.
index 684141a367145a824ffe722cba43d83b60f7d760..811576e9e70d6c712dfbb87801af5a19259da88e 100644 (file)
@@ -470,6 +470,8 @@ DIAG(err_statically_allocated_object, ERROR,
      "statically allocated Objective-C object '%0'")
 DIAG(warn_method_not_found, WARNING,
      "method '%0%1' not found (return type defaults to 'id')")
+DIAG(warn_method_not_found_in_protocol, WARNING,
+     "method '%0%1' not found in protocol (return type defaults to 'id')")
 
 //===----------------------------------------------------------------------===//
 // Semantic Analysis
diff --git a/test/Sema/id-test-3.m b/test/Sema/id-test-3.m
new file mode 100644 (file)
index 0000000..5331888
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: clang -rewrite-test %s
+
+@protocol P
+- (id<P>) Meth: (id<P>) Arg;
+@end
+
+@interface INTF<P>
+- (id<P>)IMeth;
+@end
+
+@implementation INTF
+- (id<P>)IMeth { return [(id<P>)self Meth: 0]; }
+- (id<P>) Meth : (id<P>) Arg {}
+@end
diff --git a/test/Sema/protocol-id-test-1.m b/test/Sema/protocol-id-test-1.m
new file mode 100644 (file)
index 0000000..765500e
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: clang -verify %s
+
+@interface FF
+- (void) Meth;
+@end
+
+@protocol P
+@end
+
+@interface INTF<P>
+- (void)IMeth;
+@end
+
+@implementation INTF
+- (void)IMeth {INTF<P> *pi;  [pi Meth]; } // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}}
+@end
diff --git a/test/Sema/protocol-id-test-2.m b/test/Sema/protocol-id-test-2.m
new file mode 100644 (file)
index 0000000..525d2cc
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: clang -verify %s
+
+@protocol P
+@end
+
+@interface INTF<P>
+- (void)IMeth;
+ - (void) Meth;
+@end
+
+@implementation INTF
+- (void)IMeth { [(id<P>)self Meth]; }  // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}}
+- (void) Meth {}
+@end