ExternalASTMerger.h revision 360784
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 21namespace 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. 48class ExternalASTMerger : public ExternalASTSource { 49public: 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; 59private: 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 68public: 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 105private: 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 114public: 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 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. 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. 182 void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; } 183private: 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 193public: 194 /// Log something if there is a logging callback installed. 195 llvm::raw_ostream &logs() { return *LogStream; } 196 197 /// True if the log stream is not llvm::nulls(); 198 bool LoggingEnabled() { return LogStream != &llvm::nulls(); } 199}; 200 201} // end namespace clang 202 203#endif 204