From d0b90bff98bafb72ea9809f509bf37c93c60e74e Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 26 Sep 2007 18:27:25 +0000 Subject: [PATCH] This patch inserts ivars declared in @implementation in its object and verifies that they conform(in type, name and numbers) to those declared in @interface. Test case highlights kind of checking we do here. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42360 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/Decl.cpp | 13 ++++ Sema/Sema.h | 4 ++ Sema/SemaDecl.cpp | 61 +++++++++++++++++- include/clang/AST/Decl.h | 7 ++- include/clang/Basic/DiagnosticKinds.def | 7 +++ include/clang/Parse/Action.h | 4 ++ test/Sema/conflicting-ivar-test-1.m | 84 +++++++++++++++++++++++++ 7 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 test/Sema/conflicting-ivar-test-1.m diff --git a/AST/Decl.cpp b/AST/Decl.cpp index c0a77a2faa..83762e9465 100644 --- a/AST/Decl.cpp +++ b/AST/Decl.cpp @@ -294,6 +294,19 @@ void ObjcInterfaceDecl::ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, } } +/// ObjcAddInstanceVariablesToClassImpl - Checks for correctness of Instance +/// Variables (Ivars) relative to what declared in @implementation;s class. +/// Ivars into ObjcImplementationDecl's fields. +/// +void ObjcImplementationDecl::ObjcAddInstanceVariablesToClassImpl( + ObjcIvarDecl **ivars, unsigned numIvars) { + NumIvars = numIvars; + if (numIvars) { + Ivars = new ObjcIvarDecl*[numIvars]; + memcpy(Ivars, ivars, numIvars*sizeof(ObjcIvarDecl*)); + } +} + /// addObjcMethods - Insert instance and methods declarations into /// ObjcInterfaceDecl's InsMethods and ClsMethods fields. /// diff --git a/Sema/Sema.h b/Sema/Sema.h index 0891c66453..bb83b0e6ae 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -386,6 +386,10 @@ public: virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl, DeclTy **allMethods, unsigned allNum); + + virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl, + DeclTy **Fields, unsigned NumFields); + virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, tok::TokenKind MethodType, TypeTy *ReturnType, ObjcKeywordDecl *Keywords, unsigned NumKeywords, diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 5470eb456b..1fb4142796 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -1129,6 +1129,51 @@ Sema::DeclTy *Sema::ObjcStartClassImplementation(Scope *S, return IMPDecl; } +void Sema::ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl, + DeclTy **Fields, unsigned numIvars) { + ObjcInterfaceDecl* IDecl = + cast(static_cast(ClassDecl)); + assert(IDecl && "missing named interface class decl"); + ObjcIvarDecl** ivars = reinterpret_cast(Fields); + assert(ivars && "missing @implementation ivars"); + + // Check interface's Ivar list against those in the implementation. + // names and types must match. + // + ObjcIvarDecl** IntfIvars = IDecl->getIntfDeclIvars(); + int IntfNumIvars = IDecl->getIntfDeclNumIvars(); + unsigned j = 0; + bool err = false; + while (numIvars > 0 && IntfNumIvars > 0) { + ObjcIvarDecl* ImplIvar = ivars[j]; + ObjcIvarDecl* ClsIvar = IntfIvars[j++]; + assert (ImplIvar && "missing implementation ivar"); + assert (ClsIvar && "missing class ivar"); + if (ImplIvar->getCanonicalType() != ClsIvar->getCanonicalType()) { + Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type, + ImplIvar->getIdentifier()->getName()); + Diag(ClsIvar->getLocation(), diag::err_previous_definition, + ClsIvar->getIdentifier()->getName()); + } + // TODO: Two mismatched (unequal width) Ivar bitfields should be diagnosed + // as error. + else if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) { + Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name, + ImplIvar->getIdentifier()->getName()); + Diag(ClsIvar->getLocation(), diag::err_previous_definition, + ClsIvar->getIdentifier()->getName()); + err = true; + break; + } + --numIvars; + --IntfNumIvars; + } + if (!err && (numIvars > 0 || IntfNumIvars > 0)) + Diag(numIvars > 0 ? ivars[j]->getLocation() : IntfIvars[j]->getLocation(), + diag::err_inconsistant_ivar); + +} + /// ObjcClassDeclaration - /// Scope will always be top level file scope. Action::DeclTy * @@ -1463,8 +1508,20 @@ void Sema::ActOnFields(SourceLocation RecLoc, DeclTy *RecDecl, else { ObjcIvarDecl **ClsFields = reinterpret_cast(&RecFields[0]); - cast(static_cast(RecDecl))-> - ObjcAddInstanceVariablesToClass(ClsFields, RecFields.size()); + if (isa(static_cast(RecDecl))) + cast(static_cast(RecDecl))-> + ObjcAddInstanceVariablesToClass(ClsFields, RecFields.size()); + else if (isa(static_cast(RecDecl))) { + ObjcImplementationDecl* IMPDecl = + cast(static_cast(RecDecl)); + assert(IMPDecl && "ActOnFields - missing ObjcImplementationDecl"); + IMPDecl->ObjcAddInstanceVariablesToClassImpl(ClsFields, RecFields.size()); + ObjcInterfaceDecl* IDecl = + Context.getObjCInterfaceDecl(IMPDecl->getIdentifier()); + if (IDecl) + ActOnImpleIvarVsClassIvars(static_cast(IDecl), + reinterpret_cast(&RecFields[0]), RecFields.size()); + } } } diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 7cb370b41c..b420c1da81 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -587,6 +587,9 @@ public: NumIntfRefProtocols = numRefProtos; } } + ObjcIvarDecl **getIntfDeclIvars() const { return Ivars; } + int getIntfDeclNumIvars() const { return NumIvars; } + void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, unsigned numIvars); @@ -883,8 +886,8 @@ class ObjcImplementationDecl : public TypeDecl { Ivars(0), NumIvars(-1), InsMethods(0), NumInsMethods(-1), ClsMethods(0), NumClsMethods(-1) {} - void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, - unsigned numIvars); + void ObjcAddInstanceVariablesToClassImpl(ObjcIvarDecl **ivars, + unsigned numIvars); void ObjcAddMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers, ObjcMethodDecl **clsMethods, unsigned numClsMembers); diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index bd41546cd3..d77e6b4d24 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -426,6 +426,13 @@ DIAG(err_dup_implementation_class, ERROR, "reimplementation of class '%0'") DIAG(err_conflicting_super_class, ERROR, "conflicting super class name '%0'") +DIAG(err_conflicting_ivar_name, ERROR, + "conflicting instance variable name '%0'") +DIAG(err_inconsistant_ivar, ERROR, + "inconsistent instance variable specification") +DIAG(err_conflicting_ivar_type, ERROR, + "conflicting instance variable type") + //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index fe902fc00f..bc14226bec 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -448,6 +448,10 @@ public: DeclTy **allMethods, unsigned allNum) { return; } + virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl, + DeclTy **Fields, unsigned NumFields) { + return; + } virtual DeclTy *ObjcStartProtoInterface(Scope* S, SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, diff --git a/test/Sema/conflicting-ivar-test-1.m b/test/Sema/conflicting-ivar-test-1.m new file mode 100644 index 0000000000..e08da34bc2 --- /dev/null +++ b/test/Sema/conflicting-ivar-test-1.m @@ -0,0 +1,84 @@ +@interface INTF +{ +@public + int IVAR; // expected-error {{previous definition is here}} +} +@end + +@implementation INTF +{ +@private + + int XIVAR; // expected-error {{conflicting instance variable name 'XIVAR'}} +} +@end + + + +@interface INTF1 +{ +@public + int IVAR; + int IVAR1; // expected-error {{inconsistent instance variable specification}} +} +@end + +@implementation INTF1 +{ +@private + + int IVAR; +} +@end + + +@interface INTF2 +{ +@public + int IVAR; +} +@end + +@implementation INTF2 +{ +@private + + int IVAR; + int IVAR1; // expected-error {{inconsistent instance variable specification}} +} +@end + + +@interface INTF3 +{ +@public + int IVAR; // expected-error {{previous definition is here}} +} +@end + +@implementation INTF3 +{ +@private + + short IVAR; // expected-error {{conflicting instance variable type}} +} +@end + +@implementation INTF4 // expected-warning {{cannot find interface declaration for 'INTF4'}} +{ +@private + + short IVAR; +} +@end + +@interface INTF5 +{ + char * ch; +} +@end + +@implementation INTF5 +{ +} +@end -- 2.40.0