123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- ExternalASTSource.h - Abstract External AST Interface ----*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines the ExternalASTSource interface, which enables
- // construction of AST nodes from some external source.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H
- #define LLVM_CLANG_AST_EXTERNALASTSOURCE_H
- #include "clang/AST/CharUnits.h"
- #include "clang/AST/DeclBase.h"
- #include "clang/Basic/LLVM.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/IntrusiveRefCntPtr.h"
- #include "llvm/ADT/Optional.h"
- #include "llvm/ADT/PointerUnion.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/iterator.h"
- #include "llvm/Support/PointerLikeTypeTraits.h"
- #include <cassert>
- #include <cstddef>
- #include <cstdint>
- #include <iterator>
- #include <utility>
- namespace clang {
- class ASTConsumer;
- class ASTContext;
- class ASTSourceDescriptor;
- class CXXBaseSpecifier;
- class CXXCtorInitializer;
- class CXXRecordDecl;
- class DeclarationName;
- class FieldDecl;
- class IdentifierInfo;
- class NamedDecl;
- class ObjCInterfaceDecl;
- class RecordDecl;
- class Selector;
- class Stmt;
- class TagDecl;
- /// Abstract interface for external sources of AST nodes.
- ///
- /// External AST sources provide AST nodes constructed from some
- /// external source, such as a precompiled header. External AST
- /// sources can resolve types and declarations from abstract IDs into
- /// actual type and declaration nodes, and read parts of declaration
- /// contexts.
- class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
- friend class ExternalSemaSource;
- /// Generation number for this external AST source. Must be increased
- /// whenever we might have added new redeclarations for existing decls.
- uint32_t CurrentGeneration = 0;
- /// LLVM-style RTTI.
- static char ID;
- public:
- ExternalASTSource() = default;
- virtual ~ExternalASTSource();
- /// RAII class for safely pairing a StartedDeserializing call
- /// with FinishedDeserializing.
- class Deserializing {
- ExternalASTSource *Source;
- public:
- explicit Deserializing(ExternalASTSource *source) : Source(source) {
- assert(Source);
- Source->StartedDeserializing();
- }
- ~Deserializing() {
- Source->FinishedDeserializing();
- }
- };
- /// Get the current generation of this AST source. This number
- /// is incremented each time the AST source lazily extends an existing
- /// entity.
- uint32_t getGeneration() const { return CurrentGeneration; }
- /// Resolve a declaration ID into a declaration, potentially
- /// building a new declaration.
- ///
- /// This method only needs to be implemented if the AST source ever
- /// passes back decl sets as VisibleDeclaration objects.
- ///
- /// The default implementation of this method is a no-op.
- virtual Decl *GetExternalDecl(uint32_t ID);
- /// Resolve a selector ID into a selector.
- ///
- /// This operation only needs to be implemented if the AST source
- /// returns non-zero for GetNumKnownSelectors().
- ///
- /// The default implementation of this method is a no-op.
- virtual Selector GetExternalSelector(uint32_t ID);
- /// Returns the number of selectors known to the external AST
- /// source.
- ///
- /// The default implementation of this method is a no-op.
- virtual uint32_t GetNumExternalSelectors();
- /// Resolve the offset of a statement in the decl stream into
- /// a statement.
- ///
- /// This operation is meant to be used via a LazyOffsetPtr. It only
- /// needs to be implemented if the AST source uses methods like
- /// FunctionDecl::setLazyBody when building decls.
- ///
- /// The default implementation of this method is a no-op.
- virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
- /// Resolve the offset of a set of C++ constructor initializers in
- /// the decl stream into an array of initializers.
- ///
- /// The default implementation of this method is a no-op.
- virtual CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset);
- /// Resolve the offset of a set of C++ base specifiers in the decl
- /// stream into an array of specifiers.
- ///
- /// The default implementation of this method is a no-op.
- virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
- /// Update an out-of-date identifier.
- virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {}
- /// Find all declarations with the given name in the given context,
- /// and add them to the context by calling SetExternalVisibleDeclsForName
- /// or SetNoExternalVisibleDeclsForName.
- /// \return \c true if any declarations might have been found, \c false if
- /// we definitely have no declarations with tbis name.
- ///
- /// The default implementation of this method is a no-op returning \c false.
- virtual bool
- FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
- /// Ensures that the table of all visible declarations inside this
- /// context is up to date.
- ///
- /// The default implementation of this function is a no-op.
- virtual void completeVisibleDeclsMap(const DeclContext *DC);
- /// Retrieve the module that corresponds to the given module ID.
- virtual Module *getModule(unsigned ID) { return nullptr; }
- /// Return a descriptor for the corresponding module, if one exists.
- virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
- enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
- virtual ExtKind hasExternalDefinitions(const Decl *D);
- /// Finds all declarations lexically contained within the given
- /// DeclContext, after applying an optional filter predicate.
- ///
- /// \param IsKindWeWant a predicate function that returns true if the passed
- /// declaration kind is one we are looking for.
- ///
- /// The default implementation of this method is a no-op.
- virtual void
- FindExternalLexicalDecls(const DeclContext *DC,
- llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
- SmallVectorImpl<Decl *> &Result);
- /// Finds all declarations lexically contained within the given
- /// DeclContext.
- void FindExternalLexicalDecls(const DeclContext *DC,
- SmallVectorImpl<Decl *> &Result) {
- FindExternalLexicalDecls(DC, [](Decl::Kind) { return true; }, Result);
- }
- /// Get the decls that are contained in a file in the Offset/Length
- /// range. \p Length can be 0 to indicate a point at \p Offset instead of
- /// a range.
- virtual void FindFileRegionDecls(FileID File, unsigned Offset,
- unsigned Length,
- SmallVectorImpl<Decl *> &Decls);
- /// Gives the external AST source an opportunity to complete
- /// the redeclaration chain for a declaration. Called each time we
- /// need the most recent declaration of a declaration after the
- /// generation count is incremented.
- virtual void CompleteRedeclChain(const Decl *D);
- /// Gives the external AST source an opportunity to complete
- /// an incomplete type.
- virtual void CompleteType(TagDecl *Tag);
- /// Gives the external AST source an opportunity to complete an
- /// incomplete Objective-C class.
- ///
- /// This routine will only be invoked if the "externally completed" bit is
- /// set on the ObjCInterfaceDecl via the function
- /// \c ObjCInterfaceDecl::setExternallyCompleted().
- virtual void CompleteType(ObjCInterfaceDecl *Class);
- /// Loads comment ranges.
- virtual void ReadComments();
- /// Notify ExternalASTSource that we started deserialization of
- /// a decl or type so until FinishedDeserializing is called there may be
- /// decls that are initializing. Must be paired with FinishedDeserializing.
- ///
- /// The default implementation of this method is a no-op.
- virtual void StartedDeserializing();
- /// Notify ExternalASTSource that we finished the deserialization of
- /// a decl or type. Must be paired with StartedDeserializing.
- ///
- /// The default implementation of this method is a no-op.
- virtual void FinishedDeserializing();
- /// Function that will be invoked when we begin parsing a new
- /// translation unit involving this external AST source.
- ///
- /// The default implementation of this method is a no-op.
- virtual void StartTranslationUnit(ASTConsumer *Consumer);
- /// Print any statistics that have been gathered regarding
- /// the external AST source.
- ///
- /// The default implementation of this method is a no-op.
- virtual void PrintStats();
- /// Perform layout on the given record.
- ///
- /// This routine allows the external AST source to provide an specific
- /// layout for a record, overriding the layout that would normally be
- /// constructed. It is intended for clients who receive specific layout
- /// details rather than source code (such as LLDB). The client is expected
- /// to fill in the field offsets, base offsets, virtual base offsets, and
- /// complete object size.
- ///
- /// \param Record The record whose layout is being requested.
- ///
- /// \param Size The final size of the record, in bits.
- ///
- /// \param Alignment The final alignment of the record, in bits.
- ///
- /// \param FieldOffsets The offset of each of the fields within the record,
- /// expressed in bits. All of the fields must be provided with offsets.
- ///
- /// \param BaseOffsets The offset of each of the direct, non-virtual base
- /// classes. If any bases are not given offsets, the bases will be laid
- /// out according to the ABI.
- ///
- /// \param VirtualBaseOffsets The offset of each of the virtual base classes
- /// (either direct or not). If any bases are not given offsets, the bases will be laid
- /// out according to the ABI.
- ///
- /// \returns true if the record layout was provided, false otherwise.
- virtual bool layoutRecordType(
- const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
- llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
- llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets);
- //===--------------------------------------------------------------------===//
- // Queries for performance analysis.
- //===--------------------------------------------------------------------===//
- struct MemoryBufferSizes {
- size_t malloc_bytes;
- size_t mmap_bytes;
- MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
- : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
- };
- /// Return the amount of memory used by memory buffers, breaking down
- /// by heap-backed versus mmap'ed memory.
- MemoryBufferSizes getMemoryBufferSizes() const {
- MemoryBufferSizes sizes(0, 0);
- getMemoryBufferSizes(sizes);
- return sizes;
- }
- virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
- /// LLVM-style RTTI.
- /// \{
- virtual bool isA(const void *ClassID) const { return ClassID == &ID; }
- static bool classof(const ExternalASTSource *S) { return S->isA(&ID); }
- /// \}
- protected:
- static DeclContextLookupResult
- SetExternalVisibleDeclsForName(const DeclContext *DC,
- DeclarationName Name,
- ArrayRef<NamedDecl*> Decls);
- static DeclContextLookupResult
- SetNoExternalVisibleDeclsForName(const DeclContext *DC,
- DeclarationName Name);
- /// Increment the current generation.
- uint32_t incrementGeneration(ASTContext &C);
- };
- /// A lazy pointer to an AST node (of base type T) that resides
- /// within an external AST source.
- ///
- /// The AST node is identified within the external AST source by a
- /// 63-bit offset, and can be retrieved via an operation on the
- /// external AST source itself.
- template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)>
- struct LazyOffsetPtr {
- /// Either a pointer to an AST node or the offset within the
- /// external AST source where the AST node can be found.
- ///
- /// If the low bit is clear, a pointer to the AST node. If the low
- /// bit is set, the upper 63 bits are the offset.
- mutable uint64_t Ptr = 0;
- public:
- LazyOffsetPtr() = default;
- explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {}
- explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) {
- assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
- if (Offset == 0)
- Ptr = 0;
- }
- LazyOffsetPtr &operator=(T *Ptr) {
- this->Ptr = reinterpret_cast<uint64_t>(Ptr);
- return *this;
- }
- LazyOffsetPtr &operator=(uint64_t Offset) {
- assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
- if (Offset == 0)
- Ptr = 0;
- else
- Ptr = (Offset << 1) | 0x01;
- return *this;
- }
- /// Whether this pointer is non-NULL.
- ///
- /// This operation does not require the AST node to be deserialized.
- explicit operator bool() const { return Ptr != 0; }
- /// Whether this pointer is non-NULL.
- ///
- /// This operation does not require the AST node to be deserialized.
- bool isValid() const { return Ptr != 0; }
- /// Whether this pointer is currently stored as an offset.
- bool isOffset() const { return Ptr & 0x01; }
- /// Retrieve the pointer to the AST node that this lazy pointer points to.
- ///
- /// \param Source the external AST source.
- ///
- /// \returns a pointer to the AST node.
- T* get(ExternalASTSource *Source) const {
- if (isOffset()) {
- assert(Source &&
- "Cannot deserialize a lazy pointer without an AST source");
- Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
- }
- return reinterpret_cast<T*>(Ptr);
- }
- };
- /// A lazy value (of type T) that is within an AST node of type Owner,
- /// where the value might change in later generations of the external AST
- /// source.
- template<typename Owner, typename T, void (ExternalASTSource::*Update)(Owner)>
- struct LazyGenerationalUpdatePtr {
- /// A cache of the value of this pointer, in the most recent generation in
- /// which we queried it.
- struct LazyData {
- ExternalASTSource *ExternalSource;
- uint32_t LastGeneration = 0;
- T LastValue;
- LazyData(ExternalASTSource *Source, T Value)
- : ExternalSource(Source), LastValue(Value) {}
- };
- // Our value is represented as simply T if there is no external AST source.
- using ValueType = llvm::PointerUnion<T, LazyData*>;
- ValueType Value;
- LazyGenerationalUpdatePtr(ValueType V) : Value(V) {}
- // Defined in ASTContext.h
- static ValueType makeValue(const ASTContext &Ctx, T Value);
- public:
- explicit LazyGenerationalUpdatePtr(const ASTContext &Ctx, T Value = T())
- : Value(makeValue(Ctx, Value)) {}
- /// Create a pointer that is not potentially updated by later generations of
- /// the external AST source.
- enum NotUpdatedTag { NotUpdated };
- LazyGenerationalUpdatePtr(NotUpdatedTag, T Value = T())
- : Value(Value) {}
- /// Forcibly set this pointer (which must be lazy) as needing updates.
- void markIncomplete() {
- Value.template get<LazyData *>()->LastGeneration = 0;
- }
- /// Set the value of this pointer, in the current generation.
- void set(T NewValue) {
- if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) {
- LazyVal->LastValue = NewValue;
- return;
- }
- Value = NewValue;
- }
- /// Set the value of this pointer, for this and all future generations.
- void setNotUpdated(T NewValue) { Value = NewValue; }
- /// Get the value of this pointer, updating its owner if necessary.
- T get(Owner O) {
- if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) {
- if (LazyVal->LastGeneration != LazyVal->ExternalSource->getGeneration()) {
- LazyVal->LastGeneration = LazyVal->ExternalSource->getGeneration();
- (LazyVal->ExternalSource->*Update)(O);
- }
- return LazyVal->LastValue;
- }
- return Value.template get<T>();
- }
- /// Get the most recently computed value of this pointer without updating it.
- T getNotUpdated() const {
- if (auto *LazyVal = Value.template dyn_cast<LazyData *>())
- return LazyVal->LastValue;
- return Value.template get<T>();
- }
- void *getOpaqueValue() { return Value.getOpaqueValue(); }
- static LazyGenerationalUpdatePtr getFromOpaqueValue(void *Ptr) {
- return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr));
- }
- };
- } // namespace clang
- namespace llvm {
- /// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be
- /// placed into a PointerUnion.
- template<typename Owner, typename T,
- void (clang::ExternalASTSource::*Update)(Owner)>
- struct PointerLikeTypeTraits<
- clang::LazyGenerationalUpdatePtr<Owner, T, Update>> {
- using Ptr = clang::LazyGenerationalUpdatePtr<Owner, T, Update>;
- static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); }
- static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); }
- static constexpr int NumLowBitsAvailable =
- PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1;
- };
- } // namespace llvm
- namespace clang {
- /// Represents a lazily-loaded vector of data.
- ///
- /// The lazily-loaded vector of data contains data that is partially loaded
- /// from an external source and partially added by local translation. The
- /// items loaded from the external source are loaded lazily, when needed for
- /// iteration over the complete vector.
- template<typename T, typename Source,
- void (Source::*Loader)(SmallVectorImpl<T>&),
- unsigned LoadedStorage = 2, unsigned LocalStorage = 4>
- class LazyVector {
- SmallVector<T, LoadedStorage> Loaded;
- SmallVector<T, LocalStorage> Local;
- public:
- /// Iteration over the elements in the vector.
- ///
- /// In a complete iteration, the iterator walks the range [-M, N),
- /// where negative values are used to indicate elements
- /// loaded from the external source while non-negative values are used to
- /// indicate elements added via \c push_back().
- /// However, to provide iteration in source order (for, e.g., chained
- /// precompiled headers), dereferencing the iterator flips the negative
- /// values (corresponding to loaded entities), so that position -M
- /// corresponds to element 0 in the loaded entities vector, position -M+1
- /// corresponds to element 1 in the loaded entities vector, etc. This
- /// gives us a reasonably efficient, source-order walk.
- ///
- /// We define this as a wrapping iterator around an int. The
- /// iterator_adaptor_base class forwards the iterator methods to basic integer
- /// arithmetic.
- class iterator
- : public llvm::iterator_adaptor_base<
- iterator, int, std::random_access_iterator_tag, T, int, T *, T &> {
- friend class LazyVector;
- LazyVector *Self;
- iterator(LazyVector *Self, int Position)
- : iterator::iterator_adaptor_base(Position), Self(Self) {}
- bool isLoaded() const { return this->I < 0; }
- public:
- iterator() : iterator(nullptr, 0) {}
- typename iterator::reference operator*() const {
- if (isLoaded())
- return Self->Loaded.end()[this->I];
- return Self->Local.begin()[this->I];
- }
- };
- iterator begin(Source *source, bool LocalOnly = false) {
- if (LocalOnly)
- return iterator(this, 0);
- if (source)
- (source->*Loader)(Loaded);
- return iterator(this, -(int)Loaded.size());
- }
- iterator end() {
- return iterator(this, Local.size());
- }
- void push_back(const T& LocalValue) {
- Local.push_back(LocalValue);
- }
- void erase(iterator From, iterator To) {
- if (From.isLoaded() && To.isLoaded()) {
- Loaded.erase(&*From, &*To);
- return;
- }
- if (From.isLoaded()) {
- Loaded.erase(&*From, Loaded.end());
- From = begin(nullptr, true);
- }
- Local.erase(&*From, &*To);
- }
- };
- /// A lazy pointer to a statement.
- using LazyDeclStmtPtr =
- LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>;
- /// A lazy pointer to a declaration.
- using LazyDeclPtr =
- LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>;
- /// A lazy pointer to a set of CXXCtorInitializers.
- using LazyCXXCtorInitializersPtr =
- LazyOffsetPtr<CXXCtorInitializer *, uint64_t,
- &ExternalASTSource::GetExternalCXXCtorInitializers>;
- /// A lazy pointer to a set of CXXBaseSpecifiers.
- using LazyCXXBaseSpecifiersPtr =
- LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
- &ExternalASTSource::GetExternalCXXBaseSpecifiers>;
- } // namespace clang
- #endif // LLVM_CLANG_AST_EXTERNALASTSOURCE_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|