//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- 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 NestedNameSpecifier class, which represents // a C++ nested-name-specifier. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/Compiler.h" namespace clang { class ASTContext; class CXXRecordDecl; class NamespaceAliasDecl; class NamespaceDecl; class IdentifierInfo; struct PrintingPolicy; class Type; class TypeLoc; class LangOptions; /// \brief Represents a C++ nested name specifier, such as /// "\::std::vector::". /// /// C++ nested name specifiers are the prefixes to qualified /// namespaces. For example, "foo::" in "foo::x" is a nested name /// specifier. Nested name specifiers are made up of a sequence of /// specifiers, each of which can be a namespace, type, identifier /// (for dependent names), decltype specifier, or the global specifier ('::'). /// The last two specifiers can only appear at the start of a /// nested-namespace-specifier. class NestedNameSpecifier : public llvm::FoldingSetNode { /// \brief Enumeration describing enum StoredSpecifierKind { StoredIdentifier = 0, StoredDecl = 1, StoredTypeSpec = 2, StoredTypeSpecWithTemplate = 3 }; /// \brief The nested name specifier that precedes this nested name /// specifier. /// /// The pointer is the nested-name-specifier that precedes this /// one. The integer stores one of the first four values of type /// SpecifierKind. llvm::PointerIntPair Prefix; /// \brief The last component in the nested name specifier, which /// can be an identifier, a declaration, or a type. /// /// When the pointer is NULL, this specifier represents the global /// specifier '::'. Otherwise, the pointer is one of /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of /// specifier as encoded within the prefix. void* Specifier; public: /// \brief The kind of specifier that completes this nested name /// specifier. enum SpecifierKind { /// \brief An identifier, stored as an IdentifierInfo*. Identifier, /// \brief A namespace, stored as a NamespaceDecl*. Namespace, /// \brief A namespace alias, stored as a NamespaceAliasDecl*. NamespaceAlias, /// \brief A type, stored as a Type*. TypeSpec, /// \brief A type that was preceded by the 'template' keyword, /// stored as a Type*. TypeSpecWithTemplate, /// \brief The global specifier '::'. There is no stored value. Global, /// \brief Microsoft's '__super' specifier, stored as a CXXRecordDecl* of /// the class it appeared in. Super }; private: /// \brief Builds the global specifier. NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier), Specifier(nullptr) {} /// \brief Copy constructor used internally to clone nested name /// specifiers. NestedNameSpecifier(const NestedNameSpecifier &Other) : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), Specifier(Other.Specifier) { } void operator=(const NestedNameSpecifier &) = delete; /// \brief Either find or insert the given nested name specifier /// mockup in the given context. static NestedNameSpecifier *FindOrInsert(const ASTContext &Context, const NestedNameSpecifier &Mockup); public: /// \brief Builds a specifier combining a prefix and an identifier. /// /// The prefix must be dependent, since nested name specifiers /// referencing an identifier are only permitted when the identifier /// cannot be resolved. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, IdentifierInfo *II); /// \brief Builds a nested name specifier that names a namespace. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, const NamespaceDecl *NS); /// \brief Builds a nested name specifier that names a namespace alias. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, NamespaceAliasDecl *Alias); /// \brief Builds a nested name specifier that names a type. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, bool Template, const Type *T); /// \brief Builds a specifier that consists of just an identifier. /// /// The nested-name-specifier is assumed to be dependent, but has no /// prefix because the prefix is implied by something outside of the /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent /// type. static NestedNameSpecifier *Create(const ASTContext &Context, IdentifierInfo *II); /// \brief Returns the nested name specifier representing the global /// scope. static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); /// \brief Returns the nested name specifier representing the __super scope /// for the given CXXRecordDecl. static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context, CXXRecordDecl *RD); /// \brief Return the prefix of this nested name specifier. /// /// The prefix contains all of the parts of the nested name /// specifier that preced this current specifier. For example, for a /// nested name specifier that represents "foo::bar::", the current /// specifier will contain "bar::" and the prefix will contain /// "foo::". NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } /// \brief Determine what kind of nested name specifier is stored. SpecifierKind getKind() const; /// \brief Retrieve the identifier stored in this nested name /// specifier. IdentifierInfo *getAsIdentifier() const { if (Prefix.getInt() == StoredIdentifier) return (IdentifierInfo *)Specifier; return nullptr; } /// \brief Retrieve the namespace stored in this nested name /// specifier. NamespaceDecl *getAsNamespace() const; /// \brief Retrieve the namespace alias stored in this nested name /// specifier. NamespaceAliasDecl *getAsNamespaceAlias() const; /// \brief Retrieve the record declaration stored in this nested name /// specifier. CXXRecordDecl *getAsRecordDecl() const; /// \brief Retrieve the type stored in this nested name specifier. const Type *getAsType() const { if (Prefix.getInt() == StoredTypeSpec || Prefix.getInt() == StoredTypeSpecWithTemplate) return (const Type *)Specifier; return nullptr; } /// \brief Whether this nested name specifier refers to a dependent /// type or not. bool isDependent() const; /// \brief Whether this nested name specifier involves a template /// parameter. bool isInstantiationDependent() const; /// \brief Whether this nested-name-specifier contains an unexpanded /// parameter pack (for C++11 variadic templates). bool containsUnexpandedParameterPack() const; /// \brief Print this nested name specifier to the given output /// stream. void print(raw_ostream &OS, const PrintingPolicy &Policy) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(Prefix.getOpaqueValue()); ID.AddPointer(Specifier); } /// \brief Dump the nested name specifier to standard output to aid /// in debugging. void dump(const LangOptions &LO) const; void dump() const; }; /// \brief A C++ nested-name-specifier augmented with source location /// information. class NestedNameSpecifierLoc { NestedNameSpecifier *Qualifier; void *Data; /// \brief Determines the data length for the last component in the /// given nested-name-specifier. static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier); /// \brief Determines the data length for the entire /// nested-name-specifier. static unsigned getDataLength(NestedNameSpecifier *Qualifier); public: /// \brief Construct an empty nested-name-specifier. NestedNameSpecifierLoc() : Qualifier(nullptr), Data(nullptr) { } /// \brief Construct a nested-name-specifier with source location information /// from NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) : Qualifier(Qualifier), Data(Data) { } /// \brief Evalutes true when this nested-name-specifier location is /// non-empty. explicit operator bool() const { return Qualifier; } /// \brief Evalutes true when this nested-name-specifier location is /// empty. bool hasQualifier() const { return Qualifier; } /// \brief Retrieve the nested-name-specifier to which this instance /// refers. NestedNameSpecifier *getNestedNameSpecifier() const { return Qualifier; } /// \brief Retrieve the opaque pointer that refers to source-location data. void *getOpaqueData() const { return Data; } /// \brief Retrieve the source range covering the entirety of this /// nested-name-specifier. /// /// For example, if this instance refers to a nested-name-specifier /// \c \::std::vector::, the returned source range would cover /// from the initial '::' to the last '::'. SourceRange getSourceRange() const LLVM_READONLY; /// \brief Retrieve the source range covering just the last part of /// this nested-name-specifier, not including the prefix. /// /// For example, if this instance refers to a nested-name-specifier /// \c \::std::vector::, the returned source range would cover /// from "vector" to the last '::'. SourceRange getLocalSourceRange() const; /// \brief Retrieve the location of the beginning of this /// nested-name-specifier. SourceLocation getBeginLoc() const { return getSourceRange().getBegin(); } /// \brief Retrieve the location of the end of this /// nested-name-specifier. SourceLocation getEndLoc() const { return getSourceRange().getEnd(); } /// \brief Retrieve the location of the beginning of this /// component of the nested-name-specifier. SourceLocation getLocalBeginLoc() const { return getLocalSourceRange().getBegin(); } /// \brief Retrieve the location of the end of this component of the /// nested-name-specifier. SourceLocation getLocalEndLoc() const { return getLocalSourceRange().getEnd(); } /// \brief Return the prefix of this nested-name-specifier. /// /// For example, if this instance refers to a nested-name-specifier /// \c \::std::vector::, the prefix is \c \::std::. Note that the /// returned prefix may be empty, if this is the first component of /// the nested-name-specifier. NestedNameSpecifierLoc getPrefix() const { if (!Qualifier) return *this; return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data); } /// \brief For a nested-name-specifier that refers to a type, /// retrieve the type with source-location information. TypeLoc getTypeLoc() const; /// \brief Determines the data length for the entire /// nested-name-specifier. unsigned getDataLength() const { return getDataLength(Qualifier); } friend bool operator==(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { return X.Qualifier == Y.Qualifier && X.Data == Y.Data; } friend bool operator!=(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { return !(X == Y); } }; /// \brief Class that aids in the construction of nested-name-specifiers along /// with source-location information for all of the components of the /// nested-name-specifier. class NestedNameSpecifierLocBuilder { /// \brief The current representation of the nested-name-specifier we're /// building. NestedNameSpecifier *Representation; /// \brief Buffer used to store source-location information for the /// nested-name-specifier. /// /// Note that we explicitly manage the buffer (rather than using a /// SmallVector) because \c Declarator expects it to be possible to memcpy() /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. char *Buffer; /// \brief The size of the buffer used to store source-location information /// for the nested-name-specifier. unsigned BufferSize; /// \brief The capacity of the buffer used to store source-location /// information for the nested-name-specifier. unsigned BufferCapacity; public: NestedNameSpecifierLocBuilder() : Representation(nullptr), Buffer(nullptr), BufferSize(0), BufferCapacity(0) {} NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); NestedNameSpecifierLocBuilder & operator=(const NestedNameSpecifierLocBuilder &Other); ~NestedNameSpecifierLocBuilder() { if (BufferCapacity) free(Buffer); } /// \brief Retrieve the representation of the nested-name-specifier. NestedNameSpecifier *getRepresentation() const { return Representation; } /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'type::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param TemplateKWLoc The location of the 'template' keyword, if present. /// /// \param TL The TypeLoc that describes the type preceding the '::'. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, SourceLocation ColonColonLoc); /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'identifier::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param Identifier The identifier. /// /// \param IdentifierLoc The location of the identifier. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, IdentifierInfo *Identifier, SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'namespace::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param Namespace The namespace. /// /// \param NamespaceLoc The location of the namespace name. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, NamespaceDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'namespace-alias::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param Alias The namespace alias. /// /// \param AliasLoc The location of the namespace alias /// name. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, SourceLocation AliasLoc, SourceLocation ColonColonLoc); /// \brief Turn this (empty) nested-name-specifier into the global /// nested-name-specifier '::'. void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); /// \brief Turns this (empty) nested-name-specifier into '__super' /// nested-name-specifier. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param RD The declaration of the class in which nested-name-specifier /// appeared. /// /// \param SuperLoc The location of the '__super' keyword. /// name. /// /// \param ColonColonLoc The location of the trailing '::'. void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, SourceLocation SuperLoc, SourceLocation ColonColonLoc); /// \brief Make a new nested-name-specifier from incomplete source-location /// information. /// /// This routine should be used very, very rarely, in cases where we /// need to synthesize a nested-name-specifier. Most code should instead use /// \c Adopt() with a proper \c NestedNameSpecifierLoc. void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R); /// \brief Adopt an existing nested-name-specifier (with source-range /// information). void Adopt(NestedNameSpecifierLoc Other); /// \brief Retrieve the source range covered by this nested-name-specifier. SourceRange getSourceRange() const LLVM_READONLY { return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); } /// \brief Retrieve a nested-name-specifier with location information, /// copied into the given AST context. /// /// \param Context The context into which this nested-name-specifier will be /// copied. NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; /// \brief Retrieve a nested-name-specifier with location /// information based on the information in this builder. /// /// This loc will contain references to the builder's internal data and may /// be invalidated by any change to the builder. NestedNameSpecifierLoc getTemporary() const { return NestedNameSpecifierLoc(Representation, Buffer); } /// \brief Clear out this builder, and prepare it to build another /// nested-name-specifier with source-location information. void Clear() { Representation = nullptr; BufferSize = 0; } /// \brief Retrieve the underlying buffer. /// /// \returns A pair containing a pointer to the buffer of source-location /// data and the size of the source-location data that resides in that /// buffer. std::pair getBuffer() const { return std::make_pair(Buffer, BufferSize); } }; /// Insertion operator for diagnostics. This allows sending /// NestedNameSpecifiers into a diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, NestedNameSpecifier *NNS) { DB.AddTaggedVal(reinterpret_cast(NNS), DiagnosticsEngine::ak_nestednamespec); return DB; } } #endif