Patch for method implementation. It populates ObjcImplementationDecl object with method implementation declarations .

It checks and warns on those methods declared in class interface and not implemented.

llvm-svn: 42412
This commit is contained in:
Fariborz Jahanian 2007-09-27 18:57:03 +00:00
parent 65ca537b55
commit f6546b38b2
11 changed files with 160 additions and 8 deletions

View File

@ -364,4 +364,23 @@ void ObjcCategoryDecl::ObjcAddCatMethods(ObjcMethodDecl **insMethods,
}
}
/// ObjcAddImplMethods - Insert instance and methods declarations into
/// ObjcImplementationDecl's InsMethods and ClsMethods fields.
///
void ObjcImplementationDecl::ObjcAddImplMethods(ObjcMethodDecl **insMethods,
unsigned numInsMembers,
ObjcMethodDecl **clsMethods,
unsigned numClsMembers) {
NumInsMethods = numInsMembers;
if (numInsMembers) {
InsMethods = new ObjcMethodDecl*[numInsMembers];
memcpy(InsMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*));
}
NumClsMethods = numClsMembers;
if (numClsMembers) {
ClsMethods = new ObjcMethodDecl*[numClsMembers];
memcpy(ClsMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*));
}
}

View File

@ -882,12 +882,22 @@ Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration(
if (Tok.getKind() == tok::l_brace)
ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/); // we have ivars
return 0;
return ImplClsType;
}
Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
"ParseObjCAtEndDeclaration(): Expected @end");
ConsumeToken(); // the "end" identifier
if (ObjcImpDecl) {
// Checking is not necessary except that a parse error might have caused
// @implementation not to have been parsed to completion and ObjcImpDecl
// could be 0.
/// Insert collected methods declarations into the @interface object.
Actions.ObjcAddMethodsToClass(ObjcImpDecl,
&AllImplMethods[0],AllImplMethods.size());
ObjcImpDecl = 0;
AllImplMethods.clear();
}
return 0;
}
@ -1056,7 +1066,7 @@ void Parser::ParseObjCInstanceMethodDefinition() {
assert(Tok.getKind() == tok::minus &&
"ParseObjCInstanceMethodDefinition(): Expected '-'");
// FIXME: @optional/@protocol??
ParseObjCMethodPrototype(ObjcImpDecl);
AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
// parse optional ';'
if (Tok.getKind() == tok::semi)
ConsumeToken();
@ -1075,7 +1085,7 @@ void Parser::ParseObjCClassMethodDefinition() {
assert(Tok.getKind() == tok::plus &&
"ParseObjCClassMethodDefinition(): Expected '+'");
// FIXME: @optional/@protocol??
ParseObjCMethodPrototype(ObjcImpDecl);
AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
// parse optional ';'
if (Tok.getKind() == tok::semi)
ConsumeToken();

View File

@ -23,6 +23,7 @@ Parser::Parser(Preprocessor &pp, Action &actions)
NumCachedScopes = 0;
ParenCount = BracketCount = BraceCount = 0;
ObjcImpDecl = 0;
AllImplMethods.clear();
}
/// Out-of-line virtual destructor to provide home for Action class.

View File

@ -390,6 +390,8 @@ public:
virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
DeclTy **Fields, unsigned NumFields);
virtual void ActOnImplMethodsVsClassMethods(DeclTy *ImplClass, DeclTy *Class);
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel,
// optional arguments. The number of types/arguments is obtained

View File

