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:
parent
65ca537b55
commit
f6546b38b2
|
@ -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*));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue