From: Argyrios Kyrtzidis Date: Mon, 9 Jun 2008 21:05:31 +0000 (+0000) Subject: Added new C++ AST Decl subclasses. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d3bb44f0f1a83cb208d3e61ee80afe6a4d20d2d8;p=clang Added new C++ AST Decl subclasses. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52155 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/AST.h b/include/clang/AST/AST.h index 07e923235e..96e887cfc0 100644 --- a/include/clang/AST/AST.h +++ b/include/clang/AST/AST.h @@ -17,6 +17,7 @@ // This header exports all AST interfaces. #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 1bfad2e391..c404e4ff99 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the Decl interface and subclasses. +// This file defines the Decl subclasses. // //===----------------------------------------------------------------------===// @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_DECL_H #include "clang/AST/DeclBase.h" +#include "clang/Parse/AccessSpecifier.h" namespace clang { class Expr; @@ -382,11 +383,6 @@ private: /// function. ScopedDecl *DeclChain; - // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum - unsigned SClass : 2; - bool IsInline : 1; - bool IsImplicit : 1; - /// PreviousDeclaration - A link to the previous declaration of this /// same function, NULL if this is the first declaration. For /// example, in the following code, the PreviousDeclaration can be @@ -398,13 +394,19 @@ private: /// int f(int x, int y) { return x + y; } FunctionDecl *PreviousDeclaration; - FunctionDecl(DeclContext *DC, SourceLocation L, + // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum + unsigned SClass : 2; + bool IsInline : 1; + bool IsImplicit : 1; + +protected: + FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S, bool isInline, ScopedDecl *PrevDecl) - : ValueDecl(Function, DC, L, Id, T, PrevDecl), - DeclContext(Function), - ParamInfo(0), Body(0), DeclChain(0), SClass(S), - IsInline(isInline), IsImplicit(0), PreviousDeclaration(0) {} + : ValueDecl(DK, DC, L, Id, T, PrevDecl), + DeclContext(DK), + ParamInfo(0), Body(0), DeclChain(0), PreviousDeclaration(0), + SClass(S), IsInline(isInline), IsImplicit(0) {} virtual ~FunctionDecl(); virtual void Destroy(ASTContext& C); @@ -498,7 +500,9 @@ public: bool isInline() const { return IsInline; } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == Function; } + static bool classof(const Decl *D) { + return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast; + } static bool classof(const FunctionDecl *D) { return true; } protected: @@ -608,6 +612,9 @@ protected: IdentifierInfo *Id, ScopedDecl *PrevDecl) : ScopedDecl(DK, DC, L, Id, PrevDecl), TypeForDecl(0) {} public: + void setAccess(AccessSpecifier AS) { Access = AS; } + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= TypeFirst && D->getKind() <= TypeLast; @@ -759,7 +766,8 @@ class RecordDecl : public TagDecl { /// Members/NumMembers - This is a new[]'d array of pointers to Decls. FieldDecl **Members; // Null if not defined. int NumMembers; // -1 if not defined. - + +protected: RecordDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ScopedDecl *PrevDecl) : TagDecl(DK, DC, L, Id, PrevDecl) { HasFlexibleArrayMember = false; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index b4f4c3b046..4bc2cc95a3 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -21,9 +21,11 @@ namespace clang { class TranslationUnitDecl; class NamespaceDecl; +class ScopedDecl; class FunctionDecl; -class ObjCMethodDecl; +class CXXRecordDecl; class EnumDecl; +class ObjCMethodDecl; class ObjCInterfaceDecl; /// Decl - This represents one declaration (or definition), e.g. a variable, @@ -35,11 +37,13 @@ public: // This lists the concrete classes of Decl in order of the inheritance // hierarchy. This allows us to do efficient classof tests based on the // enums below. The commented out names are abstract class names. + // [DeclContext] indicatea that the class also inherits from DeclContext. // Decl - TranslationUnit, + TranslationUnit, // [DeclContext] // NamedDecl Field, + CXXField, ObjCIvar, ObjCCategory, ObjCCategoryImpl, @@ -47,23 +51,29 @@ public: ObjCProtocol, ObjCProperty, // ScopedDecl - Namespace, + Namespace, // [DeclContext] // TypeDecl Typedef, // TagDecl - Enum, + Enum, // [DeclContext] // RecordDecl Struct, Union, Class, + // CXXRecordDecl [DeclContext] + CXXStruct, + CXXUnion, + CXXClass, // ValueDecl EnumConstant, - Function, + Function, // [DeclContext] + CXXMethod, Var, + CXXClassVar, ParmVar, - ObjCInterface, + ObjCInterface, // [DeclContext] ObjCCompatibleAlias, - ObjCMethod, + ObjCMethod, // [DeclContext] ObjCClass, ObjCForwardProtocol, ObjCPropertyImpl, @@ -72,14 +82,16 @@ public: // For each non-leaf class, we now define a mapping to the first/last member // of the class, to allow efficient classof. - NamedFirst = Field, NamedLast = ParmVar, - FieldFirst = Field, FieldLast = ObjCIvar, - ScopedFirst = Namespace, ScopedLast = ParmVar, - TypeFirst = Typedef, TypeLast = Class, - TagFirst = Enum , TagLast = Class, - RecordFirst = Struct , RecordLast = Class, - ValueFirst = EnumConstant , ValueLast = ParmVar, - VarFirst = Var , VarLast = ParmVar + NamedFirst = Field , NamedLast = ParmVar, + FieldFirst = Field , FieldLast = ObjCIvar, + ScopedFirst = Namespace , ScopedLast = ParmVar, + TypeFirst = Typedef , TypeLast = CXXClass, + TagFirst = Enum , TagLast = CXXClass, + RecordFirst = Struct , RecordLast = CXXClass, + CXXRecordFirst = CXXStruct , CXXRecordLast = CXXClass, + ValueFirst = EnumConstant , ValueLast = ParmVar, + FunctionFirst = Function , FunctionLast = CXXMethod, + VarFirst = Var , VarLast = ParmVar }; /// IdentifierNamespace - According to C99 6.2.3, there are four namespaces, @@ -118,7 +130,13 @@ private: /// HasAttrs - This indicates whether the decl has attributes or not. unsigned int HasAttrs : 1; -protected: + + protected: + /// Access - Used by C++ decls for the access specifier. + // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum + unsigned Access : 2; + friend class CXXClassMemberWrapper; + Decl(Kind DK, SourceLocation L) : Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false) { if (Decl::CollectingStats()) addDeclKind(DK); @@ -161,10 +179,14 @@ public: case EnumConstant: case ObjCInterface: case ObjCCompatibleAlias: + case CXXField: return IDNS_Ordinary; case Struct: case Union: case Class: + case CXXStruct: + case CXXUnion: + case CXXClass: case Enum: return IDNS_Tag; case Namespace: @@ -206,8 +228,9 @@ protected: /// TranslationUnitDecl /// NamespaceDecl /// FunctionDecl -/// ObjCMethodDecl +/// CXXRecordDecl /// EnumDecl +/// ObjCMethodDecl /// ObjCInterfaceDecl /// class DeclContext { @@ -230,15 +253,18 @@ class DeclContext { return static_cast(const_cast(D)); case Decl::Namespace: return static_cast(const_cast(D)); - case Decl::Function: - return static_cast(const_cast(D)); + case Decl::Enum: + return static_cast(const_cast(D)); case Decl::ObjCMethod: return static_cast(const_cast(D)); case Decl::ObjCInterface: return static_cast(const_cast(D)); - case Decl::Enum: - return static_cast(const_cast(D)); default: + if (DK >= Decl::FunctionFirst && DK <= Decl::FunctionLast) + return static_cast(const_cast(D)); + if (DK >= Decl::CXXRecordFirst && DK <= Decl::CXXRecordLast) + return static_cast(const_cast(D)); + assert(false && "a decl that inherits DeclContext isn't handled"); return 0; } @@ -255,6 +281,7 @@ public: bool isFunctionOrMethod() const { switch (DeclKind) { case Decl::Function: + case Decl::CXXMethod: case Decl::ObjCMethod: return true; default: @@ -272,12 +299,17 @@ public: switch (D->getKind()) { case Decl::TranslationUnit: case Decl::Namespace: - case Decl::Function: + case Decl::Enum: case Decl::ObjCMethod: case Decl::ObjCInterface: - case Decl::Enum: return true; default: + if (D->getKind() >= Decl::FunctionFirst && + D->getKind() <= Decl::FunctionLast) + return true; + if (D->getKind() >= Decl::CXXRecordFirst && + D->getKind() <= Decl::CXXRecordLast) + return true; return false; } } @@ -285,8 +317,9 @@ public: static bool classof(const TranslationUnitDecl *D) { return true; } static bool classof(const NamespaceDecl *D) { return true; } static bool classof(const FunctionDecl *D) { return true; } - static bool classof(const ObjCMethodDecl *D) { return true; } + static bool classof(const CXXRecordDecl *D) { return true; } static bool classof(const EnumDecl *D) { return true; } + static bool classof(const ObjCMethodDecl *D) { return true; } static bool classof(const ObjCInterfaceDecl *D) { return true; } }; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h new file mode 100644 index 0000000000..4c152f5adf --- /dev/null +++ b/include/clang/AST/DeclCXX.h @@ -0,0 +1,195 @@ +//===-- DeclCXX.h - Classes for representing C++ declarations *- C++ -*-======// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C++ Decl subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLCXX_H +#define LLVM_CLANG_AST_DECLCXX_H + +#include "clang/AST/Decl.h" + +namespace clang { +class CXXRecordDecl; + +/// CXXFieldDecl - Represents an instance field of a C++ struct/union/class. +class CXXFieldDecl : public FieldDecl { + CXXRecordDecl *Parent; + + CXXFieldDecl(CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, + QualType T, Expr *BW = NULL) + : FieldDecl(CXXField, L, Id, T, BW), Parent(RD) {} +public: + static CXXFieldDecl *Create(ASTContext &C, CXXRecordDecl *RD,SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW = NULL); + + void setAccess(AccessSpecifier AS) { Access = AS; } + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + CXXRecordDecl *getParent() const { return Parent; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == CXXField; } + static bool classof(const CXXFieldDecl *D) { return true; } +}; + +/// CXXRecordDecl - Represents a C++ struct/union/class. +/// The only difference with RecordDecl is that CXXRecordDecl is a DeclContext. +class CXXRecordDecl : public RecordDecl, public DeclContext { +protected: + CXXRecordDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ScopedDecl *PrevDecl) : RecordDecl(DK, DC, L, Id, PrevDecl), + DeclContext(DK) { + assert(classof(static_cast(this)) && "Invalid Kind!"); + } +public: + static CXXRecordDecl *Create(ASTContext &C, Kind DK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + ScopedDecl *PrevDecl); + + const CXXFieldDecl *getMember(unsigned i) const { + return cast(RecordDecl::getMember(i)); + } + CXXFieldDecl *getMember(unsigned i) { + return cast(RecordDecl::getMember(i)); + } + + /// getMember - If the member doesn't exist, or there are no members, this + /// function will return 0; + CXXFieldDecl *getMember(IdentifierInfo *name) { + return cast_or_null(RecordDecl::getMember(name)); + } + + static bool classof(const Decl *D) { + return D->getKind() >= CXXRecordFirst && D->getKind() <= CXXRecordLast; + } + static bool classof(const CXXRecordDecl *D) { return true; } + +protected: + /// EmitImpl - Serialize this CXXRecordDecl. Called by Decl::Emit. + // FIXME: Implement this. + //virtual void EmitImpl(llvm::Serializer& S) const; + + /// CreateImpl - Deserialize a CXXRecordDecl. Called by Decl::Create. + // FIXME: Implement this. + static CXXRecordDecl* CreateImpl(Kind DK, llvm::Deserializer& D, ASTContext& C); + + friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); +}; + +/// CXXMethodDecl - Represents a static or instance method of a +/// struct/union/class. +class CXXMethodDecl : public FunctionDecl { + + CXXMethodDecl(CXXRecordDecl *RD, SourceLocation L, + IdentifierInfo *Id, QualType T, + bool isStatic, bool isInline, ScopedDecl *PrevDecl) + : FunctionDecl(CXXMethod, RD, L, Id, T, (isStatic ? Static : None), + isInline, PrevDecl) {} +public: + static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, IdentifierInfo *Id, + QualType T, bool isStatic = false, + bool isInline = false, ScopedDecl *PrevDecl = 0); + + bool isStatic() const { return getStorageClass() == Static; } + bool isInstance() const { return !isStatic(); } + + void setAccess(AccessSpecifier AS) { Access = AS; } + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + + /// getThisType - Returns the type of 'this' pointer. + /// Should only be called for instance methods. + QualType getThisType(ASTContext &C) const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == CXXMethod; } + static bool classof(const CXXMethodDecl *D) { return true; } + +protected: + /// EmitImpl - Serialize this CXXMethodDecl. Called by Decl::Emit. + // FIXME: Implement this. + //virtual void EmitImpl(llvm::Serializer& S) const; + + /// CreateImpl - Deserialize a CXXMethodDecl. Called by Decl::Create. + // FIXME: Implement this. + static CXXMethodDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C); + + friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); +}; + +/// CXXClassVarDecl - Represents a static data member of a struct/union/class. +class CXXClassVarDecl : public VarDecl { + + CXXClassVarDecl(CXXRecordDecl *RD, SourceLocation L, + IdentifierInfo *Id, QualType T, ScopedDecl *PrevDecl) + : VarDecl(CXXClassVar, RD, L, Id, T, None, PrevDecl) {} +public: + static CXXClassVarDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L,IdentifierInfo *Id, + QualType T, ScopedDecl *PrevDecl); + + void setAccess(AccessSpecifier AS) { Access = AS; } + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == CXXClassVar; } + static bool classof(const CXXClassVarDecl *D) { return true; } + +protected: + /// EmitImpl - Serialize this CXXClassVarDecl. Called by Decl::Emit. + // FIXME: Implement this. + //virtual void EmitImpl(llvm::Serializer& S) const; + + /// CreateImpl - Deserialize a CXXClassVarDecl. Called by Decl::Create. + // FIXME: Implement this. + static CXXClassVarDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C); + + friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); +}; + + +/// CXXClassMemberWrapper - A wrapper class for C++ class member decls. +/// Common functions like set/getAccess are included here to avoid bloating +/// the interface of non-C++ specific decl classes, like NamedDecl. +class CXXClassMemberWrapper { + Decl *MD; + +public: + CXXClassMemberWrapper(Decl *D) : MD(D) { + assert(isMember(D) && "Not a C++ class member!"); + } + + AccessSpecifier getAccess() const { + return AccessSpecifier(MD->Access); + } + + void setAccess(AccessSpecifier AS) { + assert(AS != AS_none && "Access must be specified."); + MD->Access = AS; + } + + CXXRecordDecl *getParent() const { + if (ScopedDecl *SD = dyn_cast(MD)) { + return cast(SD->getDeclContext()); + } + return cast(MD)->getParent(); + } + + static bool isMember(Decl *D) { + if (ScopedDecl *SD = dyn_cast(D)) { + return isa(SD->getDeclContext()); + } + return isa(D); + } +}; + +} // end namespace clang + +#endif diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 8d68a58f8c..b5dba1029b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -62,7 +62,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, StorageClass S, bool isInline, ScopedDecl *PrevDecl) { void *Mem = C.getAllocator().Allocate(); - return new (Mem) FunctionDecl(DC, L, Id, T, S, isInline, PrevDecl); + return new (Mem) FunctionDecl(Function, DC, L, Id, T, S, isInline, PrevDecl); } FieldDecl *FieldDecl::Create(ASTContext &C, SourceLocation L, diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index b5b028320d..296304a66d 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" #include "llvm/ADT/DenseMap.h" using namespace clang; @@ -206,6 +207,13 @@ void Decl::addDeclKind(Kind k) { case LinkageSpec: nLinkageSpecDecl++; break; case FileScopeAsm: nFileScopeAsmDecl++; break; case TranslationUnit: break; + + // FIXME: Statistics for C++ decls. + case CXXField: + case CXXStruct: case CXXUnion: case CXXClass: + case CXXMethod: + case CXXClassVar: + break; } } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp new file mode 100644 index 0000000000..c319191bae --- /dev/null +++ b/lib/AST/DeclCXX.cpp @@ -0,0 +1,58 @@ +//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the C++ related Decl classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ASTContext.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, IdentifierInfo *Id, + QualType T, Expr *BW) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) CXXFieldDecl(RD, L, Id, T, BW); +} + +CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, Kind DK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) CXXRecordDecl(DK, DC, L, Id, PrevDecl); +} + +CXXMethodDecl * +CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, IdentifierInfo *Id, + QualType T, bool isStatic, bool isInline, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) CXXMethodDecl(RD, L, Id, T, isStatic, isInline, PrevDecl); +} + +QualType CXXMethodDecl::getThisType(ASTContext &C) const { + assert(isInstance() && "No 'this' for static methods!"); + QualType ClassTy = C.getTagDeclType(cast(getParent())); + QualType ThisTy = C.getPointerType(ClassTy); + ThisTy.addConst(); + return ThisTy; +} + +CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, IdentifierInfo *Id, + QualType T, ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) CXXClassVarDecl(RD, L, Id, T, PrevDecl); +} diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index bbc28ab6d7..ca9a15224f 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/lib/AST/DeclSerialization.cpp @@ -384,7 +384,8 @@ FunctionDecl* FunctionDecl::CreateImpl(Deserializer& D, ASTContext& C) { void *Mem = C.getAllocator().Allocate(); FunctionDecl* decl = new (Mem) - FunctionDecl(0, SourceLocation(), NULL, QualType(), SClass, IsInline, 0); + FunctionDecl(Function, 0, SourceLocation(), NULL, + QualType(), SClass, IsInline, 0); decl->ValueDecl::ReadInRec(D, C); D.ReadPtr(decl->DeclChain);