| //===--- ExternalASTMerger.h - Merging 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 declares the ExternalASTMerger, which vends a combination of ASTs |
| // from several different ASTContext/FileManager pairs |
| // |
| //===----------------------------------------------------------------------===// |
| #ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H |
| #define LLVM_CLANG_AST_EXTERNALASTMERGER_H |
| |
| #include "clang/AST/ASTImporter.h" |
| #include "clang/AST/ASTImporterSharedState.h" |
| #include "clang/AST/ExternalASTSource.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| namespace clang { |
| |
| /// ExternalASTSource implementation that merges information from several |
| /// ASTContexts. |
| /// |
| /// ExternalASTMerger maintains a vector of ASTImporters that it uses to import |
| /// (potentially incomplete) Decls and DeclContexts from the source ASTContexts |
| /// in response to ExternalASTSource API calls. |
| /// |
| /// When lookup occurs in the resulting imported DeclContexts, the original |
| /// DeclContexts need to be queried. Roughly, there are three cases here: |
| /// |
| /// - The DeclContext of origin can be found by simple name lookup. In this |
| /// case, no additional state is required. |
| /// |
| /// - The DeclContext of origin is different from what would be found by name |
| /// lookup. In this case, Origins contains an entry overriding lookup and |
| /// specifying the correct pair of DeclContext/ASTContext. |
| /// |
| /// - The DeclContext of origin was determined by another ExternalASTMerger. |
| /// (This is possible when the source ASTContext for one of the Importers has |
| /// its own ExternalASTMerger). The origin must be properly forwarded in this |
| /// case. |
| /// |
| /// ExternalASTMerger's job is to maintain the data structures necessary to |
| /// allow this. The data structures themselves can be extracted (read-only) and |
| /// copied for re-use. |
| class ExternalASTMerger : public ExternalASTSource { |
| public: |
| /// A single origin for a DeclContext. Unlike Decls, DeclContexts do |
| /// not allow their containing ASTContext to be determined in all cases. |
| struct DCOrigin { |
| DeclContext *DC; |
| ASTContext *AST; |
| }; |
| |
| typedef std::map<const DeclContext *, DCOrigin> OriginMap; |
| typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector; |
| private: |
| /// One importer exists for each source. |
| ImporterVector Importers; |
| /// Overrides in case name lookup would return nothing or would return |
| /// the wrong thing. |
| OriginMap Origins; |
| /// The installed log stream. |
| llvm::raw_ostream *LogStream; |
| |
| public: |
| /// The target for an ExternalASTMerger. |
| /// |
| /// ASTImporters require both ASTContext and FileManager to be able to |
| /// import SourceLocations properly. |
| struct ImporterTarget { |
| ASTContext &AST; |
| FileManager &FM; |
| }; |
| /// A source for an ExternalASTMerger. |
| /// |
| /// ASTImporters require both ASTContext and FileManager to be able to |
| /// import SourceLocations properly. Additionally, when import occurs for |
| /// a DeclContext whose origin has been overridden, then this |
| /// ExternalASTMerger must be able to determine that. |
| class ImporterSource { |
| ASTContext &AST; |
| FileManager &FM; |
| const OriginMap &OM; |
| /// True iff the source only exists temporary, i.e., it will be removed from |
| /// the ExternalASTMerger during the life time of the ExternalASTMerger. |
| bool Temporary; |
| /// If the ASTContext of this source has an ExternalASTMerger that imports |
| /// into this source, then this will point to that other ExternalASTMerger. |
| ExternalASTMerger *Merger; |
| |
| public: |
| ImporterSource(ASTContext &AST, FileManager &FM, const OriginMap &OM, |
| bool Temporary = false, ExternalASTMerger *Merger = nullptr) |
| : AST(AST), FM(FM), OM(OM), Temporary(Temporary), Merger(Merger) {} |
| ASTContext &getASTContext() const { return AST; } |
| FileManager &getFileManager() const { return FM; } |
| const OriginMap &getOriginMap() const { return OM; } |
| bool isTemporary() const { return Temporary; } |
| ExternalASTMerger *getMerger() const { return Merger; } |
| }; |
| |
| private: |
| /// The target for this ExternalASTMerger. |
| ImporterTarget Target; |
| /// ExternalASTMerger has multiple ASTImporters that import into the same |
| /// TU. This is the shared state for all ASTImporters of this |
| /// ExternalASTMerger. |
| /// See also the CrossTranslationUnitContext that has a similar setup. |
| std::shared_ptr<ASTImporterSharedState> SharedState; |
| |
| public: |
| ExternalASTMerger(const ImporterTarget &Target, |
| llvm::ArrayRef<ImporterSource> Sources); |
| |
| /// Asks all connected ASTImporters if any of them imported the given |
| /// declaration. If any ASTImporter did import the given declaration, |
| /// then this function returns the declaration that D was imported from. |
| /// Returns nullptr if no ASTImporter did import import D. |
| Decl *FindOriginalDecl(Decl *D); |
| |
| /// Add a set of ASTContexts as possible origins. |
| /// |
| /// Usually the set will be initialized in the constructor, but long-lived |
| /// ExternalASTMergers may need to import from new sources (for example, |
| /// newly-parsed source files). |
| /// |
| /// Ensures that Importers does not gain duplicate entries as a result. |
| void AddSources(llvm::ArrayRef<ImporterSource> Sources); |
| |
| /// Remove a set of ASTContexts as possible origins. |
| /// |
| /// Sometimes an origin goes away (for example, if a source file gets |
| /// superseded by a newer version). |
| /// |
| /// The caller is responsible for ensuring that this doesn't leave |
| /// DeclContexts that can't be completed. |
| void RemoveSources(llvm::ArrayRef<ImporterSource> Sources); |
| |
| /// Implementation of the ExternalASTSource API. |
| bool FindExternalVisibleDeclsByName(const DeclContext *DC, |
| DeclarationName Name) override; |
| |
| /// Implementation of the ExternalASTSource API. |
| void |
| FindExternalLexicalDecls(const DeclContext *DC, |
| llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, |
| SmallVectorImpl<Decl *> &Result) override; |
| |
| /// Implementation of the ExternalASTSource API. |
| void CompleteType(TagDecl *Tag) override; |
| |
| /// Implementation of the ExternalASTSource API. |
| void CompleteType(ObjCInterfaceDecl *Interface) override; |
| |
| /// Returns true if DC can be found in any source AST context. |
| bool CanComplete(DeclContext *DC); |
| |
| /// Records an origin in Origins only if name lookup would find |
| /// something different or nothing at all. |
| void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); |
| |
| /// Regardless of any checks, override the Origin for a DeclContext. |
| void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); |
| |
| /// Get a read-only view of the Origins map, for use in constructing |
| /// an ImporterSource for another ExternalASTMerger. |
| const OriginMap &GetOrigins() { return Origins; } |
| |
| /// Returns true if Importers contains an ASTImporter whose source is |
| /// OriginContext. |
| bool HasImporterForOrigin(ASTContext &OriginContext); |
| |
| /// Returns a reference to the ASTImporter from Importers whose origin |
| /// is OriginContext. This allows manual import of ASTs while preserving the |
| /// OriginMap correctly. |
| ASTImporter &ImporterForOrigin(ASTContext &OriginContext); |
| |
| /// Sets the current log stream. |
| void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; } |
| private: |
| /// Records and origin in Origins. |
| void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, |
| ASTImporter &importer); |
| |
| /// Performs an action for every DeclContext that is identified as |
| /// corresponding (either by forced origin or by name lookup) to DC. |
| template <typename CallbackType> |
| void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback); |
| |
| public: |
| /// Log something if there is a logging callback installed. |
| llvm::raw_ostream &logs() { return *LogStream; } |
| |
| /// True if the log stream is not llvm::nulls(); |
| bool LoggingEnabled() { return LogStream != &llvm::nulls(); } |
| }; |
| |
| } // end namespace clang |
| |
| #endif |