//===--- 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" namespace llvm { class raw_ostream; } namespace clang { class ASTContext; 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), or the global specifier ('::', must be the /// first specifier). class NestedNameSpecifier : public llvm::FoldingSetNode { /// \brief Enumeration describing enum StoredSpecifierKind { StoredIdentifier = 0, StoredNamespaceOrAlias = 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 }; private: /// \brief Builds the global specifier. NestedNameSpecifier() : Prefix(0, StoredIdentifier), Specifier(0) { } /// \brief Copy constructor used internally to clone nested name /// specifiers. NestedNameSpecifier(const NestedNameSpecifier &Other) : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), Specifier(Other.Specifier) { } NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not implement /// \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, 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 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 0; } /// \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 type stored in this nested name specifier. const Type *getAsType() const { if (Prefix.getInt() == StoredTypeSpec || Prefix.getInt() == StoredTypeSpecWithTemplate) return (const Type *)Specifier; return 0; } /// \brief Whether this nested name specifier refers to a dependent /// type or not. bool isDependent() const; /// \brief Whether this nested-name-specifier contains an unexpanded /// parameter pack (for C++0x variadic templates). bool containsUnexpandedParameterPack() const; /// \brief Print this nested name specifier to the given output /// stream. void print(llvm::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); }; /// \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(0), Data(0) { } /// \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. operator bool() 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; /// \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); } }; /// 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), Diagnostic::ak_nestednamespec); return DB; } } #endif