]> granicus.if.org Git - clang/commitdiff
This patch instantiates objects for forward protocols and in general handles use of
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 21 Sep 2007 15:40:54 +0000 (15:40 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 21 Sep 2007 15:40:54 +0000 (15:40 +0000)
protocols referenced in @protocol declarations.

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

AST/Decl.cpp
Parse/MinimalAction.cpp
Parse/ParseObjc.cpp
Sema/Sema.h
Sema/SemaDecl.cpp
include/clang/AST/ASTContext.h
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
test/Sema/protocol-test-2.m [new file with mode: 0644]

index 4b330eeeebe6399686bfff6c9c2ac9eba067d8be..bde4b6b45b52b6c898ccbb9fb427cf37b55b31ef 100644 (file)
@@ -29,6 +29,7 @@ static unsigned nInterfaceDecls = 0;
 static unsigned nClassDecls = 0;
 static unsigned nMethodDecls = 0;
 static unsigned nProtocolDecls = 0;
+static unsigned nForwardProtocolDecls = 0;
 static unsigned nCategoryDecls = 0;
 static unsigned nIvarDecls = 0;
 
@@ -59,6 +60,8 @@ const char *Decl::getDeclKindName() const {
     return "ObjcProtoMethod";
   case ObjcProtocol:
     return "ObjcProtocol";
+  case ObjcForwardProtocol:
+    return "ObjcForwardProtocol"; 
   case Struct:
     return "Struct";
   case Union:
@@ -122,6 +125,9 @@ void Decl::PrintStats() {
   fprintf(stderr, "    %d protocol decls, %d each (%d bytes)\n", 
          nProtocolDecls, (int)sizeof(ObjcProtocolDecl),
          int(nProtocolDecls*sizeof(ObjcProtocolDecl)));
+  fprintf(stderr, "    %d forward protocol decls, %d each (%d bytes)\n", 
+         nForwardProtocolDecls, (int)sizeof(ObjcForwardProtocolDecl),
+         int(nForwardProtocolDecls*sizeof(ObjcForwardProtocolDecl)));
   fprintf(stderr, "    %d category decls, %d each (%d bytes)\n", 
          nCategoryDecls, (int)sizeof(ObjcCategoryDecl),
          int(nCategoryDecls*sizeof(ObjcCategoryDecl)));
@@ -178,6 +184,9 @@ void Decl::addDeclKind(const Kind k) {
     case ObjcProtocol:
       nProtocolDecls++;
       break;
+    case ObjcForwardProtocol:
+      nForwardProtocolDecls++;
+      break;
     case ObjcCategory:
      nCategoryDecls++;
      break;
index 7f1f239d160100fbcf8c90dbe836d4c05f9459ba..c5be83b8fce99984fb11e42d9e18ebed8be748e8 100644 (file)
@@ -109,6 +109,23 @@ MinimalAction::ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,
   return 0;
 }
 
+/// ObjcForwardProtocolDeclaration - 
+/// Scope will always be top level file scope. 
+Action::DeclTy *
+MinimalAction::ObjcForwardProtocolDeclaration(Scope *S, SourceLocation AtClassLoc,
+                 IdentifierInfo **IdentList, unsigned NumElts) {
+  for (unsigned i = 0; i != NumElts; ++i) {
+    TypeNameInfo *TI =
+    new TypeNameInfo(1, IdentList[i]->getFETokenInfo<TypeNameInfo>());
+    
+    IdentList[i]->setFETokenInfo(TI);
+    
+    // Remember that this needs to be removed when the scope is popped.
+    S->AddDecl(IdentList[i]);
+  }
+  return 0;
+}
+
 /// PopScope - When a scope is popped, if any typedefs are now out-of-scope,
 /// they are removed from the IdentifierInfo::FETokenInfo field.
 void MinimalAction::PopScope(SourceLocation Loc, Scope *S) {
index 0533660974c7a3f7780f933ebb0e5d5e524ade40..116c2d81b2ec1b6a52f1f9dfddca29da91c262c7 100644 (file)
@@ -713,13 +713,13 @@ Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
   IdentifierInfo *protocolName = Tok.getIdentifierInfo();
   SourceLocation nameLoc = ConsumeToken();
   
-  if (Tok.getKind() == tok::semi) { // forward declaration.
+  llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
+  if (Tok.getKind() == tok::semi) { // forward declaration of one protocol.
     ConsumeToken();
-    return 0; // FIXME: add protocolName
+    ProtocolRefs.push_back(protocolName);
   }
   if (Tok.getKind() == tok::comma) { // list of forward declarations.
     // Parse the list of forward declarations.
-    llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
     ProtocolRefs.push_back(protocolName);
     
     while (1) {
@@ -738,10 +738,12 @@ Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
     // Consume the ';'.
     if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
       return 0;
-    return 0; // FIXME
   }
+  if (ProtocolRefs.size() > 0)
+    return Actions.ObjcForwardProtocolDeclaration(CurScope, AtLoc,
+                                                  &ProtocolRefs[0], 
+                                                  ProtocolRefs.size());
   // Last, and definitely not least, parse a protocol declaration.
-  llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
   if (Tok.getKind() == tok::less) {
     if (ParseObjCProtocolReferences(ProtocolRefs))
       return 0;
index 29a03d1eb2c4ea71113222549370bffc36aadd8e..d99b1fc12f9c8bc8ae4035d7e9e78d1176f77e7f 100644 (file)
@@ -370,6 +370,11 @@ public:
   virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,
                                        IdentifierInfo **IdentList,
                                        unsigned NumElts);
+  
+  virtual DeclTy *ObjcForwardProtocolDeclaration(Scope *S, 
+                                                 SourceLocation AtProtocolLoc,
+                                                 IdentifierInfo **IdentList,
+                                                 unsigned NumElts);
 
   virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl, 
                                     DeclTy **allMethods, unsigned allNum);
index f46ec42cbdd9f298cdcfaaa73745e6e4f671fc7a..a82aea90b063a7b727023db6b03c941b0e3a3475 100644 (file)
@@ -905,16 +905,66 @@ Sema::DeclTy *Sema::ObjcStartProtoInterface(SourceLocation AtProtoInterfaceLoc,
                 IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
                 IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs) {
   assert(ProtocolName && "Missing protocol identifier");
-  ObjcProtocolDecl *PDecl;
-
-  PDecl = new ObjcProtocolDecl(AtProtoInterfaceLoc, ProtocolName);
+  ObjcProtocolDecl *PDecl = Context.getObjCProtocolDecl(ProtocolName);
+  if (PDecl) {
+    // Protocol already seen. Better be a forward protocol declaration
+    if (!PDecl->getIsForwardProtoDecl())
+      Diag(ProtocolLoc, diag::err_duplicate_protocol_def, 
+           ProtocolName->getName());
+    else {
+      PDecl->setIsForwardProtoDecl(false);
+      PDecl->AllocReferencedProtocols(NumProtoRefs);
+    }
+  }
+  else {
+    PDecl = new ObjcProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs, 
+                                 ProtocolName);
+    PDecl->setIsForwardProtoDecl(false);
+    // Chain & install the protocol decl into the identifier.
+    PDecl->setNext(ProtocolName->getFETokenInfo<ScopedDecl>());
+    ProtocolName->setFETokenInfo(PDecl);
+    Context.setObjCProtocolDecl(ProtocolName, PDecl);
+  }    
+  
+  /// Check then save referenced protocols
+  for (unsigned int i = 0; i != NumProtoRefs; i++) {
+    ObjcProtocolDecl* RefPDecl = Context.getObjCProtocolDecl(ProtoRefNames[i]);
+    if (!RefPDecl || RefPDecl->getIsForwardProtoDecl())
+      Diag(ProtocolLoc, diag::err_undef_protocolref,
+          ProtoRefNames[i]->getName(),
+           ProtocolName->getName());
+    PDecl->setReferencedProtocols((int)i, RefPDecl);
+  }
 
-  // Chain & install the protocol decl into the identifier.
-  PDecl->setNext(ProtocolName->getFETokenInfo<ScopedDecl>());
-  ProtocolName->setFETokenInfo(PDecl);
   return PDecl;
 }
 
+/// ObjcForwardProtocolDeclaration - 
+/// Scope will always be top level file scope. 
+Action::DeclTy *
+Sema::ObjcForwardProtocolDeclaration(Scope *S, SourceLocation AtProtocolLoc,
+        IdentifierInfo **IdentList, unsigned NumElts) {
+  ObjcForwardProtocolDecl *FDecl = new ObjcForwardProtocolDecl(AtProtocolLoc, 
+                                                               NumElts);
+  
+  for (unsigned i = 0; i != NumElts; ++i) {
+    ObjcProtocolDecl *PDecl;
+    PDecl = Context.getObjCProtocolDecl(IdentList[i]);
+    if (!PDecl)  {// Already seen?
+      PDecl = new ObjcProtocolDecl(SourceLocation(), 0, IdentList[i], true);
+      // Chain & install the protocol decl into the identifier.
+      PDecl->setNext(IdentList[i]->getFETokenInfo<ScopedDecl>());
+      IdentList[i]->setFETokenInfo(PDecl);
+      Context.setObjCProtocolDecl(IdentList[i], PDecl);
+    }
+    // Remember that this needs to be removed when the scope is popped.
+    S->AddDecl(IdentList[i]);
+    
+    FDecl->setForwardProtocolDecl((int)i, PDecl);
+  }
+  return FDecl;
+}
+
 Sema::DeclTy *Sema::ObjcStartCatInterface(SourceLocation AtInterfaceLoc,
                       IdentifierInfo *ClassName, SourceLocation ClassLoc,
                       IdentifierInfo *CategoryName, SourceLocation CategoryLoc,
index 0e4bab1eab07e9f0f9bdb369b8d2de989284a4bc..fe7cc3c003f0c7af7f110f3b0d6e9c9c41d0eab8 100644 (file)
@@ -38,6 +38,7 @@ class ASTContext {
   llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
   llvm::DenseMap<const RecordDecl*, const RecordLayout*> RecordLayoutInfo;
   llvm::DenseMap<const IdentifierInfo*, ObjcInterfaceDecl*> ClassNameInfo;
+  llvm::DenseMap<const IdentifierInfo*, ObjcProtocolDecl*> ProtocolNameInfo;
   RecordDecl *CFConstantStringTypeDecl;
 public:
   
@@ -165,6 +166,12 @@ public:
                             ObjcInterfaceDecl* InterfaceDecl)
   { ClassNameInfo[ClassName] = InterfaceDecl; }
   
+  ObjcProtocolDecl* getObjCProtocolDecl(const IdentifierInfo* ProtocolName) 
+  { return ProtocolNameInfo[ProtocolName]; }
+  void setObjCProtocolDecl(const IdentifierInfo* ProtocolName,
+                            ObjcProtocolDecl* ProtocolDecl)
+  { ProtocolNameInfo[ProtocolName] = ProtocolDecl; }
+  
   //===--------------------------------------------------------------------===//
   //                            Type Operators
   //===--------------------------------------------------------------------===//
index 40607cfd4f994127053db03fce8a79c343f162fc..0ba45810b538a006148184c4c176901c1ac4c309 100644 (file)
@@ -38,7 +38,7 @@ public:
     Function, BlockVariable, FileVariable, ParmVariable, EnumConstant,
     // Concrete sub-classes of TypeDecl
     Typedef, Struct, Union, Class, Enum, ObjcInterface, ObjcClass, ObjcMethod,
-    ObjcProtoMethod, ObjcProtocol, ObjcCategory,
+    ObjcProtoMethod, ObjcProtocol, ObjcForwardProtocol, ObjcCategory,
     // Concrete sub-class of Decl
     Field, ObjcIvar
   };
@@ -680,6 +680,10 @@ public:
 };
 
 class ObjcProtocolDecl : public TypeDecl {
+  /// referenced protocols
+  ObjcProtocolDecl **ReferencedProtocols;  // Null if none
+  int NumReferencedProtocols;  // -1 if none
+  
   /// protocol instance methods
   ObjcMethodDecl **ProtoInsMethods;  // Null if not defined
   int NumProtoInsMethods;  // -1 if not defined
@@ -690,20 +694,62 @@ class ObjcProtocolDecl : public TypeDecl {
 
   bool isForwardProtoDecl; // declared with @protocol.
 public:
-  ObjcProtocolDecl(SourceLocation L, IdentifierInfo *Id, bool FD = false)
+  ObjcProtocolDecl(SourceLocation L, unsigned numRefProtos,
+                   IdentifierInfo *Id, bool FD = false)
     : TypeDecl(ObjcProtocol, L, Id, 0), 
+      ReferencedProtocols(0), NumReferencedProtocols(-1),
       ProtoInsMethods(0), NumProtoInsMethods(-1), 
       ProtoClsMethods(0), NumProtoClsMethods(-1),
-      isForwardProtoDecl(FD) { }
-
+      isForwardProtoDecl(FD) {
+        AllocReferencedProtocols(numRefProtos);
+      }
+  void AllocReferencedProtocols(unsigned numRefProtos) {
+    if (numRefProtos) {
+      ReferencedProtocols = new ObjcProtocolDecl*[numRefProtos];
+      memset(ReferencedProtocols, '\0', 
+             numRefProtos*sizeof(ObjcProtocolDecl*));
+      NumReferencedProtocols = numRefProtos;
+    }    
+  }
   void ObjcAddProtoMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
                            ObjcMethodDecl **clsMethods, unsigned numClsMembers);
+  
+  void setReferencedProtocols(int idx, ObjcProtocolDecl *OID) {
+    assert((idx < NumReferencedProtocols) && "index out of range");
+    ReferencedProtocols[idx] = OID;
+  }
+  
+  
+  bool getIsForwardProtoDecl() const { return isForwardProtoDecl; }
+  void setIsForwardProtoDecl(bool val) { isForwardProtoDecl = val; }
 
   static bool classof(const Decl *D) {
     return D->getKind() == ObjcProtocol;
   }
   static bool classof(const ObjcProtocolDecl *D) { return true; }
 };
+  
+class ObjcForwardProtocolDecl : public TypeDecl {
+    ObjcProtocolDecl **ForwardProtocolDecls;   // Null if not defined.
+    int NumForwardProtocolDecls;               // -1 if not defined.
+  public:
+    ObjcForwardProtocolDecl(SourceLocation L, unsigned nElts)
+    : TypeDecl(ObjcForwardProtocol, L, 0, 0) { 
+      if (nElts) {
+        ForwardProtocolDecls = new ObjcProtocolDecl*[nElts];
+        memset(ForwardProtocolDecls, '\0', nElts*sizeof(ObjcProtocolDecl*));
+        NumForwardProtocolDecls = nElts;
+      }
+    }
+    void setForwardProtocolDecl(int idx, ObjcProtocolDecl *OID) {
+      assert((idx < NumForwardProtocolDecls) && "index out of range");
+      ForwardProtocolDecls[idx] = OID;
+    }
+    static bool classof(const Decl *D) {
+      return D->getKind() == ObjcForwardProtocol;
+    }
+    static bool classof(const ObjcForwardProtocolDecl *D) { return true; }
+};
 
 class ObjcCategoryDecl : public ScopedDecl {
   /// category instance methods
index 445f3bf2b80cd20f1ef5cc16c705db26e2f95c53..2556b2324204bd0b6cc5c7b51dbde6c2756145b9 100644 (file)
@@ -412,7 +412,10 @@ DIAG(err_undef_superclass, ERROR,
      "cannot find interface declaration for '%0', superclass of '%1'")
 DIAG(err_duplicate_class_def, ERROR,
      "duplicate interface declaration for class '%0'")
-
+DIAG(err_undef_protocolref, ERROR,
+     "cannot find protocol definition for '%0', referenced by '%1'")
+DIAG(err_duplicate_protocol_def, ERROR,
+     "duplicate protocol declaration of '%0'")
 
 //===----------------------------------------------------------------------===//
 // Semantic Analysis
index fab3bfe73df8b39d2b335f4989484e5b879572b8..dca01000755a5a09d5f5a75383cad3b42a580acc 100644 (file)
@@ -502,6 +502,14 @@ public:
                                        unsigned NumElts) {
     return 0;
   }
+  
+  virtual DeclTy *ObjcForwardProtocolDeclaration(Scope *S, 
+                                                 SourceLocation AtProtocolLoc,
+                                                 IdentifierInfo **IdentList,
+                                                 unsigned NumElts) {
+    return 0;
+  }
+  
   virtual void ObjCStartCategoryInterface() { // FIXME
     return;
   }
@@ -548,6 +556,11 @@ public:
                                        IdentifierInfo **IdentList,
                                        unsigned NumElts);
   
+  virtual DeclTy *ObjcForwardProtocolDeclaration(Scope *S, 
+                                                 SourceLocation AtProtocolLoc,
+                                                 IdentifierInfo **IdentList,
+                                                 unsigned NumElts);
+   
   virtual DeclTy *ObjcStartClassInterface(SourceLocation AtInterafceLoc,
                     IdentifierInfo *ClassName, SourceLocation ClassLoc,
                     IdentifierInfo *SuperName, SourceLocation SuperLoc,
diff --git a/test/Sema/protocol-test-2.m b/test/Sema/protocol-test-2.m
new file mode 100644 (file)
index 0000000..04ad3c6
--- /dev/null
@@ -0,0 +1,29 @@
+@interface INTF1 @end
+
+@protocol p1,p2,p3;
+
+@protocol p1;
+
+@protocol PROTO1
+- (INTF1<p1>*) meth;
+@end
+
+@protocol PROTO2<p1> // expected-error {{cannot find protocol definition for 'p1', referenced by 'PROTO2'}}
+@end
+
+@protocol p1 @end
+
+@protocol PROTO<p1>
+@end
+
+@protocol PROTO<p1>    // expected-error {{duplicate protocol declaration of 'PROTO'}}
+@end
+
+@protocol PROTO3<p1, p1>
+@end
+
+@protocol p2 <p1>
+@end
+
+@protocol PROTO4 <p1, p2, PROTO, PROTO3, p3> // expected-error {{cannot find protocol definition for 'p3', referenced by 'PROTO4'}}
+@end