| 1 | //===--- ExternalASTMerger.h - Merging External AST Interface ---*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file declares the ExternalASTMerger, which vends a combination of ASTs |
| 10 | // from several different ASTContext/FileManager pairs |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | #ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H |
| 14 | #define LLVM_CLANG_AST_EXTERNALASTMERGER_H |
| 15 | |
| 16 | #include "clang/AST/ASTImporter.h" |
| 17 | #include "clang/AST/ASTImporterSharedState.h" |
| 18 | #include "clang/AST/ExternalASTSource.h" |
| 19 | #include "llvm/Support/raw_ostream.h" |
| 20 | |
| 21 | namespace clang { |
| 22 | |
| 23 | /// ExternalASTSource implementation that merges information from several |
| 24 | /// ASTContexts. |
| 25 | /// |
| 26 | /// ExternalASTMerger maintains a vector of ASTImporters that it uses to import |
| 27 | /// (potentially incomplete) Decls and DeclContexts from the source ASTContexts |
| 28 | /// in response to ExternalASTSource API calls. |
| 29 | /// |
| 30 | /// When lookup occurs in the resulting imported DeclContexts, the original |
| 31 | /// DeclContexts need to be queried. Roughly, there are three cases here: |
| 32 | /// |
| 33 | /// - The DeclContext of origin can be found by simple name lookup. In this |
| 34 | /// case, no additional state is required. |
| 35 | /// |
| 36 | /// - The DeclContext of origin is different from what would be found by name |
| 37 | /// lookup. In this case, Origins contains an entry overriding lookup and |
| 38 | /// specifying the correct pair of DeclContext/ASTContext. |
| 39 | /// |
| 40 | /// - The DeclContext of origin was determined by another ExternalASTMerger. |
| 41 | /// (This is possible when the source ASTContext for one of the Importers has |
| 42 | /// its own ExternalASTMerger). The origin must be properly forwarded in this |
| 43 | /// case. |
| 44 | /// |
| 45 | /// ExternalASTMerger's job is to maintain the data structures necessary to |
| 46 | /// allow this. The data structures themselves can be extracted (read-only) and |
| 47 | /// copied for re-use. |
| 48 | class ExternalASTMerger : public ExternalASTSource { |
| 49 | public: |
| 50 | /// A single origin for a DeclContext. Unlike Decls, DeclContexts do |
| 51 | /// not allow their containing ASTContext to be determined in all cases. |
| 52 | struct DCOrigin { |
| 53 | DeclContext *DC; |
| 54 | ASTContext *AST; |
| 55 | }; |
| 56 | |
| 57 | typedef std::map<const DeclContext *, DCOrigin> OriginMap; |
| 58 | typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector; |
| 59 | private: |
| 60 | /// One importer exists for each source. |
| 61 | ImporterVector Importers; |
| 62 | /// Overrides in case name lookup would return nothing or would return |
| 63 | /// the wrong thing. |
| 64 | OriginMap Origins; |
| 65 | /// The installed log stream. |
| 66 | llvm::raw_ostream *LogStream; |
| 67 | |
| 68 | public: |
| 69 | /// The target for an ExternalASTMerger. |
| 70 | /// |
| 71 | /// ASTImporters require both ASTContext and FileManager to be able to |
| 72 | /// import SourceLocations properly. |
| 73 | struct ImporterTarget { |
| 74 | ASTContext &AST; |
| 75 | FileManager &FM; |
| 76 | }; |
| 77 | /// A source for an ExternalASTMerger. |
| 78 | /// |
| 79 | /// ASTImporters require both ASTContext and FileManager to be able to |
| 80 | /// import SourceLocations properly. Additionally, when import occurs for |
| 81 | /// a DeclContext whose origin has been overridden, then this |
| 82 | /// ExternalASTMerger must be able to determine that. |
| 83 | class ImporterSource { |
| 84 | ASTContext &AST; |
| 85 | FileManager &FM; |
| 86 | const OriginMap &OM; |
| 87 | /// True iff the source only exists temporary, i.e., it will be removed from |
| 88 | /// the ExternalASTMerger during the life time of the ExternalASTMerger. |
| 89 | bool Temporary; |
| 90 | /// If the ASTContext of this source has an ExternalASTMerger that imports |
| 91 | /// into this source, then this will point to that other ExternalASTMerger. |
| 92 | ExternalASTMerger *Merger; |
| 93 | |
| 94 | public: |
| 95 | ImporterSource(ASTContext &AST, FileManager &FM, const OriginMap &OM, |
| 96 | bool Temporary = false, ExternalASTMerger *Merger = nullptr) |
| 97 | : AST(AST), FM(FM), OM(OM), Temporary(Temporary), Merger(Merger) {} |
| 98 | ASTContext &getASTContext() const { return AST; } |
| 99 | FileManager &getFileManager() const { return FM; } |
| 100 | const OriginMap &getOriginMap() const { return OM; } |
| 101 | bool isTemporary() const { return Temporary; } |
| 102 | ExternalASTMerger *getMerger() const { return Merger; } |
| 103 | }; |
| 104 | |
| 105 | private: |
| 106 | /// The target for this ExternalASTMerger. |
| 107 | ImporterTarget Target; |
| 108 | /// ExternalASTMerger has multiple ASTImporters that import into the same |
| 109 | /// TU. This is the shared state for all ASTImporters of this |
| 110 | /// ExternalASTMerger. |
| 111 | /// See also the CrossTranslationUnitContext that has a similar setup. |
| 112 | std::shared_ptr<ASTImporterSharedState> SharedState; |
| 113 | |
| 114 | public: |
| 115 | ExternalASTMerger(const ImporterTarget &Target, |
| 116 | ArrayRef<ImporterSource> Sources); |
| 117 | |
| 118 | /// Asks all connected ASTImporters if any of them imported the given |
| 119 | /// declaration. If any ASTImporter did import the given declaration, |
| 120 | /// then this function returns the declaration that D was imported from. |
| 121 | /// Returns nullptr if no ASTImporter did import D. |
| 122 | Decl *FindOriginalDecl(Decl *D); |
| 123 | |
| 124 | /// Add a set of ASTContexts as possible origins. |
| 125 | /// |
| 126 | /// Usually the set will be initialized in the constructor, but long-lived |
| 127 | /// ExternalASTMergers may need to import from new sources (for example, |
| 128 | /// newly-parsed source files). |
| 129 | /// |
| 130 | /// Ensures that Importers does not gain duplicate entries as a result. |
| 131 | void AddSources(ArrayRef<ImporterSource> Sources); |
| 132 | |
| 133 | /// Remove a set of ASTContexts as possible origins. |
| 134 | /// |
| 135 | /// Sometimes an origin goes away (for example, if a source file gets |
| 136 | /// superseded by a newer version). |
| 137 | /// |
| 138 | /// The caller is responsible for ensuring that this doesn't leave |
| 139 | /// DeclContexts that can't be completed. |
| 140 | void RemoveSources(ArrayRef<ImporterSource> Sources); |
| 141 | |
| 142 | /// Implementation of the ExternalASTSource API. |
| 143 | bool FindExternalVisibleDeclsByName(const DeclContext *DC, |
| 144 | DeclarationName Name, |
| 145 | const DeclContext *OriginalDC) override; |
| 146 | |
| 147 | /// Implementation of the ExternalASTSource API. |
| 148 | void |
| 149 | FindExternalLexicalDecls(const DeclContext *DC, |
| 150 | llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, |
| 151 | SmallVectorImpl<Decl *> &Result) override; |
| 152 | |
| 153 | /// Implementation of the ExternalASTSource API. |
| 154 | void CompleteType(TagDecl *Tag) override; |
| 155 | |
| 156 | /// Implementation of the ExternalASTSource API. |
| 157 | void CompleteType(ObjCInterfaceDecl *Interface) override; |
| 158 | |
| 159 | /// Returns true if DC can be found in any source AST context. |
| 160 | bool CanComplete(DeclContext *DC); |
| 161 | |
| 162 | /// Records an origin in Origins only if name lookup would find |
| 163 | /// something different or nothing at all. |
| 164 | void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); |
| 165 | |
| 166 | /// Regardless of any checks, override the Origin for a DeclContext. |
| 167 | void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); |
| 168 | |
| 169 | /// Get a read-only view of the Origins map, for use in constructing |
| 170 | /// an ImporterSource for another ExternalASTMerger. |
| 171 | const OriginMap &GetOrigins() { return Origins; } |
| 172 | |
| 173 | /// Returns true if Importers contains an ASTImporter whose source is |
| 174 | /// OriginContext. |
| 175 | bool HasImporterForOrigin(ASTContext &OriginContext); |
| 176 | |
| 177 | /// Returns a reference to the ASTImporter from Importers whose origin |
| 178 | /// is OriginContext. This allows manual import of ASTs while preserving the |
| 179 | /// OriginMap correctly. |
| 180 | ASTImporter &ImporterForOrigin(ASTContext &OriginContext); |
| 181 | |
| 182 | /// Sets the current log stream. |
| 183 | void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; } |
| 184 | private: |
| 185 | /// Records and origin in Origins. |
| 186 | void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, |
| 187 | ASTImporter &importer); |
| 188 | |
| 189 | /// Performs an action for every DeclContext that is identified as |
| 190 | /// corresponding (either by forced origin or by name lookup) to DC. |
| 191 | template <typename CallbackType> |
| 192 | void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback); |
| 193 | |
| 194 | public: |
| 195 | /// Log something if there is a logging callback installed. |
| 196 | llvm::raw_ostream &logs() { return *LogStream; } |
| 197 | |
| 198 | /// True if the log stream is not llvm::nulls(); |
| 199 | bool LoggingEnabled() { return LogStream != &llvm::nulls(); } |
| 200 | }; |
| 201 | |
| 202 | } // end namespace clang |
| 203 | |
| 204 | #endif |
| 205 | |