1 //===--- ExternalASTMerger.h - Merging External AST Interface ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file declares the ExternalASTMerger, which vends a combination of ASTs
10 // from several different ASTContext/FileManager pairs
12 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H
14 #define LLVM_CLANG_AST_EXTERNALASTMERGER_H
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"
23 /// ExternalASTSource implementation that merges information from several
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.
30 /// When lookup occurs in the resulting imported DeclContexts, the original
31 /// DeclContexts need to be queried. Roughly, there are three cases here:
33 /// - The DeclContext of origin can be found by simple name lookup. In this
34 /// case, no additional state is required.
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.
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
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 {
50 /// A single origin for a DeclContext. Unlike Decls, DeclContexts do
51 /// not allow their containing ASTContext to be determined in all cases.
57 typedef std::map<const DeclContext *, DCOrigin> OriginMap;
58 typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector;
60 /// One importer exists for each source.
61 ImporterVector Importers;
62 /// Overrides in case name lookup would return nothing or would return
65 /// The installed log stream.
66 llvm::raw_ostream *LogStream;
69 /// The target for an ExternalASTMerger.
71 /// ASTImporters require both ASTContext and FileManager to be able to
72 /// import SourceLocations properly.
73 struct ImporterTarget {
77 /// A source for an ExternalASTMerger.
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 {
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.
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;
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; }
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;
115 ExternalASTMerger(const ImporterTarget &Target,
116 llvm::ArrayRef<ImporterSource> Sources);
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);
124 /// Add a set of ASTContexts as possible origins.
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).
130 /// Ensures that Importers does not gain duplicate entries as a result.
131 void AddSources(llvm::ArrayRef<ImporterSource> Sources);
133 /// Remove a set of ASTContexts as possible origins.
135 /// Sometimes an origin goes away (for example, if a source file gets
136 /// superseded by a newer version).
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);
142 /// Implementation of the ExternalASTSource API.
143 bool FindExternalVisibleDeclsByName(const DeclContext *DC,
144 DeclarationName Name) override;
146 /// Implementation of the ExternalASTSource API.
148 FindExternalLexicalDecls(const DeclContext *DC,
149 llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
150 SmallVectorImpl<Decl *> &Result) override;
152 /// Implementation of the ExternalASTSource API.
153 void CompleteType(TagDecl *Tag) override;
155 /// Implementation of the ExternalASTSource API.
156 void CompleteType(ObjCInterfaceDecl *Interface) override;
158 /// Returns true if DC can be found in any source AST context.
159 bool CanComplete(DeclContext *DC);
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);
165 /// Regardless of any checks, override the Origin for a DeclContext.
166 void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin);
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; }
172 /// Returns true if Importers contains an ASTImporter whose source is
174 bool HasImporterForOrigin(ASTContext &OriginContext);
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);
181 /// Sets the current log stream.
182 void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; }
184 /// Records and origin in Origins.
185 void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
186 ASTImporter &importer);
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);
194 /// Log something if there is a logging callback installed.
195 llvm::raw_ostream &logs() { return *LogStream; }
197 /// True if the log stream is not llvm::nulls();
198 bool LoggingEnabled() { return LogStream != &llvm::nulls(); }
201 } // end namespace clang