| //===- ExternalASTSource.h - Abstract External AST Interface ----*- 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 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 "clang/Basic/Module.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/StringRef.h" |
| #include "llvm/ADT/iterator.h" |
| #include "llvm/Support/PointerLikeTypeTraits.h" |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <iterator> |
| #include <string> |
| #include <utility> |
| |
| namespace clang { |
| |
| class ASTConsumer; |
| class ASTContext; |
| 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; |
| |
| /// Whether this AST source also provides information for |
| /// semantic analysis. |
| bool SemaSource = false; |
| |
| 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; } |
| |
| /// Determine whether D comes from a PCH which was built with a corresponding |
| /// object file. |
| virtual bool DeclIsFromPCHWithObjectFile(const Decl *D) { return false; } |
| |
| /// Abstracts clang modules and precompiled header files and holds |
| /// everything needed to generate debug info for an imported module |
| /// or PCH. |
| class ASTSourceDescriptor { |
| StringRef PCHModuleName; |
| StringRef Path; |
| StringRef ASTFile; |
| ASTFileSignature Signature; |
| const Module *ClangModule = nullptr; |
| |
| public: |
| ASTSourceDescriptor() = default; |
| ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile, |
| ASTFileSignature Signature) |
| : PCHModuleName(std::move(Name)), Path(std::move(Path)), |
| ASTFile(std::move(ASTFile)), Signature(Signature) {} |
| ASTSourceDescriptor(const Module &M); |
| |
| std::string getModuleName() const; |
| StringRef getPath() const { return Path; } |
| StringRef getASTFile() const { return ASTFile; } |
| ASTFileSignature getSignature() const { return Signature; } |
| const Module *getModuleOrNull() const { return ClangModule; } |
| }; |
| |
| /// 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; |
| |
| 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 |
| |
| /// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be |
| /// placed into a PointerUnion. |
| namespace llvm { |
| |
| 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); } |
| |
| enum { |
| 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 |