mirror of
https://github.com/intel/llvm.git
synced 2026-01-28 01:04:49 +08:00
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:
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
///
|
||||
|
||||
@@ -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
|
||||
|
||||
26
clang/test/Sema/method-undef-category-warn-1.m
Normal file
26
clang/test/Sema/method-undef-category-warn-1.m
Normal 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
|
||||
Reference in New Issue
Block a user