@ -1174,6 +1174,49 @@ void Sema::ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
}
void Sema::ActOnImplMethodsVsClassMethods(DeclTy* ImplClassDecl,
DeclTy* ClassDecl) {
ObjcImplementationDecl* IMPDecl =
cast<ObjcImplementationDecl>(static_cast<Decl*>(ImplClassDecl));
assert(IMPDecl && "missing implmentation class decl");
ObjcInterfaceDecl* IDecl =
cast<ObjcInterfaceDecl>(static_cast<Decl*>(ClassDecl));
assert(IDecl && "missing interface class decl");
llvm::DenseMap<const SelectorInfo*, char> Map;
// Check and see if instance methods in class interface have been
// implemented in the implementation class.
ObjcMethodDecl **methods = IMPDecl->getInsMethods();
for (int i=0; i < IMPDecl->getNumInsMethods(); i++) {
Map[methods[i]->getSelector()] = 'a';
}
methods = IDecl->getInsMethods();
for (int j = 0; j < IDecl->getNumInsMethods(); j++)
if (!Map.count(methods[j]->getSelector())) {
llvm::SmallString<128> buf;
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
methods[j]->getSelector()->getName(buf));
}
Map.clear();
// Check and see if class methods in class interface have been
// implemented in the implementation class.
methods = IMPDecl->getClsMethods();
for (int i=0; i < IMPDecl->getNumClsMethods(); i++) {
Map[methods[i]->getSelector()] = 'a';
}
methods = IDecl->getClsMethods();
for (int j = 0; j < IDecl->getNumClsMethods(); j++)
if (!Map.count(methods[j]->getSelector())) {
llvm::SmallString<128> buf;
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
methods[j]->getSelector()->getName(buf));
}
return;
}
/// ObjcClassDeclaration -
/// Scope will always be top level file scope.
Action::DeclTy *
@ -1560,7 +1603,17 @@ void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl,
static_cast<Decl*>(ClassDecl));
Category->ObjcAddCatMethods(&insMethods[0], insMethods.size(),
&clsMethods[0], clsMethods.size());
}
}
else if (isa<ObjcImplementationDecl>(static_cast<Decl *>(ClassDecl))) {
ObjcImplementationDecl* ImplClass = cast<ObjcImplementationDecl>(
static_cast<Decl*>(ClassDecl));
ImplClass->ObjcAddImplMethods(&insMethods[0], insMethods.size(),
&clsMethods[0], clsMethods.size());
ObjcInterfaceDecl* IDecl =
Context.getObjCInterfaceDecl(ImplClass->getIdentifier());
if (IDecl)
ActOnImplMethodsVsClassMethods(ImplClass, IDecl);
}
else
assert(0 && "Sema::ObjcAddMethodsToClass(): Unknown DeclTy");
return;

View File

@ -733,6 +733,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

@ -591,6 +591,12 @@ public:
ObjcIvarDecl **getIntfDeclIvars() const { return Ivars; }
int getIntfDeclNumIvars() const { return NumIvars; }
ObjcMethodDecl** getInsMethods() const { return InsMethods; }
int getNumInsMethods() const { return NumInsMethods; }
ObjcMethodDecl** getClsMethods() const { return ClsMethods; }
int getNumClsMethods() const { return NumClsMethods; }
void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars,
unsigned numIvars);
@ -677,6 +683,9 @@ private:
/// List of attributes for this method declaration.
AttributeList *MethodAttrs;
/// Loc - location of this declaration.
SourceLocation Loc;
/// instance (true) or class (false) method.
bool IsInstance : 1;
@ -690,7 +699,7 @@ public:
Decl *PrevDecl = 0)
: Decl(ObjcMethod), Selector(SelInfo), MethodDeclType(T),
ParamInfo(paramInfo), NumMethodParams(numParams),
MethodAttrs(M), IsInstance(isInstance) {}
MethodAttrs(M), Loc(L), IsInstance(isInstance) {}
#if 0
ObjcMethodDecl(Kind DK, SourceLocation L, IdentifierInfo &SelId, QualType T,
ParmVarDecl **paramInfo = 0, int numParams=-1,
@ -701,6 +710,7 @@ public:
MethodAttrs(M), IsInstance(isInstance) {}
#endif
virtual ~ObjcMethodDecl();
SelectorInfo *getSelector() const { return Selector; }
QualType getMethodType() const { return MethodDeclType; }
unsigned getNumMethodParams() const { return NumMethodParams; }
ParmVarDecl *getMethodParamDecl(unsigned i) {
@ -710,6 +720,7 @@ public:
void setMethodParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
AttributeList *getMethodAttrs() const {return MethodAttrs;}
SourceLocation getLocation() const { return Loc; }
bool isInstance() const { return IsInstance; }
// Related to protocols declared in @protocol
void setDeclImplementation(ImplementationControl ic)
@ -890,13 +901,19 @@ class ObjcImplementationDecl : public TypeDecl {
void ObjcAddInstanceVariablesToClassImpl(ObjcIvarDecl **ivars,
unsigned numIvars);
void ObjcAddMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
ObjcMethodDecl **clsMethods, unsigned numClsMembers);
void ObjcAddImplMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
ObjcMethodDecl **clsMethods, unsigned numClsMembers);
ObjcInterfaceDecl *getImplSuperClass() const { return SuperClass; }
void setImplSuperClass(ObjcInterfaceDecl * superCls)
{ SuperClass = superCls; }
ObjcMethodDecl **getInsMethods() const { return InsMethods; }
int getNumInsMethods() const { return NumInsMethods; }
ObjcMethodDecl **getClsMethods() const { return ClsMethods; }
int getNumClsMethods() const { return NumClsMethods; }
static bool classof(const Decl *D) {
return D->getKind() == ObjcImplementation;

View File

@ -432,7 +432,8 @@ DIAG(err_inconsistant_ivar, ERROR,
"inconsistent instance variable specification")
DIAG(err_conflicting_ivar_type, ERROR,
"conflicting instance variable type")
DIAG(warn_undef_method_impl, WARNING,
"method definition for '%0' not found")
//===----------------------------------------------------------------------===//
// Semantic Analysis

View File

@ -451,6 +451,10 @@ public:
DeclTy **Fields, unsigned NumFields) {
return;
}
virtual void ActOnImplMethodsVsClassMethods(DeclTy *ImplClassDecl,
DeclTy *ClassDecl) {
return;
}
virtual DeclTy *ObjcStartProtoInterface(Scope* S,
SourceLocation AtProtoInterfaceLoc,
IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,

View File

@ -265,6 +265,8 @@ private:
DeclTy *ParseObjCAtProtocolDeclaration(SourceLocation atLoc);
DeclTy *ObjcImpDecl;
/// Vector is used to collect method decls for each @implementation
llvm::SmallVector<DeclTy*, 32> AllImplMethods;
DeclTy *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
DeclTy *ParseObjCAtEndDeclaration(SourceLocation atLoc);
DeclTy *ParseObjCAtAliasDeclaration(SourceLocation atLoc);

View File

@ -0,0 +1,42 @@
@interface INTF
- (void) meth;
- (void) meth : (int) arg1;
- (int) int_meth; // expected-warning {{method definition for 'int_meth' not found}}
+ (int) cls_meth; // expected-warning {{method definition for 'cls_meth' not found}}
+ (void) cls_meth1 : (int) arg1; // expected-warning {{method definition for 'cls_meth1:' not found}}
@end
@implementation INTF
- (void) meth {}
- (void) meth : (int) arg2{}
- (void) cls_meth1 : (int) arg2{}
@end
@interface INTF1
- (void) meth;
- (void) meth : (int) arg1;
- (int) int_meth; // expected-warning {{method definition for 'int_meth' not found}}
+ (int) cls_meth; // expected-warning {{method definition for 'cls_meth' not found}}
+ (void) cls_meth1 : (int) arg1; // expected-warning {{method definition for 'cls_meth1:' not found}}
@end
@implementation INTF1
- (void) meth {}
- (void) meth : (int) arg2{}
- (void) cls_meth1 : (int) arg2{}
@end
@interface INTF2
- (void) meth;
- (void) meth : (int) arg1;
- (void) cls_meth1 : (int) arg1;
@end
@implementation INTF2
- (void) meth {}
- (void) meth : (int) arg2{}
- (void) cls_meth1 : (int) arg2{}
@end