aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2007-09-27 18:57:03 +0000
committerFariborz Jahanian <fjahanian@apple.com>2007-09-27 18:57:03 +0000
commitd0b015461a819913efa1161c56a8b897d7e8cdb2 (patch)
tree93683180c25a289b89c3c8ce08091011c0cd5694
parent4cbcb897fe7c4ff1ed5322ee4dfd490c581e33d5 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42412 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--AST/Decl.cpp19
-rw-r--r--Parse/ParseObjc.cpp16
-rw-r--r--Parse/Parser.cpp1
-rw-r--r--Sema/Sema.h2
-rw-r--r--Sema/SemaDecl.cpp55
-rw-r--r--clang.xcodeproj/project.pbxproj1
-rw-r--r--include/clang/AST/Decl.h23
-rw-r--r--include/clang/Basic/DiagnosticKinds.def3
-rw-r--r--include/clang/Parse/Action.h4
-rw-r--r--include/clang/Parse/Parser.h2
-rw-r--r--test/Sema/method-undefined-warn-1.m42
11 files changed, 160 insertions, 8 deletions
diff --git a/AST/Decl.cpp b/AST/Decl.cpp
index 83762e9465..10da7b163e 100644
--- a/AST/Decl.cpp
+++ b/AST/Decl.cpp
@@ -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*));
+ }
+}
+
diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp
index 9da15fafd2..d8361b07df 100644
--- a/Parse/ParseObjc.cpp
+++ b/Parse/ParseObjc.cpp
@@ -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();
diff --git a/Parse/Parser.cpp b/Parse/Parser.cpp
index b9bcc929a5..362ca35512 100644
--- a/Parse/Parser.cpp
+++ b/Parse/Parser.cpp
@@ -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.
diff --git a/Sema/Sema.h b/Sema/Sema.h
index a486d4fa73..45d1a2dc33 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -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
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index dd8fe22cc9..381003f86a 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -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;
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 04dad73923..fca0464b47 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -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 = "";
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index ea8121326e..b3c30e5334 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -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;
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index c394663dd9..937684c7f6 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -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
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 3e9a687ef4..48ae4bea84 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -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,
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 243b88f9ff..3982028ff2 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -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);
diff --git a/test/Sema/method-undefined-warn-1.m b/test/Sema/method-undefined-warn-1.m
new file mode 100644
index 0000000000..2c7cdadcf0
--- /dev/null
+++ b/test/Sema/method-undefined-warn-1.m
@@ -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
+