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) AST(AST)97 : AST(AST), FM(FM), OM(OM), Temporary(Temporary), Merger(Merger) {} getASTContext()98 ASTContext &getASTContext() const { return AST; } getFileManager()99 FileManager &getFileManager() const { return FM; } getOriginMap()100 const OriginMap &getOriginMap() const { return OM; } isTemporary()101 bool isTemporary() const { return Temporary; } getMerger()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 llvm::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(llvm::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(llvm::ArrayRef<ImporterSource> Sources); 141 142 /// Implementation of the ExternalASTSource API. 143 bool FindExternalVisibleDeclsByName(const DeclContext *DC, 144 DeclarationName Name) override; 145 146 /// Implementation of the ExternalASTSource API. 147 void 148 FindExternalLexicalDecls(const DeclContext *DC, 149 llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, 150 SmallVectorImpl<Decl *> &Result) override; 151 152 /// Implementation of the ExternalASTSource API. 153 void CompleteType(TagDecl *Tag) override; 154 155 /// Implementation of the ExternalASTSource API. 156 void CompleteType(ObjCInterfaceDecl *Interface) override; 157 158 /// Returns true if DC can be found in any source AST context. 159 bool CanComplete(DeclContext *DC); 160 161 /// Records an origin in Origins only if name lookup would find 162 /// something different or nothing at all. 163 void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); 164 165 /// Regardless of any checks, override the Origin for a DeclContext. 166 void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); 167 168 /// Get a read-only view of the Origins map, for use in constructing 169 /// an ImporterSource for another ExternalASTMerger. GetOrigins()170 const OriginMap &GetOrigins() { return Origins; } 171 172 /// Returns true if Importers contains an ASTImporter whose source is 173 /// OriginContext. 174 bool HasImporterForOrigin(ASTContext &OriginContext); 175 176 /// Returns a reference to the ASTImporter from Importers whose origin 177 /// is OriginContext. This allows manual import of ASTs while preserving the 178 /// OriginMap correctly. 179 ASTImporter &ImporterForOrigin(ASTContext &OriginContext); 180 181 /// Sets the current log stream. SetLogStream(llvm::raw_string_ostream & Stream)182 void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; } 183 private: 184 /// Records and origin in Origins. 185 void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, 186 ASTImporter &importer); 187 188 /// Performs an action for every DeclContext that is identified as 189 /// corresponding (either by forced origin or by name lookup) to DC. 190 template <typename CallbackType> 191 void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback); 192 193 public: 194 /// Log something if there is a logging callback installed. logs()195 llvm::raw_ostream &logs() { return *LogStream; } 196 197 /// True if the log stream is not llvm::nulls(); LoggingEnabled()198 bool LoggingEnabled() { return LogStream != &llvm::nulls(); } 199 }; 200 201 } // end namespace clang 202 203 #endif 204