This patch introduces the ObjcCategoryImplDecl class and does the checking related to

unimplemented methods in category implementation.

llvm-svn: 42531
This commit is contained in:
Fariborz Jahanian
2007-10-02 16:38:50 +00:00
parent a6d930a925
commit 89b8ef92be
9 changed files with 225 additions and 4 deletions

View File

@@ -34,6 +34,7 @@ static unsigned nForwardProtocolDecls = 0;
static unsigned nCategoryDecls = 0;
static unsigned nIvarDecls = 0;
static unsigned nObjcImplementationDecls = 0;
static unsigned nObjcCategoryImpl = 0;
static bool StatSwitch = false;
@@ -136,6 +137,10 @@ void Decl::PrintStats() {
nObjcImplementationDecls, (int)sizeof(ObjcImplementationDecl),
int(nObjcImplementationDecls*sizeof(ObjcImplementationDecl)));
fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n",
nObjcCategoryImpl, (int)sizeof(ObjcCategoryImplDecl),
int(nObjcCategoryImpl*sizeof(ObjcCategoryImplDecl)));
fprintf(stderr, "Total bytes = %d\n",
int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+
nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+
@@ -199,6 +204,9 @@ void Decl::addDeclKind(const Kind k) {
case ObjcImplementation:
nObjcImplementationDecls++;
break;
case ObjcCategoryImpl:
nObjcCategoryImpl++;
break;
}
}
@@ -344,7 +352,7 @@ void ObjcProtocolDecl::ObjcAddProtoMethods(ObjcMethodDecl **insMethods,
}
/// ObjcAddCat - Insert instance and methods declarations into
/// ObjcProtocolDecl's CatInsMethods and CatClsMethods fields.
/// ObjcCategoryDecl's CatInsMethods and CatClsMethods fields.
///
void ObjcCategoryDecl::ObjcAddCatMethods(ObjcMethodDecl **insMethods,
unsigned numInsMembers,
@@ -362,6 +370,25 @@ void ObjcCategoryDecl::ObjcAddCatMethods(ObjcMethodDecl **insMethods,
}
}
/// ObjcAddCatImplMethods - Insert instance and methods declarations into
/// ObjcCategoryImplDecl's CatInsMethods and CatClsMethods fields.
///
void ObjcCategoryImplDecl::ObjcAddCatImplMethods(ObjcMethodDecl **insMethods,
unsigned numInsMembers,
ObjcMethodDecl **clsMethods,
unsigned numClsMembers) {
NumCatInsMethods = numInsMembers;
if (numInsMembers) {
CatInsMethods = new ObjcMethodDecl*[numInsMembers];
memcpy(CatInsMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*));
}
NumCatClsMethods = numClsMembers;
if (numClsMembers) {
CatClsMethods = new ObjcMethodDecl*[numClsMembers];
memcpy(CatClsMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*));
}
}
/// ObjcAddImplMethods - Insert instance and methods declarations into
/// ObjcImplementationDecl's InsMethods and ClsMethods fields.
///

View File

@@ -934,7 +934,10 @@ Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration(
return 0;
}
rparenLoc = ConsumeParen();
return 0;
DeclTy *ImplCatType = Actions.ObjcStartCategoryImplementation(CurScope,
atLoc, nameId, nameLoc, categoryId,
categoryLoc);
return ImplCatType;
}
// We have a class implementation
SourceLocation superClassLoc;

View File

@@ -49,6 +49,8 @@ namespace clang {
class ObjcInterfaceDecl;
class ObjcProtocolDecl;
class ObjcImplementationDecl;
class ObjcCategoryImplDecl;
class ObjcCategoryDecl;
/// Sema - This implements semantic analysis and AST building for C.
class Sema : public Action {
@@ -219,6 +221,11 @@ private:
void ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl,
ObjcInterfaceDecl* IDecl);
/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
/// category interface is implemented in the category @implementation.
void ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl,
ObjcCategoryDecl *CatClassDecl);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
public:
@@ -395,6 +402,13 @@ public:
IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc);
virtual DeclTy *ObjcStartCategoryImplementation(Scope* S,
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
IdentifierInfo *CatName,
SourceLocation CatLoc);
virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
unsigned NumElts);

View File

