From: Fariborz Jahanian Date: Sat, 22 Sep 2007 00:01:35 +0000 (+0000) Subject: This patch adds to new things to clang: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b27c156688ca557cb277ecdfea6dccc1dac5b49f;p=clang This patch adds to new things to clang: 1. Handles saving and checking on protocols used in an @interface declaration 2. Checks and saves class's super class. 3. Adds semantic check to category declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42218 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index a82aea90b0..ff7620380b 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -875,11 +875,13 @@ Sema::DeclTy *Sema::ObjcStartClassInterface(SourceLocation AtInterfaceLoc, // Class already seen. Is it a forward declaration? if (!IDecl->getIsForwardDecl()) Diag(AtInterfaceLoc, diag::err_duplicate_class_def, ClassName->getName()); - else + else { IDecl->setIsForwardDecl(false); + IDecl->AllocIntfRefProtocols(NumProtocols); + } } else { - IDecl = new ObjcInterfaceDecl(AtInterfaceLoc, ClassName); + IDecl = new ObjcInterfaceDecl(AtInterfaceLoc, NumProtocols, ClassName); // Chain & install the interface decl into the identifier. IDecl->setNext(ClassName->getFETokenInfo()); @@ -887,15 +889,28 @@ Sema::DeclTy *Sema::ObjcStartClassInterface(SourceLocation AtInterfaceLoc, } if (SuperName) { - const ObjcInterfaceDecl* SuperClassEntry = - Context.getObjCInterfaceDecl(SuperName); + ObjcInterfaceDecl* SuperClassEntry = + Context.getObjCInterfaceDecl(SuperName); if (!SuperClassEntry || SuperClassEntry->getIsForwardDecl()) { Diag(AtInterfaceLoc, diag::err_undef_superclass, SuperName->getName(), ClassName->getName()); } + else + IDecl->setSuperClass(SuperClassEntry); + } + + /// Check then save referenced protocols + for (unsigned int i = 0; i != NumProtocols; i++) { + ObjcProtocolDecl* RefPDecl = Context.getObjCProtocolDecl(ProtocolNames[i]); + if (!RefPDecl || RefPDecl->getIsForwardProtoDecl()) + Diag(ClassLoc, diag::err_undef_protocolref, + ProtocolNames[i]->getName(), + ClassName->getName()); + IDecl->setIntfRefProtocols((int)i, RefPDecl); } + Context.setObjCInterfaceDecl(ClassName, IDecl); return IDecl; @@ -970,15 +985,50 @@ Sema::DeclTy *Sema::ObjcStartCatInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs) { ObjcCategoryDecl *CDecl; - CDecl = new ObjcCategoryDecl(AtInterfaceLoc, ClassName); - assert (ClassName->getFETokenInfo() && "Missing @interface decl"); - Decl *D = static_cast(ClassName->getFETokenInfo()); - assert(isa(D) && "Missing @interface decl"); + ObjcInterfaceDecl* IDecl = Context.getObjCInterfaceDecl(ClassName); + CDecl = new ObjcCategoryDecl(AtInterfaceLoc, NumProtoRefs, ClassName); + if (IDecl) { + assert (ClassName->getFETokenInfo() && "Missing @interface decl"); + Decl *D = static_cast(ClassName->getFETokenInfo()); + assert(isa(D) && "Missing @interface decl"); - // Chain & install the category decl into the identifier. - // Note that head of the chain is the @interface class type and follow up - // nodes in the chain are the protocol decl nodes. - cast(D)->setNext(CDecl); + // Chain & install the category decl into the identifier. + // Note that head of the chain is the @interface class type and follow up + // nodes in the chain are the protocol decl nodes. + cast(D)->setNext(CDecl); + } + + CDecl->setClassInterface(IDecl); + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->getIsForwardDecl()) + Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); + else { + /// Check for duplicate interface declaration for this category + ObjcCategoryDecl *CDeclChain; + for (CDeclChain = IDecl->getListCategories(); CDeclChain; + CDeclChain = CDeclChain->getNextClassCategory()) { + if (CDeclChain->getCatName() == CategoryName) { + Diag(CategoryLoc, diag::err_dup_category_def, ClassName->getName(), + CategoryName->getName()); + break; + } + } + if (!CDeclChain) { + CDecl->setCatName(CategoryName); + CDecl->insertNextClassCategory(); + } + } + + /// Check then save referenced protocols + for (unsigned int i = 0; i != NumProtoRefs; i++) { + ObjcProtocolDecl* RefPDecl = Context.getObjCProtocolDecl(ProtoRefNames[i]); + if (!RefPDecl || RefPDecl->getIsForwardProtoDecl()) + Diag(CategoryLoc, diag::err_undef_protocolref, + ProtoRefNames[i]->getName(), + CategoryName->getName()); + CDecl->setCatReferencedProtocols((int)i, RefPDecl); + } + return CDecl; } @@ -993,7 +1043,7 @@ Sema::ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc, ObjcInterfaceDecl *IDecl; IDecl = Context.getObjCInterfaceDecl(IdentList[i]); if (!IDecl) {// Already seen? - IDecl = new ObjcInterfaceDecl(SourceLocation(), IdentList[i], true); + IDecl = new ObjcInterfaceDecl(SourceLocation(), 0, IdentList[i], true); // Chain & install the interface decl into the identifier. IDecl->setNext(IdentList[i]->getFETokenInfo()); IdentList[i]->setFETokenInfo(IDecl); diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 0ba45810b5..e0c7c88596 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -26,6 +26,8 @@ class FunctionDecl; class AttributeList; class ObjcIvarDecl; class ObjcMethodDecl; +class ObjcProtocolDecl; +class ObjcCategoryDecl; /// Decl - This represents one declaration (or definition), e.g. a variable, @@ -539,6 +541,14 @@ public: }; class ObjcInterfaceDecl : public TypeDecl { + + /// Class's super class. + ObjcInterfaceDecl *SuperClass; + + /// Protocols referenced in interface header declaration + ObjcProtocolDecl **IntfRefProtocols; // Null if none + int NumIntfRefProtocols; // -1 if none + /// Ivars/NumIvars - This is a new[]'d array of pointers to Decls. ObjcIvarDecl **Ivars; // Null if not defined. int NumIvars; // -1 if not defined. @@ -551,13 +561,31 @@ class ObjcInterfaceDecl : public TypeDecl { ObjcMethodDecl **ClsMethods; // Null if not defined int NumClsMethods; // -1 if not defined + /// List of categories defined for this class. + ObjcCategoryDecl *ListCategories; + bool isForwardDecl; // declared with @class. public: - ObjcInterfaceDecl(SourceLocation L, IdentifierInfo *Id, bool FD = false) - : TypeDecl(ObjcInterface, L, Id, 0), Ivars(0), NumIvars(-1), + ObjcInterfaceDecl(SourceLocation L, unsigned numRefProtos, + IdentifierInfo *Id, bool FD = false) + : TypeDecl(ObjcInterface, L, Id, 0), + SuperClass(0), + IntfRefProtocols(0), NumIntfRefProtocols(-1), + Ivars(0), NumIvars(-1), InsMethods(0), NumInsMethods(-1), ClsMethods(0), NumClsMethods(-1), - isForwardDecl(FD) { } - + ListCategories(0), + isForwardDecl(FD) { + AllocIntfRefProtocols(numRefProtos); + } + + void AllocIntfRefProtocols(unsigned numRefProtos) { + if (numRefProtos) { + IntfRefProtocols = new ObjcProtocolDecl*[numRefProtos]; + memset(IntfRefProtocols, '\0', + numRefProtos*sizeof(ObjcProtocolDecl*)); + NumIntfRefProtocols = numRefProtos; + } + } void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, unsigned numIvars); @@ -567,6 +595,19 @@ public: bool getIsForwardDecl() const { return isForwardDecl; } void setIsForwardDecl(bool val) { isForwardDecl = val; } + void setIntfRefProtocols(int idx, ObjcProtocolDecl *OID) { + assert((idx < NumIntfRefProtocols) && "index out of range"); + IntfRefProtocols[idx] = OID; + } + + ObjcInterfaceDecl *getSuperClass() const { return SuperClass; } + void setSuperClass(ObjcInterfaceDecl * superCls) { SuperClass = superCls; } + + ObjcCategoryDecl* getListCategories() const { return ListCategories; } + void setListCategories(ObjcCategoryDecl *category) { + ListCategories = category; + } + static bool classof(const Decl *D) { return D->getKind() == ObjcInterface; } @@ -752,6 +793,16 @@ class ObjcForwardProtocolDecl : public TypeDecl { }; class ObjcCategoryDecl : public ScopedDecl { + /// Interface belonging to this category + ObjcInterfaceDecl *ClassInterface; + + /// Category name + IdentifierInfo *ObjcCatName; + + /// referenced protocols in this category + ObjcProtocolDecl **CatReferencedProtocols; // Null if none + int NumCatReferencedProtocols; // -1 if none + /// category instance methods ObjcMethodDecl **CatInsMethods; // Null if not defined int NumCatInsMethods; // -1 if not defined @@ -760,21 +811,45 @@ class ObjcCategoryDecl : public ScopedDecl { ObjcMethodDecl **CatClsMethods; // Null if not defined int NumCatClsMethods; // -1 if not defined - /// Category name - IdentifierInfo *ObjcCatName; + /// Next category belonging to this class + ObjcCategoryDecl *NextClassCategory; public: - ObjcCategoryDecl(SourceLocation L, IdentifierInfo *Id) + ObjcCategoryDecl(SourceLocation L, unsigned numRefProtocol, + IdentifierInfo *Id) : ScopedDecl(ObjcCategory, L, Id, 0), + ClassInterface(0), ObjcCatName(0), + CatReferencedProtocols(0), NumCatReferencedProtocols(-1), CatInsMethods(0), NumCatInsMethods(-1), CatClsMethods(0), NumCatClsMethods(-1), - ObjcCatName(0) {} + NextClassCategory(0) { + if (numRefProtocol) { + CatReferencedProtocols = new ObjcProtocolDecl*[numRefProtocol]; + memset(CatReferencedProtocols, '\0', + numRefProtocol*sizeof(ObjcProtocolDecl*)); + NumCatReferencedProtocols = numRefProtocol; + } + } + ObjcInterfaceDecl *getClassInterface() const { return ClassInterface; } + void setClassInterface(ObjcInterfaceDecl *IDecl) { ClassInterface = IDecl; } + + void setCatReferencedProtocols(int idx, ObjcProtocolDecl *OID) { + assert((idx < NumCatReferencedProtocols) && "index out of range"); + CatReferencedProtocols[idx] = OID; + } + void ObjcAddCatMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers, ObjcMethodDecl **clsMethods, unsigned numClsMembers); IdentifierInfo *getCatName() const { return ObjcCatName; } void setCatName(IdentifierInfo *catName) { ObjcCatName = catName; } + + ObjcCategoryDecl *getNextClassCategory() const { return NextClassCategory; } + void insertNextClassCategory() { + NextClassCategory = ClassInterface->getListCategories(); + ClassInterface->setListCategories(this); + } static bool classof(const Decl *D) { return D->getKind() == ObjcCategory; diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 2556b23242..3a76a8bc88 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -416,6 +416,10 @@ 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'") +DIAG(err_undef_interface, ERROR, + "cannot find interface declaration for '%0'") +DIAG(err_dup_category_def, ERROR, + "duplicate interface declaration for category '%0(%1)'") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/test/Sema/category-1.m b/test/Sema/category-1.m new file mode 100644 index 0000000000..fc3cf6fac1 --- /dev/null +++ b/test/Sema/category-1.m @@ -0,0 +1,36 @@ +@interface MyClass1 @end + +@protocol p1,p2,p3; + +@interface MyClass1 (Category1) // expected-error {{cannot find protocol definition for 'p1', referenced by 'Category1'}} +@end + +@interface MyClass1 (Category1) // expected-error {{duplicate interface declaration for category 'MyClass1(Category1)'}} +@end + +@interface MyClass1 (Category3) +@end + +@interface MyClass1 (Category4) @end +@interface MyClass1 (Category5) @end +@interface MyClass1 (Category6) @end +@interface MyClass1 (Category7) @end +@interface MyClass1 (Category8) @end + + +@interface MyClass1 (Category4) @end // expected-error {{duplicate interface declaration for category 'MyClass1(Category4)'}} +@interface MyClass1 (Category7) @end // expected-error {{duplicate interface declaration for category 'MyClass1(Category7)'}} +@interface MyClass1 (Category8) @end // expected-error {{duplicate interface declaration for category 'MyClass1(Category8)'}} + + +@protocol p3 @end + +@interface MyClass1 (Category) @end // expected-error {{cannot find protocol definition for 'p2', referenced by 'Category'}} + +@interface MyClass (Category) @end // expected-error {{cannot find interface declaration for 'MyClass'}} + +@class MyClass2; + +@interface MyClass2 (Category) @end // expected-error {{cannot find interface declaration for 'MyClass2'}} + + diff --git a/test/Sema/class-proto-1.m b/test/Sema/class-proto-1.m new file mode 100644 index 0000000000..dfcd0a266d --- /dev/null +++ b/test/Sema/class-proto-1.m @@ -0,0 +1,34 @@ +@interface INTF1 @end + +@protocol p1,p2,p3; + +@protocol p1; + +@protocol PROTO1 +- (INTF1*) meth; +@end + +@protocol p1 @end + +@interface I1 @end + +@interface E1 @end // expected-error {{cannot find protocol definition for 'p2', referenced by 'E1'}} + +@protocol p2 @end + + +@interface I2 @end + +@interface E2 @end // expected-error {{cannot find protocol definition for 'p3', referenced by 'E2'}} + +@class U1, U2; + +@interface E3 : U1 @end // expected-error {{cannot find interface declaration for 'U1', superclass of 'E3'}} + + +@interface I3 : E3 @end + +@interface U2 @end + +@interface I4 : U2 +@end