From: Chris Lattner Date: Wed, 12 Dec 2007 07:09:47 +0000 (+0000) Subject: split objc pieces of SemaDecl.cpp out into SemaDeclObjC.cpp X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4d3914836e85258e9ace7306999413e3c7ea6c11;p=clang split objc pieces of SemaDecl.cpp out into SemaDeclObjC.cpp git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44925 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 193abc40ac..92e1f84479 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -15,7 +15,6 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Builtins.h" #include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/Parse/DeclSpec.h" @@ -25,7 +24,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/DenseSet.h" -#include "clang/Lex/Preprocessor.h" using namespace clang; Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const { @@ -210,7 +208,7 @@ TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *OldD) { // Allow multiple definitions for ObjC built-in typedefs. // FIXME: Verify the underlying types are equivalent! - if (PP.getLangOptions().ObjC1 && isBuiltinObjcType(New)) + if (getLangOptions().ObjC1 && isBuiltinObjcType(New)) return Old; // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. @@ -1050,45 +1048,6 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtTy *Body) { return D; } -/// ObjcActOnStartOfMethodDef - This routine sets up parameters; invisible -/// and user declared, in the method definition's AST. -void Sema::ObjcActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { - assert(CurFunctionDecl == 0 && "Method parsing confused"); - ObjcMethodDecl *MDecl = dyn_cast(static_cast(D)); - assert(MDecl != 0 && "Not a method declarator!"); - - // Allow all of Sema to see that we are entering a method definition. - CurMethodDecl = MDecl; - - // Create Decl objects for each parameter, entrring them in the scope for - // binding to their use. - struct DeclaratorChunk::ParamInfo PI; - - // Insert the invisible arguments, self and _cmd! - PI.Ident = &Context.Idents.get("self"); - PI.IdentLoc = SourceLocation(); // synthesized vars have a null location. - PI.InvalidType = false; - if (MDecl->isInstance()) { - QualType selfTy = Context.getObjcInterfaceType(MDecl->getClassInterface()); - selfTy = Context.getPointerType(selfTy); - PI.TypeInfo = selfTy.getAsOpaquePtr(); - } else - PI.TypeInfo = Context.getObjcIdType().getAsOpaquePtr(); - CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope)); - - PI.Ident = &Context.Idents.get("_cmd"); - PI.TypeInfo = Context.getObjcSelType().getAsOpaquePtr(); - ActOnParamDeclarator(PI, FnBodyScope); - - for (int i = 0; i < MDecl->getNumParams(); i++) { - ParmVarDecl *PDecl = MDecl->getParamDecl(i); - PI.Ident = PDecl->getIdentifier(); - PI.IdentLoc = PDecl->getLocation(); // user vars have a real location. - PI.TypeInfo = PDecl->getType().getAsOpaquePtr(); - ActOnParamDeclarator(PI, FnBodyScope); - } -} - /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, @@ -1135,550 +1094,6 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, return NewTD; } -Sema::DeclTy *Sema::ActOnStartClassInterface( - SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperName, SourceLocation SuperLoc, - IdentifierInfo **ProtocolNames, unsigned NumProtocols, - SourceLocation EndProtoLoc, AttributeList *AttrList) { - assert(ClassName && "Missing class identifier"); - - // Check for another declaration kind with the same name. - ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); - if (PrevDecl && !isa(PrevDecl)) { - Diag(ClassLoc, diag::err_redefinition_different_kind, - ClassName->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - - ObjcInterfaceDecl* IDecl = dyn_cast_or_null(PrevDecl); - if (IDecl) { - // Class already seen. Is it a forward declaration? - if (!IDecl->isForwardDecl()) - Diag(AtInterfaceLoc, diag::err_duplicate_class_def, IDecl->getName()); - else { - IDecl->setLocation(AtInterfaceLoc); - IDecl->setForwardDecl(false); - IDecl->AllocIntfRefProtocols(NumProtocols); - } - } - else { - IDecl = new ObjcInterfaceDecl(AtInterfaceLoc, NumProtocols, ClassName); - - // Chain & install the interface decl into the identifier. - IDecl->setNext(ClassName->getFETokenInfo()); - ClassName->setFETokenInfo(IDecl); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(IDecl); - } - - if (SuperName) { - ObjcInterfaceDecl* SuperClassEntry = 0; - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupInterfaceDecl(SuperName); - if (PrevDecl && !isa(PrevDecl)) { - Diag(SuperLoc, diag::err_redefinition_different_kind, - SuperName->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - else { - // Check that super class is previously defined - SuperClassEntry = dyn_cast_or_null(PrevDecl); - - if (!SuperClassEntry || SuperClassEntry->isForwardDecl()) { - Diag(AtInterfaceLoc, diag::err_undef_superclass, - SuperClassEntry ? SuperClassEntry->getName() - : SuperName->getName(), - ClassName->getName()); - } - } - IDecl->setSuperClass(SuperClassEntry); - IDecl->setLocEnd(SuperLoc); - } else { // we have a root class. - IDecl->setLocEnd(ClassLoc); - } - - /// Check then save referenced protocols - if (NumProtocols) { - for (unsigned int i = 0; i != NumProtocols; i++) { - ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtocolNames[i]]; - if (!RefPDecl || RefPDecl->isForwardDecl()) - Diag(ClassLoc, diag::warn_undef_protocolref, - ProtocolNames[i]->getName(), - ClassName->getName()); - IDecl->setIntfRefProtocols((int)i, RefPDecl); - } - IDecl->setLocEnd(EndProtoLoc); - } - return IDecl; -} - -/// ActOnCompatiblityAlias - this action is called after complete parsing of -/// @compaatibility_alias declaration. It sets up the alias relationships. -Sema::DeclTy *Sema::ActOnCompatiblityAlias( - SourceLocation AtCompatibilityAliasLoc, - IdentifierInfo *AliasName, SourceLocation AliasLocation, - IdentifierInfo *ClassName, SourceLocation ClassLocation) { - // Look for previous declaration of alias name - ScopedDecl *ADecl = LookupScopedDecl(AliasName, Decl::IDNS_Ordinary, - AliasLocation, TUScope); - if (ADecl) { - if (isa(ADecl)) { - Diag(AliasLocation, diag::warn_previous_alias_decl); - Diag(ADecl->getLocation(), diag::warn_previous_declaration); - } - else { - Diag(AliasLocation, diag::err_conflicting_aliasing_type, - AliasName->getName()); - Diag(ADecl->getLocation(), diag::err_previous_declaration); - } - return 0; - } - // Check for class declaration - ScopedDecl *CDecl = LookupScopedDecl(ClassName, Decl::IDNS_Ordinary, - ClassLocation, TUScope); - if (!CDecl || !isa(CDecl)) { - Diag(ClassLocation, diag::warn_undef_interface, - ClassName->getName()); - if (CDecl) - Diag(CDecl->getLocation(), diag::warn_previous_declaration); - return 0; - } - // Everything checked out, instantiate a new alias declaration ast - ObjcCompatibleAliasDecl *AliasDecl = - new ObjcCompatibleAliasDecl(AtCompatibilityAliasLoc, - AliasName, - dyn_cast(CDecl)); - - // Chain & install the interface decl into the identifier. - AliasDecl->setNext(AliasName->getFETokenInfo()); - AliasName->setFETokenInfo(AliasDecl); - return AliasDecl; -} - -Sema::DeclTy *Sema::ActOnStartProtocolInterface( - SourceLocation AtProtoInterfaceLoc, - IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, - IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, - SourceLocation EndProtoLoc) { - assert(ProtocolName && "Missing protocol identifier"); - ObjcProtocolDecl *PDecl = ObjcProtocols[ProtocolName]; - if (PDecl) { - // Protocol already seen. Better be a forward protocol declaration - if (!PDecl->isForwardDecl()) - Diag(ProtocolLoc, diag::err_duplicate_protocol_def, - ProtocolName->getName()); - else { - PDecl->setForwardDecl(false); - PDecl->AllocReferencedProtocols(NumProtoRefs); - } - } - else { - PDecl = new ObjcProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs, - ProtocolName); - ObjcProtocols[ProtocolName] = PDecl; - } - - if (NumProtoRefs) { - /// Check then save referenced protocols - for (unsigned int i = 0; i != NumProtoRefs; i++) { - ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtoRefNames[i]]; - if (!RefPDecl || RefPDecl->isForwardDecl()) - Diag(ProtocolLoc, diag::warn_undef_protocolref, - ProtoRefNames[i]->getName(), - ProtocolName->getName()); - PDecl->setReferencedProtocols((int)i, RefPDecl); - } - PDecl->setLocEnd(EndProtoLoc); - } - return PDecl; -} - -/// FindProtocolDeclaration - This routine looks up protocols and -/// issuer error if they are not declared. It returns list of protocol -/// declarations in its 'Protocols' argument. -void -Sema::FindProtocolDeclaration(SourceLocation TypeLoc, - IdentifierInfo **ProtocolId, - unsigned NumProtocols, - llvm::SmallVector &Protocols) { - for (unsigned i = 0; i != NumProtocols; ++i) { - ObjcProtocolDecl *PDecl = ObjcProtocols[ProtocolId[i]]; - if (!PDecl) - Diag(TypeLoc, diag::err_undeclared_protocol, - ProtocolId[i]->getName()); - else - Protocols.push_back(PDecl); - } -} - -/// ActOnForwardProtocolDeclaration - -Action::DeclTy * -Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, - IdentifierInfo **IdentList, unsigned NumElts) { - llvm::SmallVector Protocols; - - for (unsigned i = 0; i != NumElts; ++i) { - IdentifierInfo *P = IdentList[i]; - ObjcProtocolDecl *PDecl = ObjcProtocols[P]; - if (!PDecl) { // Not already seen? - // FIXME: Pass in the location of the identifier! - PDecl = new ObjcProtocolDecl(AtProtocolLoc, 0, P, true); - ObjcProtocols[P] = PDecl; - } - - Protocols.push_back(PDecl); - } - return new ObjcForwardProtocolDecl(AtProtocolLoc, - &Protocols[0], Protocols.size()); -} - -Sema::DeclTy *Sema::ActOnStartCategoryInterface( - SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CategoryName, SourceLocation CategoryLoc, - IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, - SourceLocation EndProtoLoc) { - ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); - - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) { - Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); - return 0; - } - ObjcCategoryDecl *CDecl = new ObjcCategoryDecl(AtInterfaceLoc, NumProtoRefs, - CategoryName); - CDecl->setClassInterface(IDecl); - /// Check for duplicate interface declaration for this category - ObjcCategoryDecl *CDeclChain; - for (CDeclChain = IDecl->getCategoryList(); CDeclChain; - CDeclChain = CDeclChain->getNextClassCategory()) { - if (CDeclChain->getIdentifier() == CategoryName) { - Diag(CategoryLoc, diag::err_dup_category_def, ClassName->getName(), - CategoryName->getName()); - break; - } - } - if (!CDeclChain) - CDecl->insertNextClassCategory(); - - if (NumProtoRefs) { - /// Check then save referenced protocols - for (unsigned int i = 0; i != NumProtoRefs; i++) { - ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtoRefNames[i]]; - if (!RefPDecl || RefPDecl->isForwardDecl()) { - Diag(CategoryLoc, diag::warn_undef_protocolref, - ProtoRefNames[i]->getName(), - CategoryName->getName()); - } - CDecl->setCatReferencedProtocols((int)i, RefPDecl); - } - CDecl->setLocEnd(EndProtoLoc); - } - return CDecl; -} - -/// ActOnStartCategoryImplementation - Perform semantic checks on the -/// category implementation declaration and build an ObjcCategoryImplDecl -/// object. -Sema::DeclTy *Sema::ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CatName, SourceLocation CatLoc) { - ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); - ObjcCategoryImplDecl *CDecl = new ObjcCategoryImplDecl(AtCatImplLoc, - CatName, IDecl); - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) - 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::ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, - SourceLocation SuperClassLoc) { - ObjcInterfaceDecl* IDecl = 0; - // Check for another declaration kind with the same name. - ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); - if (PrevDecl && !isa(PrevDecl)) { - Diag(ClassLoc, diag::err_redefinition_different_kind, - ClassName->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - else { - // Is there an interface declaration of this class; if not, warn! - IDecl = dyn_cast_or_null(PrevDecl); - if (!IDecl) - Diag(ClassLoc, diag::warn_undef_interface, ClassName->getName()); - } - - // Check that super class name is valid class name - ObjcInterfaceDecl* SDecl = 0; - if (SuperClassname) { - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupInterfaceDecl(SuperClassname); - if (PrevDecl && !isa(PrevDecl)) { - Diag(SuperClassLoc, diag::err_redefinition_different_kind, - SuperClassname->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - else { - SDecl = dyn_cast_or_null(PrevDecl); - if (!SDecl) - Diag(SuperClassLoc, diag::err_undef_superclass, - SuperClassname->getName(), ClassName->getName()); - else if (IDecl && IDecl->getSuperClass() != SDecl) { - // This implementation and its interface do not have the same - // super class. - Diag(SuperClassLoc, diag::err_conflicting_super_class, - SDecl->getName()); - Diag(SDecl->getLocation(), diag::err_previous_definition); - } - } - } - - if (!IDecl) { - // Legacy case of @implementation with no corresponding @interface. - // Build, chain & install the interface decl into the identifier. - IDecl = new ObjcInterfaceDecl(AtClassImplLoc, 0, ClassName, - false, true); - IDecl->setNext(ClassName->getFETokenInfo()); - ClassName->setFETokenInfo(IDecl); - IDecl->setSuperClass(SDecl); - IDecl->setLocEnd(ClassLoc); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(IDecl); - } - - ObjcImplementationDecl* IMPDecl = - new ObjcImplementationDecl(AtClassImplLoc, ClassName, IDecl, SDecl); - - // Check that there is no duplicate implementation of this class. - if (ObjcImplementations[ClassName]) - Diag(ClassLoc, diag::err_dup_implementation_class, ClassName->getName()); - else // add it to the list. - ObjcImplementations[ClassName] = IMPDecl; - return IMPDecl; -} - -void Sema::CheckImplementationIvars(ObjcImplementationDecl *ImpDecl, - ObjcIvarDecl **ivars, unsigned numIvars, - SourceLocation RBrace) { - assert(ImpDecl && "missing implementation decl"); - ObjcInterfaceDecl* IDecl = getObjCInterfaceDecl(ImpDecl->getIdentifier()); - if (!IDecl) - return; - /// Check case of non-existing @interface decl. - /// (legacy objective-c @implementation decl without an @interface decl). - /// Add implementations's ivar to the synthesize class's ivar list. - if (IDecl->ImplicitInterfaceDecl()) { - IDecl->addInstanceVariablesToClass(ivars, numIvars, RBrace); - return; - } - // If implementation has empty ivar list, just return. - if (numIvars == 0) - return; - - assert(ivars && "missing @implementation ivars"); - - // Check interface's Ivar list against those in the implementation. - // names and types must match. - // - ObjcIvarDecl** IntfIvars = IDecl->getInstanceVariables(); - int IntfNumIvars = IDecl->getNumInstanceVariables(); - 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); - -} - -/// CheckProtocolMethodDefs - This routine checks unimpletented methods -/// Declared in protocol, and those referenced by it. -void Sema::CheckProtocolMethodDefs(ObjcProtocolDecl *PDecl, - bool& IncompleteImpl, - const llvm::DenseSet &InsMap, - const llvm::DenseSet &ClsMap) { - // check unimplemented instance methods. - ObjcMethodDecl** methods = PDecl->getInstanceMethods(); - for (int j = 0; j < PDecl->getNumInstanceMethods(); j++) { - if (!InsMap.count(methods[j]->getSelector()) && - methods[j]->getImplementationControl() != ObjcMethodDecl::Optional) { - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector().getName()); - IncompleteImpl = true; - } - } - // check unimplemented class methods - methods = PDecl->getClassMethods(); - for (int j = 0; j < PDecl->getNumClassMethods(); j++) - if (!ClsMap.count(methods[j]->getSelector()) && - methods[j]->getImplementationControl() != ObjcMethodDecl::Optional) { - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector().getName()); - IncompleteImpl = true; - } - - // Check on this protocols's referenced protocols, recursively - ObjcProtocolDecl** RefPDecl = PDecl->getReferencedProtocols(); - for (int i = 0; i < PDecl->getNumReferencedProtocols(); i++) - CheckProtocolMethodDefs(RefPDecl[i], IncompleteImpl, InsMap, ClsMap); -} - -void Sema::ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl, - ObjcInterfaceDecl* IDecl) { - llvm::DenseSet InsMap; - // Check and see if instance methods in class interface have been - // implemented in the implementation class. - ObjcMethodDecl *const*methods = IMPDecl->getInstanceMethods(); - for (int i=0; i < IMPDecl->getNumInstanceMethods(); i++) - InsMap.insert(methods[i]->getSelector()); - - bool IncompleteImpl = false; - methods = IDecl->getInstanceMethods(); - for (int j = 0; j < IDecl->getNumInstanceMethods(); j++) - if (!InsMap.count(methods[j]->getSelector())) { - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector().getName()); - IncompleteImpl = true; - } - llvm::DenseSet ClsMap; - // Check and see if class methods in class interface have been - // implemented in the implementation class. - methods = IMPDecl->getClassMethods(); - for (int i=0; i < IMPDecl->getNumClassMethods(); i++) - ClsMap.insert(methods[i]->getSelector()); - - methods = IDecl->getClassMethods(); - for (int j = 0; j < IDecl->getNumClassMethods(); j++) - if (!ClsMap.count(methods[j]->getSelector())) { - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector().getName()); - IncompleteImpl = true; - } - - // Check the protocol list for unimplemented methods in the @implementation - // class. - ObjcProtocolDecl** protocols = IDecl->getReferencedProtocols(); - for (int i = 0; i < IDecl->getNumIntfRefProtocols(); i++) - CheckProtocolMethodDefs(protocols[i], IncompleteImpl, InsMap, ClsMap); - - if (IncompleteImpl) - Diag(IMPDecl->getLocation(), diag::warn_incomplete_impl_class, - IMPDecl->getName()); -} - -/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the -/// category interface is implemented in the category @implementation. -void Sema::ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl, - ObjcCategoryDecl *CatClassDecl) { - llvm::DenseSet InsMap; - // Check and see if instance methods in category interface have been - // implemented in its implementation class. - ObjcMethodDecl *const*methods = CatImplDecl->getInstanceMethods(); - for (int i=0; i < CatImplDecl->getNumInstanceMethods(); i++) - InsMap.insert(methods[i]->getSelector()); - - bool IncompleteImpl = false; - methods = CatClassDecl->getInstanceMethods(); - for (int j = 0; j < CatClassDecl->getNumInstanceMethods(); j++) - if (!InsMap.count(methods[j]->getSelector())) { - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector().getName()); - IncompleteImpl = true; - } - llvm::DenseSet ClsMap; - // Check and see if class methods in category interface have been - // implemented in its implementation class. - methods = CatImplDecl->getClassMethods(); - for (int i=0; i < CatImplDecl->getNumClassMethods(); i++) - ClsMap.insert(methods[i]->getSelector()); - - methods = CatClassDecl->getClassMethods(); - for (int j = 0; j < CatClassDecl->getNumClassMethods(); j++) - if (!ClsMap.count(methods[j]->getSelector())) { - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector().getName()); - IncompleteImpl = true; - } - - // Check the protocol list for unimplemented methods in the @implementation - // class. - ObjcProtocolDecl** protocols = CatClassDecl->getReferencedProtocols(); - for (int i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) { - ObjcProtocolDecl* PDecl = protocols[i]; - CheckProtocolMethodDefs(PDecl, IncompleteImpl, InsMap, ClsMap); - } - if (IncompleteImpl) - Diag(CatImplDecl->getLocation(), diag::warn_incomplete_impl_category, - CatClassDecl->getName()); -} - -/// ActOnForwardClassDeclaration - -Action::DeclTy * -Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, - IdentifierInfo **IdentList, unsigned NumElts) -{ - llvm::SmallVector Interfaces; - - for (unsigned i = 0; i != NumElts; ++i) { - // Check for another declaration kind with the same name. - ScopedDecl *PrevDecl = LookupInterfaceDecl(IdentList[i]); - if (PrevDecl && !isa(PrevDecl)) { - Diag(AtClassLoc, diag::err_redefinition_different_kind, - IdentList[i]->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - ObjcInterfaceDecl *IDecl = dyn_cast_or_null(PrevDecl); - if (!IDecl) { // Not already seen? Make a forward decl. - IDecl = new ObjcInterfaceDecl(AtClassLoc, 0, IdentList[i], true); - // Chain & install the interface decl into the identifier. - IDecl->setNext(IdentList[i]->getFETokenInfo()); - IdentList[i]->setFETokenInfo(IDecl); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(IDecl); - } - - Interfaces.push_back(IDecl); - } - - return new ObjcClassDecl(AtClassLoc, &Interfaces[0], Interfaces.size()); -} - - /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagType indicates what kind of tag this is. TK indicates whether this is a @@ -2007,316 +1422,6 @@ void Sema::ActOnFields(Scope* S, } } -/// MatchTwoMethodDeclarations - Checks that two methods have matching type and -/// returns true, or false, accordingly. -/// TODO: Handle protocol list; such as id in type comparisons -bool Sema:: MatchTwoMethodDeclarations(const ObjcMethodDecl *Method, - const ObjcMethodDecl *PrevMethod) { - if (Method->getResultType().getCanonicalType() != - PrevMethod->getResultType().getCanonicalType()) - return false; - for (int i = 0; i < Method->getNumParams(); i++) { - ParmVarDecl *ParamDecl = Method->getParamDecl(i); - ParmVarDecl *PrevParamDecl = PrevMethod->getParamDecl(i); - if (ParamDecl->getCanonicalType() != PrevParamDecl->getCanonicalType()) - return false; - } - return true; -} - -void Sema::AddInstanceMethodToGlobalPool(ObjcMethodDecl *Method) { - ObjcMethodList &FirstMethod = InstanceMethodPool[Method->getSelector()]; - if (!FirstMethod.Method) { - // Haven't seen a method with this selector name yet - add it. - FirstMethod.Method = Method; - FirstMethod.Next = 0; - } else { - // We've seen a method with this name, now check the type signature(s). - bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); - - for (ObjcMethodList *Next = FirstMethod.Next; !match && Next; - Next = Next->Next) - match = MatchTwoMethodDeclarations(Method, Next->Method); - - if (!match) { - // We have a new signature for an existing method - add it. - // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". - struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next); - FirstMethod.Next = OMI; - } - } -} - -void Sema::AddFactoryMethodToGlobalPool(ObjcMethodDecl *Method) { - ObjcMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()]; - if (!FirstMethod.Method) { - // Haven't seen a method with this selector name yet - add it. - FirstMethod.Method = Method; - FirstMethod.Next = 0; - } else { - // We've seen a method with this name, now check the type signature(s). - bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); - - for (ObjcMethodList *Next = FirstMethod.Next; !match && Next; - Next = Next->Next) - match = MatchTwoMethodDeclarations(Method, Next->Method); - - if (!match) { - // We have a new signature for an existing method - add it. - // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". - struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next); - FirstMethod.Next = OMI; - } - } -} - -void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, - DeclTy **allMethods, unsigned allNum, - DeclTy **allProperties, unsigned pNum) { - Decl *ClassDecl = static_cast(classDecl); - - // FIXME: If we don't have a ClassDecl, we have an error. I (snaroff) would - // prefer we always pass in a decl. If the decl has an error, isInvalidDecl() - // should be true. - if (!ClassDecl) - return; - - llvm::SmallVector insMethods; - llvm::SmallVector clsMethods; - - llvm::DenseMap InsMap; - llvm::DenseMap ClsMap; - - bool isInterfaceDeclKind = - (isa(ClassDecl) || isa(ClassDecl) - || isa(ClassDecl)); - bool checkIdenticalMethods = isa(ClassDecl); - - // TODO: property declaration in category and protocols. - if (pNum != 0 && isa(ClassDecl)) { - ObjcPropertyDecl **properties = new ObjcPropertyDecl*[pNum]; - memcpy(properties, allProperties, pNum*sizeof(ObjcPropertyDecl*)); - dyn_cast(ClassDecl)->setPropertyDecls(properties); - dyn_cast(ClassDecl)->setNumPropertyDecl(pNum); - } - - for (unsigned i = 0; i < allNum; i++ ) { - ObjcMethodDecl *Method = - cast_or_null(static_cast(allMethods[i])); - - if (!Method) continue; // Already issued a diagnostic. - if (Method->isInstance()) { - /// Check for instance method of the same name with incompatible types - const ObjcMethodDecl *&PrevMethod = InsMap[Method->getSelector()]; - bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) - : false; - if (isInterfaceDeclKind && PrevMethod && !match - || checkIdenticalMethods && match) { - Diag(Method->getLocation(), diag::error_duplicate_method_decl, - Method->getSelector().getName()); - Diag(PrevMethod->getLocation(), diag::err_previous_declaration); - } else { - insMethods.push_back(Method); - InsMap[Method->getSelector()] = Method; - /// The following allows us to typecheck messages to "id". - AddInstanceMethodToGlobalPool(Method); - } - } - else { - /// Check for class method of the same name with incompatible types - const ObjcMethodDecl *&PrevMethod = ClsMap[Method->getSelector()]; - bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) - : false; - if (isInterfaceDeclKind && PrevMethod && !match - || checkIdenticalMethods && match) { - Diag(Method->getLocation(), diag::error_duplicate_method_decl, - Method->getSelector().getName()); - Diag(PrevMethod->getLocation(), diag::err_previous_declaration); - } else { - clsMethods.push_back(Method); - ClsMap[Method->getSelector()] = Method; - /// The following allows us to typecheck messages to "id". - AddInstanceMethodToGlobalPool(Method); - } - } - } - - if (ObjcInterfaceDecl *I = dyn_cast(ClassDecl)) { - I->addMethods(&insMethods[0], insMethods.size(), - &clsMethods[0], clsMethods.size(), AtEndLoc); - } else if (ObjcProtocolDecl *P = dyn_cast(ClassDecl)) { - P->addMethods(&insMethods[0], insMethods.size(), - &clsMethods[0], clsMethods.size(), AtEndLoc); - } - else if (ObjcCategoryDecl *C = dyn_cast(ClassDecl)) { - C->addMethods(&insMethods[0], insMethods.size(), - &clsMethods[0], clsMethods.size(), AtEndLoc); - } - else if (ObjcImplementationDecl *IC = - dyn_cast(ClassDecl)) { - IC->setLocEnd(AtEndLoc); - if (ObjcInterfaceDecl* IDecl = getObjCInterfaceDecl(IC->getIdentifier())) - ImplMethodsVsClassMethods(IC, IDecl); - } else { - ObjcCategoryImplDecl* CatImplClass = cast(ClassDecl); - CatImplClass->setLocEnd(AtEndLoc); - 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->getCategoryList(); - Categories; Categories = Categories->getNextClassCategory()) { - if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { - ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories); - break; - } - } - } - } -} - -/// CvtQTToAstBitMask - utility routine to produce an AST bitmask for -/// objective-c's type qualifier from the parser version of the same info. -static Decl::ObjcDeclQualifier -CvtQTToAstBitMask(ObjcDeclSpec::ObjcDeclQualifier PQTVal) { - Decl::ObjcDeclQualifier ret = Decl::OBJC_TQ_None; - if (PQTVal & ObjcDeclSpec::DQ_In) - ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_In); - if (PQTVal & ObjcDeclSpec::DQ_Inout) - ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Inout); - if (PQTVal & ObjcDeclSpec::DQ_Out) - ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Out); - if (PQTVal & ObjcDeclSpec::DQ_Bycopy) - ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy); - if (PQTVal & ObjcDeclSpec::DQ_Byref) - ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Byref); - if (PQTVal & ObjcDeclSpec::DQ_Oneway) - ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Oneway); - - return ret; -} - -Sema::DeclTy *Sema::ActOnMethodDeclaration( - SourceLocation MethodLoc, SourceLocation EndLoc, - tok::TokenKind MethodType, DeclTy *ClassDecl, - ObjcDeclSpec &ReturnQT, TypeTy *ReturnType, - Selector Sel, - // optional arguments. The number of types/arguments is obtained - // from the Sel.getNumArgs(). - ObjcDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames, - AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, - bool isVariadic) { - llvm::SmallVector Params; - - for (unsigned i = 0; i < Sel.getNumArgs(); i++) { - // FIXME: arg->AttrList must be stored too! - QualType argType; - - if (ArgTypes[i]) - argType = QualType::getFromOpaquePtr(ArgTypes[i]); - else - argType = Context.getObjcIdType(); - ParmVarDecl* Param = new ParmVarDecl(SourceLocation(/*FIXME*/), ArgNames[i], - argType, VarDecl::None, 0); - Param->setObjcDeclQualifier( - CvtQTToAstBitMask(ArgQT[i].getObjcDeclQualifier())); - Params.push_back(Param); - } - QualType resultDeclType; - - if (ReturnType) - resultDeclType = QualType::getFromOpaquePtr(ReturnType); - else // get the type for "id". - resultDeclType = Context.getObjcIdType(); - - Decl *CDecl = static_cast(ClassDecl); - ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, EndLoc, Sel, - resultDeclType, - CDecl, - 0, -1, AttrList, - MethodType == tok::minus, isVariadic, - MethodDeclKind == tok::objc_optional ? - ObjcMethodDecl::Optional : - ObjcMethodDecl::Required); - ObjcMethod->setMethodParams(&Params[0], Sel.getNumArgs()); - ObjcMethod->setObjcDeclQualifier( - CvtQTToAstBitMask(ReturnQT.getObjcDeclQualifier())); - const ObjcMethodDecl *PrevMethod = 0; - - // For implementations (which can be very "coarse grain"), we add the - // method now. This allows the AST to implement lookup methods that work - // incrementally (without waiting until we parse the @end). It also allows - // us to flag multiple declaration errors as they occur. - if (ObjcImplementationDecl *ImpDecl = - dyn_cast(CDecl)) { - if (MethodType == tok::minus) { - PrevMethod = ImpDecl->lookupInstanceMethod(Sel); - ImpDecl->addInstanceMethod(ObjcMethod); - } else { - PrevMethod = ImpDecl->lookupClassMethod(Sel); - ImpDecl->addClassMethod(ObjcMethod); - } - } - else if (ObjcCategoryImplDecl *CatImpDecl = - dyn_cast(CDecl)) { - if (MethodType == tok::minus) { - PrevMethod = CatImpDecl->lookupInstanceMethod(Sel); - CatImpDecl->addInstanceMethod(ObjcMethod); - } else { - PrevMethod = CatImpDecl->lookupClassMethod(Sel); - CatImpDecl->addClassMethod(ObjcMethod); - } - } - if (PrevMethod) { - // You can never have two method definitions with the same name. - Diag(ObjcMethod->getLocation(), diag::error_duplicate_method_decl, - ObjcMethod->getSelector().getName()); - Diag(PrevMethod->getLocation(), diag::err_previous_declaration); - } - return ObjcMethod; -} - -Sema::DeclTy *Sema::ActOnAddObjcProperties(SourceLocation AtLoc, - DeclTy **allProperties, unsigned NumProperties, ObjcDeclSpec &DS) { - ObjcPropertyDecl *PDecl = new ObjcPropertyDecl(AtLoc); - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_readonly) - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_readonly); - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_getter) { - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_getter); - PDecl->setGetterName(DS.getGetterName()); - } - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_setter) { - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_setter); - PDecl->setSetterName(DS.getSetterName()); - } - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_assign) - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_assign); - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_readwrite) - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_readwrite); - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_retain) - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_retain); - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_copy) - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_copy); - - if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_nonatomic) - PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_nonatomic); - - PDecl->setNumPropertyDecls(NumProperties); - if (NumProperties != 0) { - ObjcIvarDecl **properties = new ObjcIvarDecl*[NumProperties]; - memcpy(properties, allProperties, NumProperties*sizeof(ObjcIvarDecl*)); - PDecl->setPropertyDecls(properties); - } - return PDecl; -} - Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, DeclTy *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, diff --git a/Sema/SemaDeclObjC.cpp b/Sema/SemaDeclObjC.cpp new file mode 100644 index 0000000000..5b5b36d06d --- /dev/null +++ b/Sema/SemaDeclObjC.cpp @@ -0,0 +1,914 @@ +//===--- SemaDeclObjC.cpp - Semantic Analysis for ObjC Declarations -------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Chris Lattner and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for Objective C declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Parse/Scope.h" + +using namespace clang; + +/// ObjcActOnStartOfMethodDef - This routine sets up parameters; invisible +/// and user declared, in the method definition's AST. +void Sema::ObjcActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { + assert(CurFunctionDecl == 0 && "Method parsing confused"); + ObjcMethodDecl *MDecl = dyn_cast(static_cast(D)); + assert(MDecl != 0 && "Not a method declarator!"); + + // Allow all of Sema to see that we are entering a method definition. + CurMethodDecl = MDecl; + + // Create Decl objects for each parameter, entrring them in the scope for + // binding to their use. + struct DeclaratorChunk::ParamInfo PI; + + // Insert the invisible arguments, self and _cmd! + PI.Ident = &Context.Idents.get("self"); + PI.IdentLoc = SourceLocation(); // synthesized vars have a null location. + PI.InvalidType = false; + if (MDecl->isInstance()) { + QualType selfTy = Context.getObjcInterfaceType(MDecl->getClassInterface()); + selfTy = Context.getPointerType(selfTy); + PI.TypeInfo = selfTy.getAsOpaquePtr(); + } else + PI.TypeInfo = Context.getObjcIdType().getAsOpaquePtr(); + CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope)); + + PI.Ident = &Context.Idents.get("_cmd"); + PI.TypeInfo = Context.getObjcSelType().getAsOpaquePtr(); + ActOnParamDeclarator(PI, FnBodyScope); + + for (int i = 0; i < MDecl->getNumParams(); i++) { + ParmVarDecl *PDecl = MDecl->getParamDecl(i); + PI.Ident = PDecl->getIdentifier(); + PI.IdentLoc = PDecl->getLocation(); // user vars have a real location. + PI.TypeInfo = PDecl->getType().getAsOpaquePtr(); + ActOnParamDeclarator(PI, FnBodyScope); + } +} + +Sema::DeclTy *Sema::ActOnStartClassInterface( + SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + IdentifierInfo **ProtocolNames, unsigned NumProtocols, + SourceLocation EndProtoLoc, AttributeList *AttrList) { + assert(ClassName && "Missing class identifier"); + + // Check for another declaration kind with the same name. + ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); + if (PrevDecl && !isa(PrevDecl)) { + Diag(ClassLoc, diag::err_redefinition_different_kind, + ClassName->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + + ObjcInterfaceDecl* IDecl = dyn_cast_or_null(PrevDecl); + if (IDecl) { + // Class already seen. Is it a forward declaration? + if (!IDecl->isForwardDecl()) + Diag(AtInterfaceLoc, diag::err_duplicate_class_def, IDecl->getName()); + else { + IDecl->setLocation(AtInterfaceLoc); + IDecl->setForwardDecl(false); + IDecl->AllocIntfRefProtocols(NumProtocols); + } + } + else { + IDecl = new ObjcInterfaceDecl(AtInterfaceLoc, NumProtocols, ClassName); + + // Chain & install the interface decl into the identifier. + IDecl->setNext(ClassName->getFETokenInfo()); + ClassName->setFETokenInfo(IDecl); + + // Remember that this needs to be removed when the scope is popped. + TUScope->AddDecl(IDecl); + } + + if (SuperName) { + ObjcInterfaceDecl* SuperClassEntry = 0; + // Check if a different kind of symbol declared in this scope. + PrevDecl = LookupInterfaceDecl(SuperName); + if (PrevDecl && !isa(PrevDecl)) { + Diag(SuperLoc, diag::err_redefinition_different_kind, + SuperName->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + else { + // Check that super class is previously defined + SuperClassEntry = dyn_cast_or_null(PrevDecl); + + if (!SuperClassEntry || SuperClassEntry->isForwardDecl()) { + Diag(AtInterfaceLoc, diag::err_undef_superclass, + SuperClassEntry ? SuperClassEntry->getName() + : SuperName->getName(), + ClassName->getName()); + } + } + IDecl->setSuperClass(SuperClassEntry); + IDecl->setLocEnd(SuperLoc); + } else { // we have a root class. + IDecl->setLocEnd(ClassLoc); + } + + /// Check then save referenced protocols + if (NumProtocols) { + for (unsigned int i = 0; i != NumProtocols; i++) { + ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtocolNames[i]]; + if (!RefPDecl || RefPDecl->isForwardDecl()) + Diag(ClassLoc, diag::warn_undef_protocolref, + ProtocolNames[i]->getName(), + ClassName->getName()); + IDecl->setIntfRefProtocols((int)i, RefPDecl); + } + IDecl->setLocEnd(EndProtoLoc); + } + return IDecl; +} + +/// ActOnCompatiblityAlias - this action is called after complete parsing of +/// @compaatibility_alias declaration. It sets up the alias relationships. +Sema::DeclTy *Sema::ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation) { + // Look for previous declaration of alias name + ScopedDecl *ADecl = LookupScopedDecl(AliasName, Decl::IDNS_Ordinary, + AliasLocation, TUScope); + if (ADecl) { + if (isa(ADecl)) { + Diag(AliasLocation, diag::warn_previous_alias_decl); + Diag(ADecl->getLocation(), diag::warn_previous_declaration); + } + else { + Diag(AliasLocation, diag::err_conflicting_aliasing_type, + AliasName->getName()); + Diag(ADecl->getLocation(), diag::err_previous_declaration); + } + return 0; + } + // Check for class declaration + ScopedDecl *CDecl = LookupScopedDecl(ClassName, Decl::IDNS_Ordinary, + ClassLocation, TUScope); + if (!CDecl || !isa(CDecl)) { + Diag(ClassLocation, diag::warn_undef_interface, + ClassName->getName()); + if (CDecl) + Diag(CDecl->getLocation(), diag::warn_previous_declaration); + return 0; + } + // Everything checked out, instantiate a new alias declaration ast + ObjcCompatibleAliasDecl *AliasDecl = + new ObjcCompatibleAliasDecl(AtCompatibilityAliasLoc, + AliasName, + dyn_cast(CDecl)); + + // Chain & install the interface decl into the identifier. + AliasDecl->setNext(AliasName->getFETokenInfo()); + AliasName->setFETokenInfo(AliasDecl); + return AliasDecl; +} + +Sema::DeclTy *Sema::ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, + IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, + IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, + SourceLocation EndProtoLoc) { + assert(ProtocolName && "Missing protocol identifier"); + ObjcProtocolDecl *PDecl = ObjcProtocols[ProtocolName]; + if (PDecl) { + // Protocol already seen. Better be a forward protocol declaration + if (!PDecl->isForwardDecl()) + Diag(ProtocolLoc, diag::err_duplicate_protocol_def, + ProtocolName->getName()); + else { + PDecl->setForwardDecl(false); + PDecl->AllocReferencedProtocols(NumProtoRefs); + } + } + else { + PDecl = new ObjcProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs, + ProtocolName); + ObjcProtocols[ProtocolName] = PDecl; + } + + if (NumProtoRefs) { + /// Check then save referenced protocols + for (unsigned int i = 0; i != NumProtoRefs; i++) { + ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtoRefNames[i]]; + if (!RefPDecl || RefPDecl->isForwardDecl()) + Diag(ProtocolLoc, diag::warn_undef_protocolref, + ProtoRefNames[i]->getName(), + ProtocolName->getName()); + PDecl->setReferencedProtocols((int)i, RefPDecl); + } + PDecl->setLocEnd(EndProtoLoc); + } + return PDecl; +} + +/// FindProtocolDeclaration - This routine looks up protocols and +/// issuer error if they are not declared. It returns list of protocol +/// declarations in its 'Protocols' argument. +void +Sema::FindProtocolDeclaration(SourceLocation TypeLoc, + IdentifierInfo **ProtocolId, + unsigned NumProtocols, + llvm::SmallVector &Protocols) { + for (unsigned i = 0; i != NumProtocols; ++i) { + ObjcProtocolDecl *PDecl = ObjcProtocols[ProtocolId[i]]; + if (!PDecl) + Diag(TypeLoc, diag::err_undeclared_protocol, + ProtocolId[i]->getName()); + else + Protocols.push_back(PDecl); + } +} + +/// ActOnForwardProtocolDeclaration - +Action::DeclTy * +Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, + IdentifierInfo **IdentList, unsigned NumElts) { + llvm::SmallVector Protocols; + + for (unsigned i = 0; i != NumElts; ++i) { + IdentifierInfo *P = IdentList[i]; + ObjcProtocolDecl *PDecl = ObjcProtocols[P]; + if (!PDecl) { // Not already seen? + // FIXME: Pass in the location of the identifier! + PDecl = new ObjcProtocolDecl(AtProtocolLoc, 0, P, true); + ObjcProtocols[P] = PDecl; + } + + Protocols.push_back(PDecl); + } + return new ObjcForwardProtocolDecl(AtProtocolLoc, + &Protocols[0], Protocols.size()); +} + +Sema::DeclTy *Sema::ActOnStartCategoryInterface( + SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, + SourceLocation EndProtoLoc) { + ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) { + Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); + return 0; + } + ObjcCategoryDecl *CDecl = new ObjcCategoryDecl(AtInterfaceLoc, NumProtoRefs, + CategoryName); + CDecl->setClassInterface(IDecl); + /// Check for duplicate interface declaration for this category + ObjcCategoryDecl *CDeclChain; + for (CDeclChain = IDecl->getCategoryList(); CDeclChain; + CDeclChain = CDeclChain->getNextClassCategory()) { + if (CDeclChain->getIdentifier() == CategoryName) { + Diag(CategoryLoc, diag::err_dup_category_def, ClassName->getName(), + CategoryName->getName()); + break; + } + } + if (!CDeclChain) + CDecl->insertNextClassCategory(); + + if (NumProtoRefs) { + /// Check then save referenced protocols + for (unsigned int i = 0; i != NumProtoRefs; i++) { + ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtoRefNames[i]]; + if (!RefPDecl || RefPDecl->isForwardDecl()) { + Diag(CategoryLoc, diag::warn_undef_protocolref, + ProtoRefNames[i]->getName(), + CategoryName->getName()); + } + CDecl->setCatReferencedProtocols((int)i, RefPDecl); + } + CDecl->setLocEnd(EndProtoLoc); + } + return CDecl; +} + +/// ActOnStartCategoryImplementation - Perform semantic checks on the +/// category implementation declaration and build an ObjcCategoryImplDecl +/// object. +Sema::DeclTy *Sema::ActOnStartCategoryImplementation( + SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *CatName, SourceLocation CatLoc) { + ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjcCategoryImplDecl *CDecl = new ObjcCategoryImplDecl(AtCatImplLoc, + CatName, IDecl); + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) + 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::ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc) { + ObjcInterfaceDecl* IDecl = 0; + // Check for another declaration kind with the same name. + ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); + if (PrevDecl && !isa(PrevDecl)) { + Diag(ClassLoc, diag::err_redefinition_different_kind, + ClassName->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + else { + // Is there an interface declaration of this class; if not, warn! + IDecl = dyn_cast_or_null(PrevDecl); + if (!IDecl) + Diag(ClassLoc, diag::warn_undef_interface, ClassName->getName()); + } + + // Check that super class name is valid class name + ObjcInterfaceDecl* SDecl = 0; + if (SuperClassname) { + // Check if a different kind of symbol declared in this scope. + PrevDecl = LookupInterfaceDecl(SuperClassname); + if (PrevDecl && !isa(PrevDecl)) { + Diag(SuperClassLoc, diag::err_redefinition_different_kind, + SuperClassname->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + else { + SDecl = dyn_cast_or_null(PrevDecl); + if (!SDecl) + Diag(SuperClassLoc, diag::err_undef_superclass, + SuperClassname->getName(), ClassName->getName()); + else if (IDecl && IDecl->getSuperClass() != SDecl) { + // This implementation and its interface do not have the same + // super class. + Diag(SuperClassLoc, diag::err_conflicting_super_class, + SDecl->getName()); + Diag(SDecl->getLocation(), diag::err_previous_definition); + } + } + } + + if (!IDecl) { + // Legacy case of @implementation with no corresponding @interface. + // Build, chain & install the interface decl into the identifier. + IDecl = new ObjcInterfaceDecl(AtClassImplLoc, 0, ClassName, + false, true); + IDecl->setNext(ClassName->getFETokenInfo()); + ClassName->setFETokenInfo(IDecl); + IDecl->setSuperClass(SDecl); + IDecl->setLocEnd(ClassLoc); + + // Remember that this needs to be removed when the scope is popped. + TUScope->AddDecl(IDecl); + } + + ObjcImplementationDecl* IMPDecl = + new ObjcImplementationDecl(AtClassImplLoc, ClassName, IDecl, SDecl); + + // Check that there is no duplicate implementation of this class. + if (ObjcImplementations[ClassName]) + Diag(ClassLoc, diag::err_dup_implementation_class, ClassName->getName()); + else // add it to the list. + ObjcImplementations[ClassName] = IMPDecl; + return IMPDecl; +} + +void Sema::CheckImplementationIvars(ObjcImplementationDecl *ImpDecl, + ObjcIvarDecl **ivars, unsigned numIvars, + SourceLocation RBrace) { + assert(ImpDecl && "missing implementation decl"); + ObjcInterfaceDecl* IDecl = getObjCInterfaceDecl(ImpDecl->getIdentifier()); + if (!IDecl) + return; + /// Check case of non-existing @interface decl. + /// (legacy objective-c @implementation decl without an @interface decl). + /// Add implementations's ivar to the synthesize class's ivar list. + if (IDecl->ImplicitInterfaceDecl()) { + IDecl->addInstanceVariablesToClass(ivars, numIvars, RBrace); + return; + } + // If implementation has empty ivar list, just return. + if (numIvars == 0) + return; + + assert(ivars && "missing @implementation ivars"); + + // Check interface's Ivar list against those in the implementation. + // names and types must match. + // + ObjcIvarDecl** IntfIvars = IDecl->getInstanceVariables(); + int IntfNumIvars = IDecl->getNumInstanceVariables(); + 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); + +} + +/// CheckProtocolMethodDefs - This routine checks unimpletented methods +/// Declared in protocol, and those referenced by it. +void Sema::CheckProtocolMethodDefs(ObjcProtocolDecl *PDecl, + bool& IncompleteImpl, + const llvm::DenseSet &InsMap, + const llvm::DenseSet &ClsMap) { + // check unimplemented instance methods. + ObjcMethodDecl** methods = PDecl->getInstanceMethods(); + for (int j = 0; j < PDecl->getNumInstanceMethods(); j++) { + if (!InsMap.count(methods[j]->getSelector()) && + methods[j]->getImplementationControl() != ObjcMethodDecl::Optional) { + Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector().getName()); + IncompleteImpl = true; + } + } + // check unimplemented class methods + methods = PDecl->getClassMethods(); + for (int j = 0; j < PDecl->getNumClassMethods(); j++) + if (!ClsMap.count(methods[j]->getSelector()) && + methods[j]->getImplementationControl() != ObjcMethodDecl::Optional) { + Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector().getName()); + IncompleteImpl = true; + } + + // Check on this protocols's referenced protocols, recursively + ObjcProtocolDecl** RefPDecl = PDecl->getReferencedProtocols(); + for (int i = 0; i < PDecl->getNumReferencedProtocols(); i++) + CheckProtocolMethodDefs(RefPDecl[i], IncompleteImpl, InsMap, ClsMap); +} + +void Sema::ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl, + ObjcInterfaceDecl* IDecl) { + llvm::DenseSet InsMap; + // Check and see if instance methods in class interface have been + // implemented in the implementation class. + ObjcMethodDecl *const*methods = IMPDecl->getInstanceMethods(); + for (int i=0; i < IMPDecl->getNumInstanceMethods(); i++) + InsMap.insert(methods[i]->getSelector()); + + bool IncompleteImpl = false; + methods = IDecl->getInstanceMethods(); + for (int j = 0; j < IDecl->getNumInstanceMethods(); j++) + if (!InsMap.count(methods[j]->getSelector())) { + Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector().getName()); + IncompleteImpl = true; + } + llvm::DenseSet ClsMap; + // Check and see if class methods in class interface have been + // implemented in the implementation class. + methods = IMPDecl->getClassMethods(); + for (int i=0; i < IMPDecl->getNumClassMethods(); i++) + ClsMap.insert(methods[i]->getSelector()); + + methods = IDecl->getClassMethods(); + for (int j = 0; j < IDecl->getNumClassMethods(); j++) + if (!ClsMap.count(methods[j]->getSelector())) { + Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector().getName()); + IncompleteImpl = true; + } + + // Check the protocol list for unimplemented methods in the @implementation + // class. + ObjcProtocolDecl** protocols = IDecl->getReferencedProtocols(); + for (int i = 0; i < IDecl->getNumIntfRefProtocols(); i++) + CheckProtocolMethodDefs(protocols[i], IncompleteImpl, InsMap, ClsMap); + + if (IncompleteImpl) + Diag(IMPDecl->getLocation(), diag::warn_incomplete_impl_class, + IMPDecl->getName()); +} + +/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the +/// category interface is implemented in the category @implementation. +void Sema::ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl, + ObjcCategoryDecl *CatClassDecl) { + llvm::DenseSet InsMap; + // Check and see if instance methods in category interface have been + // implemented in its implementation class. + ObjcMethodDecl *const*methods = CatImplDecl->getInstanceMethods(); + for (int i=0; i < CatImplDecl->getNumInstanceMethods(); i++) + InsMap.insert(methods[i]->getSelector()); + + bool IncompleteImpl = false; + methods = CatClassDecl->getInstanceMethods(); + for (int j = 0; j < CatClassDecl->getNumInstanceMethods(); j++) + if (!InsMap.count(methods[j]->getSelector())) { + Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector().getName()); + IncompleteImpl = true; + } + llvm::DenseSet ClsMap; + // Check and see if class methods in category interface have been + // implemented in its implementation class. + methods = CatImplDecl->getClassMethods(); + for (int i=0; i < CatImplDecl->getNumClassMethods(); i++) + ClsMap.insert(methods[i]->getSelector()); + + methods = CatClassDecl->getClassMethods(); + for (int j = 0; j < CatClassDecl->getNumClassMethods(); j++) + if (!ClsMap.count(methods[j]->getSelector())) { + Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector().getName()); + IncompleteImpl = true; + } + + // Check the protocol list for unimplemented methods in the @implementation + // class. + ObjcProtocolDecl** protocols = CatClassDecl->getReferencedProtocols(); + for (int i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) { + ObjcProtocolDecl* PDecl = protocols[i]; + CheckProtocolMethodDefs(PDecl, IncompleteImpl, InsMap, ClsMap); + } + if (IncompleteImpl) + Diag(CatImplDecl->getLocation(), diag::warn_incomplete_impl_category, + CatClassDecl->getName()); +} + +/// ActOnForwardClassDeclaration - +Action::DeclTy * +Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, + IdentifierInfo **IdentList, unsigned NumElts) +{ + llvm::SmallVector Interfaces; + + for (unsigned i = 0; i != NumElts; ++i) { + // Check for another declaration kind with the same name. + ScopedDecl *PrevDecl = LookupInterfaceDecl(IdentList[i]); + if (PrevDecl && !isa(PrevDecl)) { + Diag(AtClassLoc, diag::err_redefinition_different_kind, + IdentList[i]->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + ObjcInterfaceDecl *IDecl = dyn_cast_or_null(PrevDecl); + if (!IDecl) { // Not already seen? Make a forward decl. + IDecl = new ObjcInterfaceDecl(AtClassLoc, 0, IdentList[i], true); + // Chain & install the interface decl into the identifier. + IDecl->setNext(IdentList[i]->getFETokenInfo()); + IdentList[i]->setFETokenInfo(IDecl); + + // Remember that this needs to be removed when the scope is popped. + TUScope->AddDecl(IDecl); + } + + Interfaces.push_back(IDecl); + } + + return new ObjcClassDecl(AtClassLoc, &Interfaces[0], Interfaces.size()); +} + + +/// MatchTwoMethodDeclarations - Checks that two methods have matching type and +/// returns true, or false, accordingly. +/// TODO: Handle protocol list; such as id in type comparisons +bool Sema::MatchTwoMethodDeclarations(const ObjcMethodDecl *Method, + const ObjcMethodDecl *PrevMethod) { + if (Method->getResultType().getCanonicalType() != + PrevMethod->getResultType().getCanonicalType()) + return false; + for (int i = 0; i < Method->getNumParams(); i++) { + ParmVarDecl *ParamDecl = Method->getParamDecl(i); + ParmVarDecl *PrevParamDecl = PrevMethod->getParamDecl(i); + if (ParamDecl->getCanonicalType() != PrevParamDecl->getCanonicalType()) + return false; + } + return true; +} + +void Sema::AddInstanceMethodToGlobalPool(ObjcMethodDecl *Method) { + ObjcMethodList &FirstMethod = InstanceMethodPool[Method->getSelector()]; + if (!FirstMethod.Method) { + // Haven't seen a method with this selector name yet - add it. + FirstMethod.Method = Method; + FirstMethod.Next = 0; + } else { + // We've seen a method with this name, now check the type signature(s). + bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); + + for (ObjcMethodList *Next = FirstMethod.Next; !match && Next; + Next = Next->Next) + match = MatchTwoMethodDeclarations(Method, Next->Method); + + if (!match) { + // We have a new signature for an existing method - add it. + // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". + struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next); + FirstMethod.Next = OMI; + } + } +} + +void Sema::AddFactoryMethodToGlobalPool(ObjcMethodDecl *Method) { + ObjcMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()]; + if (!FirstMethod.Method) { + // Haven't seen a method with this selector name yet - add it. + FirstMethod.Method = Method; + FirstMethod.Next = 0; + } else { + // We've seen a method with this name, now check the type signature(s). + bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); + + for (ObjcMethodList *Next = FirstMethod.Next; !match && Next; + Next = Next->Next) + match = MatchTwoMethodDeclarations(Method, Next->Method); + + if (!match) { + // We have a new signature for an existing method - add it. + // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". + struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next); + FirstMethod.Next = OMI; + } + } +} + +void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, + DeclTy **allMethods, unsigned allNum, + DeclTy **allProperties, unsigned pNum) { + Decl *ClassDecl = static_cast(classDecl); + + // FIXME: If we don't have a ClassDecl, we have an error. I (snaroff) would + // prefer we always pass in a decl. If the decl has an error, isInvalidDecl() + // should be true. + if (!ClassDecl) + return; + + llvm::SmallVector insMethods; + llvm::SmallVector clsMethods; + + llvm::DenseMap InsMap; + llvm::DenseMap ClsMap; + + bool isInterfaceDeclKind = + (isa(ClassDecl) || isa(ClassDecl) + || isa(ClassDecl)); + bool checkIdenticalMethods = isa(ClassDecl); + + // TODO: property declaration in category and protocols. + if (pNum != 0 && isa(ClassDecl)) { + ObjcPropertyDecl **properties = new ObjcPropertyDecl*[pNum]; + memcpy(properties, allProperties, pNum*sizeof(ObjcPropertyDecl*)); + dyn_cast(ClassDecl)->setPropertyDecls(properties); + dyn_cast(ClassDecl)->setNumPropertyDecl(pNum); + } + + for (unsigned i = 0; i < allNum; i++ ) { + ObjcMethodDecl *Method = + cast_or_null(static_cast(allMethods[i])); + + if (!Method) continue; // Already issued a diagnostic. + if (Method->isInstance()) { + /// Check for instance method of the same name with incompatible types + const ObjcMethodDecl *&PrevMethod = InsMap[Method->getSelector()]; + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + : false; + if (isInterfaceDeclKind && PrevMethod && !match + || checkIdenticalMethods && match) { + Diag(Method->getLocation(), diag::error_duplicate_method_decl, + Method->getSelector().getName()); + Diag(PrevMethod->getLocation(), diag::err_previous_declaration); + } else { + insMethods.push_back(Method); + InsMap[Method->getSelector()] = Method; + /// The following allows us to typecheck messages to "id". + AddInstanceMethodToGlobalPool(Method); + } + } + else { + /// Check for class method of the same name with incompatible types + const ObjcMethodDecl *&PrevMethod = ClsMap[Method->getSelector()]; + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + : false; + if (isInterfaceDeclKind && PrevMethod && !match + || checkIdenticalMethods && match) { + Diag(Method->getLocation(), diag::error_duplicate_method_decl, + Method->getSelector().getName()); + Diag(PrevMethod->getLocation(), diag::err_previous_declaration); + } else { + clsMethods.push_back(Method); + ClsMap[Method->getSelector()] = Method; + /// The following allows us to typecheck messages to "id". + AddInstanceMethodToGlobalPool(Method); + } + } + } + + if (ObjcInterfaceDecl *I = dyn_cast(ClassDecl)) { + I->addMethods(&insMethods[0], insMethods.size(), + &clsMethods[0], clsMethods.size(), AtEndLoc); + } else if (ObjcProtocolDecl *P = dyn_cast(ClassDecl)) { + P->addMethods(&insMethods[0], insMethods.size(), + &clsMethods[0], clsMethods.size(), AtEndLoc); + } + else if (ObjcCategoryDecl *C = dyn_cast(ClassDecl)) { + C->addMethods(&insMethods[0], insMethods.size(), + &clsMethods[0], clsMethods.size(), AtEndLoc); + } + else if (ObjcImplementationDecl *IC = + dyn_cast(ClassDecl)) { + IC->setLocEnd(AtEndLoc); + if (ObjcInterfaceDecl* IDecl = getObjCInterfaceDecl(IC->getIdentifier())) + ImplMethodsVsClassMethods(IC, IDecl); + } else { + ObjcCategoryImplDecl* CatImplClass = cast(ClassDecl); + CatImplClass->setLocEnd(AtEndLoc); + 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->getCategoryList(); + Categories; Categories = Categories->getNextClassCategory()) { + if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { + ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories); + break; + } + } + } + } +} + + +/// CvtQTToAstBitMask - utility routine to produce an AST bitmask for +/// objective-c's type qualifier from the parser version of the same info. +static Decl::ObjcDeclQualifier +CvtQTToAstBitMask(ObjcDeclSpec::ObjcDeclQualifier PQTVal) { + Decl::ObjcDeclQualifier ret = Decl::OBJC_TQ_None; + if (PQTVal & ObjcDeclSpec::DQ_In) + ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_In); + if (PQTVal & ObjcDeclSpec::DQ_Inout) + ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Inout); + if (PQTVal & ObjcDeclSpec::DQ_Out) + ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Out); + if (PQTVal & ObjcDeclSpec::DQ_Bycopy) + ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy); + if (PQTVal & ObjcDeclSpec::DQ_Byref) + ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Byref); + if (PQTVal & ObjcDeclSpec::DQ_Oneway) + ret = (Decl::ObjcDeclQualifier)(ret | Decl::OBJC_TQ_Oneway); + + return ret; +} + +Sema::DeclTy *Sema::ActOnMethodDeclaration( + SourceLocation MethodLoc, SourceLocation EndLoc, + tok::TokenKind MethodType, DeclTy *ClassDecl, + ObjcDeclSpec &ReturnQT, TypeTy *ReturnType, + Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjcDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames, + AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, + bool isVariadic) { + llvm::SmallVector Params; + + for (unsigned i = 0; i < Sel.getNumArgs(); i++) { + // FIXME: arg->AttrList must be stored too! + QualType argType; + + if (ArgTypes[i]) + argType = QualType::getFromOpaquePtr(ArgTypes[i]); + else + argType = Context.getObjcIdType(); + ParmVarDecl* Param = new ParmVarDecl(SourceLocation(/*FIXME*/), ArgNames[i], + argType, VarDecl::None, 0); + Param->setObjcDeclQualifier( + CvtQTToAstBitMask(ArgQT[i].getObjcDeclQualifier())); + Params.push_back(Param); + } + QualType resultDeclType; + + if (ReturnType) + resultDeclType = QualType::getFromOpaquePtr(ReturnType); + else // get the type for "id". + resultDeclType = Context.getObjcIdType(); + + Decl *CDecl = static_cast(ClassDecl); + ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, EndLoc, Sel, + resultDeclType, + CDecl, + 0, -1, AttrList, + MethodType == tok::minus, isVariadic, + MethodDeclKind == tok::objc_optional ? + ObjcMethodDecl::Optional : + ObjcMethodDecl::Required); + ObjcMethod->setMethodParams(&Params[0], Sel.getNumArgs()); + ObjcMethod->setObjcDeclQualifier( + CvtQTToAstBitMask(ReturnQT.getObjcDeclQualifier())); + const ObjcMethodDecl *PrevMethod = 0; + + // For implementations (which can be very "coarse grain"), we add the + // method now. This allows the AST to implement lookup methods that work + // incrementally (without waiting until we parse the @end). It also allows + // us to flag multiple declaration errors as they occur. + if (ObjcImplementationDecl *ImpDecl = + dyn_cast(CDecl)) { + if (MethodType == tok::minus) { + PrevMethod = ImpDecl->lookupInstanceMethod(Sel); + ImpDecl->addInstanceMethod(ObjcMethod); + } else { + PrevMethod = ImpDecl->lookupClassMethod(Sel); + ImpDecl->addClassMethod(ObjcMethod); + } + } + else if (ObjcCategoryImplDecl *CatImpDecl = + dyn_cast(CDecl)) { + if (MethodType == tok::minus) { + PrevMethod = CatImpDecl->lookupInstanceMethod(Sel); + CatImpDecl->addInstanceMethod(ObjcMethod); + } else { + PrevMethod = CatImpDecl->lookupClassMethod(Sel); + CatImpDecl->addClassMethod(ObjcMethod); + } + } + if (PrevMethod) { + // You can never have two method definitions with the same name. + Diag(ObjcMethod->getLocation(), diag::error_duplicate_method_decl, + ObjcMethod->getSelector().getName()); + Diag(PrevMethod->getLocation(), diag::err_previous_declaration); + } + return ObjcMethod; +} + +Sema::DeclTy *Sema::ActOnAddObjcProperties(SourceLocation AtLoc, + DeclTy **allProperties, unsigned NumProperties, ObjcDeclSpec &DS) { + ObjcPropertyDecl *PDecl = new ObjcPropertyDecl(AtLoc); + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_readonly) + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_readonly); + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_getter) { + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_getter); + PDecl->setGetterName(DS.getGetterName()); + } + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_setter) { + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_setter); + PDecl->setSetterName(DS.getSetterName()); + } + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_assign) + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_assign); + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_readwrite) + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_readwrite); + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_retain) + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_retain); + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_copy) + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_copy); + + if(DS.getPropertyAttributes() & ObjcDeclSpec::DQ_PR_nonatomic) + PDecl->setPropertyAttributes(ObjcPropertyDecl::OBJC_PR_nonatomic); + + PDecl->setNumPropertyDecls(NumProperties); + if (NumProperties != 0) { + ObjcIvarDecl **properties = new ObjcIvarDecl*[NumProperties]; + memcpy(properties, allProperties, NumProperties*sizeof(ObjcIvarDecl*)); + PDecl->setPropertyDecls(properties); + } + return PDecl; +} + diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index ed2ec876d3..0b2d9fabb0 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -82,6 +82,7 @@ DE67E7280C02109800F66BC5 /* ASTStreamer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE67E7270C02109800F66BC5 /* ASTStreamer.h */; }; DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE6951C60C4D1F5D00A5826B /* RecordLayout.h */; }; DE6954640C5121BD00A5826B /* Token.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE6954630C5121BD00A5826B /* Token.h */; }; + DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */; }; DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE75ED280B044DC90020CF81 /* ASTContext.h */; }; DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE75EDF00B06880E0020CF81 /* Type.cpp */; }; DE928B130C05659200231DA4 /* ModuleBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B120C05659200231DA4 /* ModuleBuilder.cpp */; }; @@ -312,6 +313,7 @@ DE67E7270C02109800F66BC5 /* ASTStreamer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTStreamer.h; path = clang/Sema/ASTStreamer.h; sourceTree = ""; }; DE6951C60C4D1F5D00A5826B /* RecordLayout.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = RecordLayout.h; path = clang/AST/RecordLayout.h; sourceTree = ""; }; DE6954630C5121BD00A5826B /* Token.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Token.h; sourceTree = ""; }; + DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclObjC.cpp; path = Sema/SemaDeclObjC.cpp; sourceTree = ""; }; DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = ""; }; DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = AST/Type.cpp; sourceTree = ""; }; DE928B120C05659200231DA4 /* ModuleBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleBuilder.cpp; path = CodeGen/ModuleBuilder.cpp; sourceTree = ""; }; @@ -523,6 +525,7 @@ DE67E7160C020EE400F66BC5 /* Sema.cpp */, DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */, DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */, + DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */, DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */, DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */, DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */, @@ -867,6 +870,7 @@ 35839B0C0CDF845F006ED061 /* TypeSerialization.cpp in Sources */, 3580CC0C0D072E5C00C5E4F4 /* LangOptions.cpp in Sources */, 353612DA0D075174002E3541 /* TranslationUnit.cpp in Sources */, + DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };