From 4b6c9051c6522894978c9ba6a819a659d102db36 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 11 Oct 2007 00:55:41 +0000 Subject: [PATCH] Patch to create protocol conforming class types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42856 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/ASTContext.cpp | 25 +++++++++++++++++++++++ AST/Type.cpp | 25 +++++++++++++++++++++++ Parse/ParseDecl.cpp | 24 ++++++++++++---------- Parse/ParseObjc.cpp | 21 ++++++++++--------- Sema/Sema.h | 8 +++++--- Sema/SemaDecl.cpp | 18 +++++++++-------- Sema/SemaType.cpp | 11 ++++++++-- clang.xcodeproj/project.pbxproj | 1 + include/clang/AST/ASTContext.h | 7 +++++++ include/clang/AST/Type.h | 27 ++++++++++++++++++++++--- include/clang/Parse/Action.h | 15 +++++++------- include/clang/Parse/DeclSpec.h | 16 ++++++++++++++- include/clang/Parse/Parser.h | 4 ++-- test/Sema/class-conforming-protocol-1.m | 21 +++++++++++++++++++ 14 files changed, 176 insertions(+), 47 deletions(-) create mode 100644 test/Sema/class-conforming-protocol-1.m diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index 6608330b68..a6c2bc6680 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -610,6 +610,31 @@ QualType ASTContext::getObjcInterfaceType(ObjcInterfaceDecl *Decl) { return QualType(Decl->TypeForDecl, 0); } +/// getObjcQualifiedInterfaceType - Return a +/// ObjcQualifiedInterfaceType type for the given interface decl and +/// the conforming protocol list. +QualType ASTContext::getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl, + ObjcProtocolDecl **Protocols, unsigned NumProtocols) { + ObjcInterfaceType *IType = + cast(getObjcInterfaceType(Decl)); + + llvm::FoldingSetNodeID ID; + ObjcQualifiedInterfaceType::Profile(ID, IType, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjcQualifiedInterfaceType *QT = + ObjcQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + ObjcQualifiedInterfaceType *QType = new ObjcQualifiedInterfaceType(IType); + for (unsigned i = 0; i != NumProtocols; i++) + QType->setProtocols(Protocols[i]); + Types.push_back(QType); + ObjcQualifiedInterfaceTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + /// getTypeOfExpr - Unlike many "get" functions, we can't unique /// TypeOfExpr AST's (since expression's are never shared). For example, /// multiple declarations that refer to "typeof(x)" all contain different diff --git a/AST/Type.cpp b/AST/Type.cpp index de840cf970..7deee66070 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -618,6 +618,19 @@ void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic()); } +void ObjcQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, + ObjcInterfaceType *interfaceType, + ObjcProtocolDecl **protocols, + unsigned NumProtocols) { + ID.AddPointer(interfaceType); + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); +} + +void ObjcQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getInterfaceType(), &Protocols[0], getNumProtocols()); +} + /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to /// potentially looking through *all* consequtive typedefs. This returns the /// sum of the type qualifiers, so if you have: @@ -843,6 +856,18 @@ void ObjcInterfaceType::getAsStringInternal(std::string &InnerString) const { InnerString = getDecl()->getIdentifier()->getName() + InnerString; } +void ObjcQualifiedInterfaceType::getAsStringInternal( + std::string &InnerString) const { + InnerString = getInterfaceType()->getDecl()->getName() + '<'; + int num = getNumProtocols(); + for (int i = 0; i < num; i++) { + InnerString += getProtocols(i)->getName(); + if (i < num-1) + InnerString += ','; + } + InnerString += '>'; +} + void TagType::getAsStringInternal(std::string &InnerString) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; diff --git a/Parse/ParseDecl.cpp b/Parse/ParseDecl.cpp index 00e441412f..80ff5757e0 100644 --- a/Parse/ParseDecl.cpp +++ b/Parse/ParseDecl.cpp @@ -403,18 +403,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { TypeRep); if (isInvalid) break; - else { // FIXME: restrict this to "id" and ObjC classnames. - DS.Range.setEnd(Tok.getLocation()); - ConsumeToken(); // The identifier - if (Tok.is(tok::less)) { - llvm::SmallVector ProtocolRefs; - ParseObjCProtocolReferences(ProtocolRefs); - Actions.ActOnFindProtocolDeclaration(Loc, - &ProtocolRefs[0], - ProtocolRefs.size()); - } - continue; + // FIXME: restrict this to "id" and ObjC classnames. + DS.Range.setEnd(Tok.getLocation()); + ConsumeToken(); // The identifier + if (Tok.is(tok::less)) { + llvm::SmallVector ProtocolRefs; + ParseObjCProtocolReferences(ProtocolRefs); + llvm::SmallVector *ProtocolDecl = + new llvm::SmallVector; + DS.setProtocolQualifiers(ProtocolDecl); + Actions.FindProtocolDeclaration(Loc, + &ProtocolRefs[0], ProtocolRefs.size(), + *ProtocolDecl); } + continue; } } // FALL THROUGH. diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 464fad2e40..dad82eec52 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -378,9 +378,9 @@ Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl, assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); tok::TokenKind methodType = Tok.getKind(); - SourceLocation methodLoc = ConsumeToken(); + ConsumeToken(); - DeclTy *MDecl = ParseObjCMethodDecl(methodType, methodLoc, MethodImplKind); + DeclTy *MDecl = ParseObjCMethodDecl(methodType, MethodImplKind); // Since this rule is used for both method declarations and definitions, // the caller is (optionally) responsible for consuming the ';'. return MDecl; @@ -394,7 +394,7 @@ Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl, /// unsigned long const short volatile signed restrict _Complex /// in out inout bycopy byref oneway int char float double void _Bool /// -IdentifierInfo *Parser::ParseObjCSelector() { +IdentifierInfo *Parser::ParseObjCSelector(SourceLocation &SelectorLoc) { switch (Tok.getKind()) { default: return 0; @@ -438,7 +438,7 @@ IdentifierInfo *Parser::ParseObjCSelector() { case tok::kw__Bool: case tok::kw__Complex: IdentifierInfo *II = Tok.getIdentifierInfo(); - ConsumeToken(); + SelectorLoc = ConsumeToken(); return II; } } @@ -526,15 +526,14 @@ Parser::TypeTy *Parser::ParseObjCTypeName() { /// __attribute__((unused)) /// Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, - SourceLocation mLoc, tok::ObjCKeywordKind MethodImplKind) { // Parse the return type. TypeTy *ReturnType = 0; if (Tok.is(tok::l_paren)) ReturnType = ParseObjCTypeName(); - - IdentifierInfo *SelIdent = ParseObjCSelector(); + SourceLocation mLoc; + IdentifierInfo *SelIdent = ParseObjCSelector(mLoc); if (Tok.isNot(tok::colon)) { if (!SelIdent) { Diag(Tok, diag::err_expected_ident); // missing selector name. @@ -584,7 +583,8 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, ConsumeToken(); // Eat the identifier. // Check for another keyword selector. - SelIdent = ParseObjCSelector(); + SourceLocation Loc; + SelIdent = ParseObjCSelector(Loc); if (!SelIdent && Tok.isNot(tok::colon)) break; // We have a selector or a colon, continue parsing. @@ -1175,7 +1175,8 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { ReceiverExpr = Res.Val; } // Parse objc-selector - IdentifierInfo *selIdent = ParseObjCSelector(); + SourceLocation Loc; + IdentifierInfo *selIdent = ParseObjCSelector(Loc); llvm::SmallVector KeyIdents; llvm::SmallVector KeyExprs; @@ -1201,7 +1202,7 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { KeyExprs.push_back(Res.Val); // Check for another keyword selector. - selIdent = ParseObjCSelector(); + selIdent = ParseObjCSelector(Loc); if (!selIdent && Tok.isNot(tok::colon)) break; // We have a selector or a colon, continue parsing. diff --git a/Sema/Sema.h b/Sema/Sema.h index 0eb803e260..c2ac6a23a7 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -449,9 +449,11 @@ public: IdentifierInfo **IdentList, unsigned NumElts); - virtual DeclTy **ActOnFindProtocolDeclaration(SourceLocation TypeLoc, - IdentifierInfo **ProtocolId, - unsigned NumProtocols); + virtual void FindProtocolDeclaration(SourceLocation TypeLoc, + IdentifierInfo **ProtocolId, + unsigned NumProtocols, + llvm::SmallVector & + Protocols); virtual void ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *ClassDecl, DeclTy **allMethods, unsigned allNum); diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 051a4c192a..406a745c29 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -987,20 +987,22 @@ Sema::DeclTy *Sema::ActOnStartProtocolInterface( return PDecl; } -/// ActOnFindProtocolDeclaration - This routine looks for a previously -/// declared protocol and returns it. If not found, issues diagnostic. -/// Will build a list of previously protocol declarations found in the list. -Action::DeclTy ** -Sema::ActOnFindProtocolDeclaration(SourceLocation TypeLoc, - IdentifierInfo **ProtocolId, - unsigned NumProtocols) { +/// 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); } - return 0; } /// ActOnForwardProtocolDeclaration - diff --git a/Sema/SemaType.cpp b/Sema/SemaType.cpp index 180e440f04..abf132bf32 100644 --- a/Sema/SemaType.cpp +++ b/Sema/SemaType.cpp @@ -104,8 +104,15 @@ static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) { "Can't handle qualifiers on typedef names yet!"); // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so // we have this "hack" for now... - if (isa(D)) - return Ctx.getObjcInterfaceType(cast(D)); + if (ObjcInterfaceDecl *ObjcIntDecl = dyn_cast(D)) { + if (DS.getProtocolQualifiers() == 0) + return Ctx.getObjcInterfaceType(ObjcIntDecl); + + Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0]; + return Ctx.getObjcQualifiedInterfaceType(ObjcIntDecl, + reinterpret_cast(PPDecl), + DS.NumProtocolQualifiers()); + } // TypeQuals handled by caller. return Ctx.getTypedefType(cast(D)); } diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index b5cf88f72c..c7f4908c0d 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -739,6 +739,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/ASTContext.h b/include/clang/AST/ASTContext.h index 494b28f9b1..43e40015d9 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -38,6 +38,7 @@ class ASTContext { llvm::FoldingSet VectorTypes; llvm::FoldingSet FunctionTypeNoProtos; llvm::FoldingSet FunctionTypeProtos; + llvm::FoldingSet ObjcQualifiedInterfaceTypes; llvm::DenseMap RecordLayoutInfo; RecordDecl *CFConstantStringTypeDecl; public: @@ -118,6 +119,12 @@ public: /// specified typename decl. QualType getTypedefType(TypedefDecl *Decl); QualType getObjcInterfaceType(ObjcInterfaceDecl *Decl); + + /// getObjcQualifiedInterfaceType - Return a + /// ObjcQualifiedInterfaceType type for the given interface decl and + /// the conforming protocol list. + QualType getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl, + ObjcProtocolDecl **ProtocolList, unsigned NumProtocols); /// getTypeOfType - GCC extension. QualType getTypeOfExpr(Expr *e); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 33450b85f8..0af6b134f0 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -47,6 +47,7 @@ namespace clang { class FunctionType; class OCUVectorType; class BuiltinType; + class ObjcQualifiedInterfaceType; /// QualType - For efficiency, we don't store CVR-qualified types as nodes on /// their own: instead each reference to a type stores the qualifiers. This @@ -817,6 +818,7 @@ public: class ObjcInterfaceType : public Type { ObjcInterfaceDecl *Decl; + ObjcInterfaceType(ObjcInterfaceDecl *D) : Type(ObjcInterface, QualType()), Decl(D) { } friend class ASTContext; // ASTContext creates these. @@ -825,7 +827,7 @@ public: ObjcInterfaceDecl *getDecl() const { return Decl; } virtual void getAsStringInternal(std::string &InnerString) const; - + static bool classof(const Type *T) { return T->getTypeClass() == ObjcInterface; } @@ -836,7 +838,7 @@ public: /// conforming to a list of protocols; such as, INTF. /// Duplicate protocols are removed and protocol list is canonicalized to be in /// alphabetical order. -class ObjcQualifiedInterfaceType : public Type { +class ObjcQualifiedInterfaceType : public Type, public llvm::FoldingSetNode { // Interface type for this protocol conforming object type ObjcInterfaceType *InterfaceType; @@ -846,10 +848,29 @@ class ObjcQualifiedInterfaceType : public Type { ObjcQualifiedInterfaceType(ObjcInterfaceType *T) : Type(ObjcQualifiedInterface, QualType()), InterfaceType(T) { } + + void setProtocols(ObjcProtocolDecl *pType) { + Protocols.push_back(pType); + } + friend class ASTContext; // ASTContext creates these. public: ObjcInterfaceType *getInterfaceType() const { return InterfaceType; } - + + ObjcProtocolDecl *getProtocols(unsigned i) const { + return Protocols[i]; + } + unsigned getNumProtocols() const { + return Protocols.size(); + } + + virtual void getAsStringInternal(std::string &InnerString) const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + ObjcInterfaceType *interfaceType, + ObjcProtocolDecl **protocols, unsigned NumProtocols); + static bool classof(const Type *T) { return T->getTypeClass() == ObjcQualifiedInterface; } diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index b5142f0168..462192896b 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -552,13 +552,14 @@ public: return 0; } - /// ActOnFindProtocolDeclaration - This routine looks for a previously - /// declared protocol and returns it. If not found, issues diagnostic. - /// Will build a list of previously protocol declarations found in the list. - virtual DeclTy **ActOnFindProtocolDeclaration(SourceLocation TypeLoc, - IdentifierInfo **ProtocolId, - unsigned NumProtocols) { - return 0; + /// FindProtocolDeclaration - This routine looks up protocols and + /// issues error if they are not declared. It returns list of valid + /// protocols found. + virtual void FindProtocolDeclaration(SourceLocation TypeLoc, + IdentifierInfo **ProtocolId, + unsigned NumProtocols, + llvm::SmallVector & + Protocols) { } diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index c17469dd25..79a67741bd 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -124,6 +124,9 @@ private: // attributes. AttributeList *AttrList; + // List of protocol qualifiers for objective-c classes. + llvm::SmallVector *ProtocolQualifiers; + // SourceLocation info. These are null if the item wasn't specified or if // the setting was synthesized. SourceLocation StorageClassSpecLoc, SCS_threadLoc; @@ -142,10 +145,12 @@ public: TypeQualifiers(TSS_unspecified), FS_inline_specified(false), TypeRep(0), - AttrList(0) { + AttrList(0), + ProtocolQualifiers(0) { } ~DeclSpec() { delete AttrList; + delete ProtocolQualifiers; } // storage-class-specifier SCS getStorageClassSpec() const { return StorageClassSpec; } @@ -248,6 +253,15 @@ public: } AttributeList *getAttributes() const { return AttrList; } + llvm::SmallVector *getProtocolQualifiers() const { + return ProtocolQualifiers; + } + void setProtocolQualifiers(llvm::SmallVector *protos) { + ProtocolQualifiers = protos; + } + unsigned NumProtocolQualifiers() const { + return ProtocolQualifiers ? ProtocolQualifiers->size() : 0; + } /// Finish - This does final analysis of the declspec, issuing diagnostics for /// things like "_Imaginary" (lacking an FP type). After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 2a1f0f6196..5e4c5290e8 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -275,7 +275,7 @@ private: DeclTy *ParseObjCTryStmt(SourceLocation atLoc); DeclTy *ParseObjCThrowStmt(SourceLocation atLoc); - IdentifierInfo *ParseObjCSelector(); + IdentifierInfo *ParseObjCSelector(SourceLocation &MethodLocation); // Definitions for Objective-c context sensitive keywords recognition. enum ObjCTypeQual { objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref, @@ -295,7 +295,7 @@ private: void ParseObjCMethodRequirement(); DeclTy *ParseObjCMethodPrototype(DeclTy *classOrCat, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword); - DeclTy *ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc, + DeclTy *ParseObjCMethodDecl(tok::TokenKind mType, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword); void ParseObjCPropertyAttribute(DeclTy *interfaceDecl); void ParseObjCPropertyDecl(DeclTy *interfaceDecl); diff --git a/test/Sema/class-conforming-protocol-1.m b/test/Sema/class-conforming-protocol-1.m new file mode 100644 index 0000000000..6afee0d3d4 --- /dev/null +++ b/test/Sema/class-conforming-protocol-1.m @@ -0,0 +1,21 @@ +// RUN: clang -fsyntax-only -verify %s + +@protocol P1 @end +@protocol P2 @end +@protocol P3 @end + +@interface INTF +- (INTF*) METH1; // expected-error {{previous declaration is here}} +- (INTF*) METH1; // expected-error {{duplicate declaration of method 'METH1'}} + +- (INTF*) METH2; +- (INTF*) METH2; // expected-error {{previous declaration is here}} +- (INTF*) METH2; // expected-error {{duplicate declaration of method 'METH2'}} + +- (INTF*) METH3; +- (INTF*) METH3; + +@end + +INTF* p1; + -- 2.40.0