@@ -1068,6 +1068,25 @@ Sema::DeclTy *Sema::ObjcStartCatInterface(Scope* S,
return CDecl;
}
/// ObjcStartCategoryImplementation - Perform semantic checks on the
/// category implementation declaration and build an ObjcCategoryImplDecl
/// object.
Sema::DeclTy *Sema::ObjcStartCategoryImplementation(Scope* S,
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(S, ClassName, ClassLoc);
ObjcCategoryImplDecl *CDecl = new ObjcCategoryImplDecl(AtCatImplLoc,
ClassName, IDecl,
CatName);
/// Check that class of this category is already completely declared.
if (!IDecl || IDecl->getIsForwardDecl())
Diag(ClassLoc, diag::err_undef_interface, ClassName->getName());
/// TODO: Check that CatName, category name, is not used in another
// implementation.
return CDecl;
}
Sema::DeclTy *Sema::ObjcStartClassImplementation(Scope *S,
SourceLocation AtClassImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
@@ -1255,7 +1274,51 @@ void Sema::ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl,
ObjcProtocolDecl* PDecl = protocols[i];
CheckProtocolMethodDefs(PDecl, InsMap, ClsMap);
}
return;
}
/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
/// category interface is implemented in the category @implementation.
void Sema::ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl,
ObjcCategoryDecl *CatClassDecl) {
llvm::DenseMap<void *, char> InsMap;
// Check and see if instance methods in category interface have been
// implemented in its implementation class.
ObjcMethodDecl **methods = CatImplDecl->getCatInsMethods();
for (int i=0; i < CatImplDecl->getNumCatInsMethods(); i++) {
InsMap[methods[i]->getSelector().getAsOpaquePtr()] = 'a';
}
methods = CatClassDecl->getCatInsMethods();
for (int j = 0; j < CatClassDecl->getNumCatInsMethods(); j++)
if (!InsMap.count(methods[j]->getSelector().getAsOpaquePtr())) {
llvm::SmallString<128> buf;
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
methods[j]->getSelector().getName(buf));
}
llvm::DenseMap<void *, char> ClsMap;
// Check and see if class methods in category interface have been
// implemented in its implementation class.
methods = CatImplDecl->getCatClsMethods();
for (int i=0; i < CatImplDecl->getNumCatClsMethods(); i++) {
ClsMap[methods[i]->getSelector().getAsOpaquePtr()] = 'a';
}
methods = CatClassDecl->getCatClsMethods();
for (int j = 0; j < CatClassDecl->getNumCatClsMethods(); j++)
if (!ClsMap.count(methods[j]->getSelector().getAsOpaquePtr())) {
llvm::SmallString<128> buf;
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
methods[j]->getSelector().getName(buf));
}
// Check the protocol list for unimplemented methods in the @implementation
// class.
ObjcProtocolDecl** protocols = CatClassDecl->getCatReferencedProtocols();
for (int i = 0; i < CatClassDecl->getNumCatReferencedProtocols(); i++) {
ObjcProtocolDecl* PDecl = protocols[i];
CheckProtocolMethodDefs(PDecl, InsMap, ClsMap);
}
}
/// ObjcClassDeclaration -
@@ -1647,6 +1710,24 @@ void Sema::ObjcAddMethodsToClass(Scope* S, DeclTy *ClassDecl,
if (IDecl)
ImplMethodsVsClassMethods(ImplClass, IDecl);
}
else if (isa<ObjcCategoryImplDecl>(static_cast<Decl *>(ClassDecl))) {
ObjcCategoryImplDecl* CatImplClass = cast<ObjcCategoryImplDecl>(
static_cast<Decl*>(ClassDecl));
CatImplClass->ObjcAddCatImplMethods(&insMethods[0], insMethods.size(),
&clsMethods[0], clsMethods.size());
ObjcInterfaceDecl* IDecl = CatImplClass->getClassInterface();
// Find category interface decl and then check that all methods declared
// in this interface is implemented in the category @implementation.
if (IDecl) {
for (ObjcCategoryDecl *Categories = IDecl->getListCategories();
Categories; Categories = Categories->getNextClassCategory()) {
if (Categories->getCatName() == CatImplClass->getObjcCatName()) {
ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories);
break;
}
}
}
}
else
assert(0 && "Sema::ObjcAddMethodsToClass(): Unknown DeclTy");
return;

View File

@@ -737,6 +737,7 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
projectDirPath = "";

View File

@@ -35,7 +35,7 @@ public:
Function, BlockVariable, FileVariable, ParmVariable, EnumConstant,
// Concrete sub-classes of TypeDecl
Typedef, Struct, Union, Class, Enum, ObjcInterface, ObjcClass, ObjcMethod,
ObjcProtocol, ObjcForwardProtocol, ObjcCategory,
ObjcProtocol, ObjcForwardProtocol, ObjcCategory, ObjcCategoryImpl,
ObjcImplementation,
// Concrete sub-class of Decl
Field, ObjcIvar

View File

@@ -448,6 +448,17 @@ public:
CatReferencedProtocols[idx] = OID;
}
ObjcProtocolDecl **getCatReferencedProtocols() const {
return CatReferencedProtocols;
}
int getNumCatReferencedProtocols() const { return NumCatReferencedProtocols; }
ObjcMethodDecl **getCatInsMethods() const { return CatInsMethods; }
int getNumCatInsMethods() const { return NumCatInsMethods; }
ObjcMethodDecl **getCatClsMethods() const { return CatClsMethods; }
int getNumCatClsMethods() const { return NumCatClsMethods; }
void ObjcAddCatMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
ObjcMethodDecl **clsMethods, unsigned numClsMembers);
@@ -466,6 +477,56 @@ public:
static bool classof(const ObjcCategoryDecl *D) { return true; }
};
/// ObjcCategoryImplDecl - An object of this class encapsulates a category
/// @implementation declaration.
class ObjcCategoryImplDecl : public Decl {
/// Class interface for this category implementation
ObjcInterfaceDecl *ClassInterface;
/// Category name
IdentifierInfo *ObjcCatName;
/// category instance methods being implemented
ObjcMethodDecl **CatInsMethods; // Null if category is not implementing any
int NumCatInsMethods; // -1 if category is not implementing any
/// category class methods being implemented
ObjcMethodDecl **CatClsMethods; // Null if category is not implementing any
int NumCatClsMethods; // -1 if category is not implementing any
public:
ObjcCategoryImplDecl(SourceLocation L, IdentifierInfo *Id,
ObjcInterfaceDecl *classInterface,
IdentifierInfo *catName)
: Decl(ObjcCategoryImpl),
ClassInterface(classInterface),
ObjcCatName(catName),
CatInsMethods(0), NumCatInsMethods(-1),
CatClsMethods(0), NumCatClsMethods(-1) {}
ObjcInterfaceDecl *getClassInterface() const {
return ClassInterface;
}
IdentifierInfo *getObjcCatName() const { return ObjcCatName; }
ObjcMethodDecl **getCatInsMethods() const { return CatInsMethods; }
int getNumCatInsMethods() const { return NumCatInsMethods; }
ObjcMethodDecl **getCatClsMethods() const { return CatClsMethods; }
int getNumCatClsMethods() const { return NumCatClsMethods; }
void ObjcAddCatImplMethods(
ObjcMethodDecl **insMethods, unsigned numInsMembers,
ObjcMethodDecl **clsMethods, unsigned numClsMembers);
static bool classof(const Decl *D) {
return D->getKind() == ObjcCategoryImpl;
}
static bool classof(const ObjcCategoryImplDecl *D) { return true; }
};
/// ObjcImplementationDecl - Represents a class definition - this is where
/// method definitions are specified. For example:
///

View File

@@ -472,6 +472,14 @@ public:
SourceLocation SuperClassLoc) {
return 0;
}
virtual DeclTy *ObjcStartCategoryImplementation(Scope* S,
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
IdentifierInfo *CatName,
SourceLocation CatLoc) {
return 0;
}
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType, Selector Sel,
// optional arguments. The number of types/arguments is obtained

View File

@@ -0,0 +1,26 @@
@interface MyClass1
@end
@protocol P
- (void) Pmeth; // expected-warning {{method definition for 'Pmeth' not found}}
- (void) Pmeth1; // expected-warning {{method definition for 'Pmeth1' not found}}
@end
@interface MyClass1(CAT) <P>
- (void) meth2; // expected-warning {{method definition for 'meth2' not found}}
@end
@implementation MyClass1(CAT)
- (void) Pmeth1{}
@end
@interface MyClass1(DOG) <P>
- (void)ppp; // expected-warning {{method definition for 'ppp' not found}}
@end
@implementation MyClass1(DOG)
- (void) Pmeth {}
@end
@implementation MyClass1(CAT1)
@end