1e5dd7070Spatrick //===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the ExternalASTMerger, which vends a combination of
10e5dd7070Spatrick // ASTs from several different ASTContext/FileManager pairs
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14e5dd7070Spatrick #include "clang/AST/ASTContext.h"
15e5dd7070Spatrick #include "clang/AST/Decl.h"
16e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
17e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
18e5dd7070Spatrick #include "clang/AST/DeclTemplate.h"
19e5dd7070Spatrick #include "clang/AST/ExternalASTMerger.h"
20e5dd7070Spatrick
21e5dd7070Spatrick using namespace clang;
22e5dd7070Spatrick
23e5dd7070Spatrick namespace {
24e5dd7070Spatrick
25e5dd7070Spatrick template <typename T> struct Source {
26e5dd7070Spatrick T t;
Source__anon24c518b50111::Source27e5dd7070Spatrick Source(T t) : t(t) {}
operator T__anon24c518b50111::Source28e5dd7070Spatrick operator T() { return t; }
get__anon24c518b50111::Source29e5dd7070Spatrick template <typename U = T> U &get() { return t; }
get__anon24c518b50111::Source30e5dd7070Spatrick template <typename U = T> const U &get() const { return t; }
operator Source<U>__anon24c518b50111::Source31e5dd7070Spatrick template <typename U> operator Source<U>() { return Source<U>(t); }
32e5dd7070Spatrick };
33e5dd7070Spatrick
34e5dd7070Spatrick typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;
35e5dd7070Spatrick
36e5dd7070Spatrick /// For the given DC, return the DC that is safe to perform lookups on. This is
37e5dd7070Spatrick /// the DC we actually want to work with most of the time.
CanonicalizeDC(const DeclContext * DC)38e5dd7070Spatrick const DeclContext *CanonicalizeDC(const DeclContext *DC) {
39e5dd7070Spatrick if (isa<LinkageSpecDecl>(DC))
40e5dd7070Spatrick return DC->getRedeclContext();
41e5dd7070Spatrick return DC;
42e5dd7070Spatrick }
43e5dd7070Spatrick
44e5dd7070Spatrick Source<const DeclContext *>
LookupSameContext(Source<TranslationUnitDecl * > SourceTU,const DeclContext * DC,ASTImporter & ReverseImporter)45e5dd7070Spatrick LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
46e5dd7070Spatrick ASTImporter &ReverseImporter) {
47e5dd7070Spatrick DC = CanonicalizeDC(DC);
48e5dd7070Spatrick if (DC->isTranslationUnit()) {
49e5dd7070Spatrick return SourceTU;
50e5dd7070Spatrick }
51e5dd7070Spatrick Source<const DeclContext *> SourceParentDC =
52e5dd7070Spatrick LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);
53e5dd7070Spatrick if (!SourceParentDC) {
54e5dd7070Spatrick // If we couldn't find the parent DC in this TranslationUnit, give up.
55e5dd7070Spatrick return nullptr;
56e5dd7070Spatrick }
57e5dd7070Spatrick auto *ND = cast<NamedDecl>(DC);
58e5dd7070Spatrick DeclarationName Name = ND->getDeclName();
59e5dd7070Spatrick auto SourceNameOrErr = ReverseImporter.Import(Name);
60e5dd7070Spatrick if (!SourceNameOrErr) {
61e5dd7070Spatrick llvm::consumeError(SourceNameOrErr.takeError());
62e5dd7070Spatrick return nullptr;
63e5dd7070Spatrick }
64e5dd7070Spatrick Source<DeclarationName> SourceName = *SourceNameOrErr;
65e5dd7070Spatrick DeclContext::lookup_result SearchResult =
66e5dd7070Spatrick SourceParentDC.get()->lookup(SourceName.get());
67a9ac8606Spatrick
68e5dd7070Spatrick // There are two cases here. First, we might not find the name.
69e5dd7070Spatrick // We might also find multiple copies, in which case we have no
70e5dd7070Spatrick // guarantee that the one we wanted is the one we pick. (E.g.,
71e5dd7070Spatrick // if we have two specializations of the same template it is
72e5dd7070Spatrick // very hard to determine which is the one you want.)
73e5dd7070Spatrick //
74e5dd7070Spatrick // The Origins map fixes this problem by allowing the origin to be
75e5dd7070Spatrick // explicitly recorded, so we trigger that recording by returning
76e5dd7070Spatrick // nothing (rather than a possibly-inaccurate guess) here.
77a9ac8606Spatrick if (SearchResult.isSingleResult()) {
78a9ac8606Spatrick NamedDecl *SearchResultDecl = SearchResult.front();
79e5dd7070Spatrick if (isa<DeclContext>(SearchResultDecl) &&
80e5dd7070Spatrick SearchResultDecl->getKind() == DC->getDeclKind())
81e5dd7070Spatrick return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();
82e5dd7070Spatrick return nullptr; // This type of lookup is unsupported
83a9ac8606Spatrick } else {
84a9ac8606Spatrick return nullptr;
85e5dd7070Spatrick }
86e5dd7070Spatrick }
87e5dd7070Spatrick
88e5dd7070Spatrick /// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.
89e5dd7070Spatrick ///
90e5dd7070Spatrick /// There are several modifications:
91e5dd7070Spatrick ///
92e5dd7070Spatrick /// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few
93e5dd7070Spatrick /// others), which instructs Clang to refer to ExternalASTMerger. Also, it
94e5dd7070Spatrick /// forces MinimalImport to true, which is necessary to make this work.
95e5dd7070Spatrick /// - It maintains a reverse importer for use with names. This allows lookup of
96e5dd7070Spatrick /// arbitrary names in the source context.
97e5dd7070Spatrick /// - It updates the ExternalASTMerger's origin map as needed whenever a
98e5dd7070Spatrick /// it sees a DeclContext.
99e5dd7070Spatrick class LazyASTImporter : public ASTImporter {
100e5dd7070Spatrick private:
101e5dd7070Spatrick ExternalASTMerger &Parent;
102e5dd7070Spatrick ASTImporter Reverse;
103e5dd7070Spatrick const ExternalASTMerger::OriginMap &FromOrigins;
104e5dd7070Spatrick /// @see ExternalASTMerger::ImporterSource::Temporary
105e5dd7070Spatrick bool TemporarySource;
106e5dd7070Spatrick /// Map of imported declarations back to the declarations they originated
107e5dd7070Spatrick /// from.
108e5dd7070Spatrick llvm::DenseMap<Decl *, Decl *> ToOrigin;
109e5dd7070Spatrick /// @see ExternalASTMerger::ImporterSource::Merger
110e5dd7070Spatrick ExternalASTMerger *SourceMerger;
logs()111e5dd7070Spatrick llvm::raw_ostream &logs() { return Parent.logs(); }
112e5dd7070Spatrick public:
LazyASTImporter(ExternalASTMerger & _Parent,ASTContext & ToContext,FileManager & ToFileManager,const ExternalASTMerger::ImporterSource & S,std::shared_ptr<ASTImporterSharedState> SharedState)113e5dd7070Spatrick LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,
114e5dd7070Spatrick FileManager &ToFileManager,
115e5dd7070Spatrick const ExternalASTMerger::ImporterSource &S,
116e5dd7070Spatrick std::shared_ptr<ASTImporterSharedState> SharedState)
117e5dd7070Spatrick : ASTImporter(ToContext, ToFileManager, S.getASTContext(),
118e5dd7070Spatrick S.getFileManager(),
119e5dd7070Spatrick /*MinimalImport=*/true, SharedState),
120e5dd7070Spatrick Parent(_Parent),
121e5dd7070Spatrick Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager,
122e5dd7070Spatrick /*MinimalImport=*/true),
123e5dd7070Spatrick FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()),
124e5dd7070Spatrick SourceMerger(S.getMerger()) {}
125e5dd7070Spatrick
ImportImpl(Decl * FromD)126e5dd7070Spatrick llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {
127e5dd7070Spatrick if (!TemporarySource || !SourceMerger)
128e5dd7070Spatrick return ASTImporter::ImportImpl(FromD);
129e5dd7070Spatrick
130e5dd7070Spatrick // If we get here, then this source is importing from a temporary ASTContext
131e5dd7070Spatrick // that also has another ExternalASTMerger attached. It could be
132e5dd7070Spatrick // possible that the current ExternalASTMerger and the temporary ASTContext
133e5dd7070Spatrick // share a common ImporterSource, which means that the temporary
134e5dd7070Spatrick // AST could contain declarations that were imported from a source
135e5dd7070Spatrick // that this ExternalASTMerger can access directly. Instead of importing
136e5dd7070Spatrick // such declarations from the temporary ASTContext, they should instead
137e5dd7070Spatrick // be directly imported by this ExternalASTMerger from the original
138e5dd7070Spatrick // source. This way the ExternalASTMerger can safely do a minimal import
139e5dd7070Spatrick // without creating incomplete declarations originated from a temporary
140e5dd7070Spatrick // ASTContext. If we would try to complete such declarations later on, we
141e5dd7070Spatrick // would fail to do so as their temporary AST could be deleted (which means
142e5dd7070Spatrick // that the missing parts of the minimally imported declaration in that
143e5dd7070Spatrick // ASTContext were also deleted).
144e5dd7070Spatrick //
145e5dd7070Spatrick // The following code tracks back any declaration that needs to be
146e5dd7070Spatrick // imported from the temporary ASTContext to a persistent ASTContext.
147e5dd7070Spatrick // Then the ExternalASTMerger tries to import from the persistent
148e5dd7070Spatrick // ASTContext directly by using the associated ASTImporter. If that
149e5dd7070Spatrick // succeeds, this ASTImporter just maps the declarations imported by
150e5dd7070Spatrick // the other (persistent) ASTImporter to this (temporary) ASTImporter.
151e5dd7070Spatrick // The steps can be visualized like this:
152e5dd7070Spatrick //
153e5dd7070Spatrick // Target AST <--- 3. Indirect import --- Persistent AST
154e5dd7070Spatrick // ^ of persistent decl ^
155e5dd7070Spatrick // | |
156e5dd7070Spatrick // 1. Current import 2. Tracking back to persistent decl
157e5dd7070Spatrick // 4. Map persistent decl |
158e5dd7070Spatrick // & pretend we imported. |
159e5dd7070Spatrick // | |
160e5dd7070Spatrick // Temporary AST -------------------------------'
161e5dd7070Spatrick
162e5dd7070Spatrick // First, ask the ExternalASTMerger of the source where the temporary
163e5dd7070Spatrick // declaration originated from.
164e5dd7070Spatrick Decl *Persistent = SourceMerger->FindOriginalDecl(FromD);
165e5dd7070Spatrick // FromD isn't from a persistent AST, so just do a normal import.
166e5dd7070Spatrick if (!Persistent)
167e5dd7070Spatrick return ASTImporter::ImportImpl(FromD);
168e5dd7070Spatrick // Now ask the current ExternalASTMerger to try import the persistent
169e5dd7070Spatrick // declaration into the target.
170e5dd7070Spatrick ASTContext &PersistentCtx = Persistent->getASTContext();
171e5dd7070Spatrick ASTImporter &OtherImporter = Parent.ImporterForOrigin(PersistentCtx);
172e5dd7070Spatrick // Check that we never end up in the current Importer again.
173e5dd7070Spatrick assert((&PersistentCtx != &getFromContext()) && (&OtherImporter != this) &&
174e5dd7070Spatrick "Delegated to same Importer?");
175e5dd7070Spatrick auto DeclOrErr = OtherImporter.Import(Persistent);
176e5dd7070Spatrick // Errors when importing the persistent decl are treated as if we
177e5dd7070Spatrick // had errors with importing the temporary decl.
178e5dd7070Spatrick if (!DeclOrErr)
179e5dd7070Spatrick return DeclOrErr.takeError();
180e5dd7070Spatrick Decl *D = *DeclOrErr;
181e5dd7070Spatrick // Tell the current ASTImporter that this has already been imported
182e5dd7070Spatrick // to prevent any further queries for the temporary decl.
183e5dd7070Spatrick MapImported(FromD, D);
184e5dd7070Spatrick return D;
185e5dd7070Spatrick }
186e5dd7070Spatrick
187e5dd7070Spatrick /// Implements the ASTImporter interface for tracking back a declaration
188e5dd7070Spatrick /// to its original declaration it came from.
GetOriginalDecl(Decl * To)189e5dd7070Spatrick Decl *GetOriginalDecl(Decl *To) override {
190e5dd7070Spatrick auto It = ToOrigin.find(To);
191e5dd7070Spatrick if (It != ToOrigin.end())
192e5dd7070Spatrick return It->second;
193e5dd7070Spatrick return nullptr;
194e5dd7070Spatrick }
195e5dd7070Spatrick
196e5dd7070Spatrick /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
197e5dd7070Spatrick /// map is kept up to date. Also set the appropriate flags.
Imported(Decl * From,Decl * To)198e5dd7070Spatrick void Imported(Decl *From, Decl *To) override {
199e5dd7070Spatrick ToOrigin[To] = From;
200e5dd7070Spatrick
201e5dd7070Spatrick if (auto *ToDC = dyn_cast<DeclContext>(To)) {
202e5dd7070Spatrick const bool LoggingEnabled = Parent.LoggingEnabled();
203e5dd7070Spatrick if (LoggingEnabled)
204e5dd7070Spatrick logs() << "(ExternalASTMerger*)" << (void*)&Parent
205e5dd7070Spatrick << " imported (DeclContext*)" << (void*)ToDC
206e5dd7070Spatrick << ", (ASTContext*)" << (void*)&getToContext()
207e5dd7070Spatrick << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)
208e5dd7070Spatrick << ", (ASTContext*)" << (void*)&getFromContext()
209e5dd7070Spatrick << "\n";
210e5dd7070Spatrick Source<DeclContext *> FromDC(
211e5dd7070Spatrick cast<DeclContext>(From)->getPrimaryContext());
212e5dd7070Spatrick if (FromOrigins.count(FromDC) &&
213e5dd7070Spatrick Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) {
214e5dd7070Spatrick if (LoggingEnabled)
215e5dd7070Spatrick logs() << "(ExternalASTMerger*)" << (void*)&Parent
216e5dd7070Spatrick << " forced origin (DeclContext*)"
217e5dd7070Spatrick << (void*)FromOrigins.at(FromDC).DC
218e5dd7070Spatrick << ", (ASTContext*)"
219e5dd7070Spatrick << (void*)FromOrigins.at(FromDC).AST
220e5dd7070Spatrick << "\n";
221e5dd7070Spatrick Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC));
222e5dd7070Spatrick } else {
223e5dd7070Spatrick if (LoggingEnabled)
224e5dd7070Spatrick logs() << "(ExternalASTMerger*)" << (void*)&Parent
225e5dd7070Spatrick << " maybe recording origin (DeclContext*)" << (void*)FromDC
226e5dd7070Spatrick << ", (ASTContext*)" << (void*)&getFromContext()
227e5dd7070Spatrick << "\n";
228e5dd7070Spatrick Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});
229e5dd7070Spatrick }
230e5dd7070Spatrick }
231e5dd7070Spatrick if (auto *ToTag = dyn_cast<TagDecl>(To)) {
232e5dd7070Spatrick ToTag->setHasExternalLexicalStorage();
233e5dd7070Spatrick ToTag->getPrimaryContext()->setMustBuildLookupTable();
234e5dd7070Spatrick assert(Parent.CanComplete(ToTag));
235e5dd7070Spatrick } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {
236e5dd7070Spatrick ToNamespace->setHasExternalVisibleStorage();
237e5dd7070Spatrick assert(Parent.CanComplete(ToNamespace));
238e5dd7070Spatrick } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {
239e5dd7070Spatrick ToContainer->setHasExternalLexicalStorage();
240e5dd7070Spatrick ToContainer->getPrimaryContext()->setMustBuildLookupTable();
241e5dd7070Spatrick assert(Parent.CanComplete(ToContainer));
242e5dd7070Spatrick }
243e5dd7070Spatrick }
GetReverse()244e5dd7070Spatrick ASTImporter &GetReverse() { return Reverse; }
245e5dd7070Spatrick };
246e5dd7070Spatrick
HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls,const Candidate & C)247e5dd7070Spatrick bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
248e5dd7070Spatrick if (isa<FunctionDecl>(C.first.get()))
249e5dd7070Spatrick return false;
250e5dd7070Spatrick return llvm::any_of(Decls, [&](const Candidate &D) {
251e5dd7070Spatrick return C.first.get()->getKind() == D.first.get()->getKind();
252e5dd7070Spatrick });
253e5dd7070Spatrick }
254e5dd7070Spatrick
255e5dd7070Spatrick } // end namespace
256e5dd7070Spatrick
ImporterForOrigin(ASTContext & OriginContext)257e5dd7070Spatrick ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) {
258e5dd7070Spatrick for (const std::unique_ptr<ASTImporter> &I : Importers)
259e5dd7070Spatrick if (&I->getFromContext() == &OriginContext)
260e5dd7070Spatrick return *I;
261e5dd7070Spatrick llvm_unreachable("We should have an importer for this origin!");
262e5dd7070Spatrick }
263e5dd7070Spatrick
264e5dd7070Spatrick namespace {
LazyImporterForOrigin(ExternalASTMerger & Merger,ASTContext & OriginContext)265e5dd7070Spatrick LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,
266e5dd7070Spatrick ASTContext &OriginContext) {
267e5dd7070Spatrick return static_cast<LazyASTImporter &>(
268e5dd7070Spatrick Merger.ImporterForOrigin(OriginContext));
269e5dd7070Spatrick }
270e5dd7070Spatrick }
271e5dd7070Spatrick
HasImporterForOrigin(ASTContext & OriginContext)272e5dd7070Spatrick bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) {
273e5dd7070Spatrick for (const std::unique_ptr<ASTImporter> &I : Importers)
274e5dd7070Spatrick if (&I->getFromContext() == &OriginContext)
275e5dd7070Spatrick return true;
276e5dd7070Spatrick return false;
277e5dd7070Spatrick }
278e5dd7070Spatrick
279e5dd7070Spatrick template <typename CallbackType>
ForEachMatchingDC(const DeclContext * DC,CallbackType Callback)280e5dd7070Spatrick void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,
281e5dd7070Spatrick CallbackType Callback) {
282e5dd7070Spatrick if (Origins.count(DC)) {
283e5dd7070Spatrick ExternalASTMerger::DCOrigin Origin = Origins[DC];
284e5dd7070Spatrick LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
285e5dd7070Spatrick Callback(Importer, Importer.GetReverse(), Origin.DC);
286e5dd7070Spatrick } else {
287e5dd7070Spatrick bool DidCallback = false;
288e5dd7070Spatrick for (const std::unique_ptr<ASTImporter> &Importer : Importers) {
289e5dd7070Spatrick Source<TranslationUnitDecl *> SourceTU =
290e5dd7070Spatrick Importer->getFromContext().getTranslationUnitDecl();
291e5dd7070Spatrick ASTImporter &Reverse =
292e5dd7070Spatrick static_cast<LazyASTImporter *>(Importer.get())->GetReverse();
293e5dd7070Spatrick if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {
294e5dd7070Spatrick DidCallback = true;
295e5dd7070Spatrick if (Callback(*Importer, Reverse, SourceDC))
296e5dd7070Spatrick break;
297e5dd7070Spatrick }
298e5dd7070Spatrick }
299e5dd7070Spatrick if (!DidCallback && LoggingEnabled())
300e5dd7070Spatrick logs() << "(ExternalASTMerger*)" << (void*)this
301e5dd7070Spatrick << " asserting for (DeclContext*)" << (const void*)DC
302e5dd7070Spatrick << ", (ASTContext*)" << (void*)&Target.AST
303e5dd7070Spatrick << "\n";
304e5dd7070Spatrick assert(DidCallback && "Couldn't find a source context matching our DC");
305e5dd7070Spatrick }
306e5dd7070Spatrick }
307e5dd7070Spatrick
CompleteType(TagDecl * Tag)308e5dd7070Spatrick void ExternalASTMerger::CompleteType(TagDecl *Tag) {
309e5dd7070Spatrick assert(Tag->hasExternalLexicalStorage());
310e5dd7070Spatrick ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,
311e5dd7070Spatrick Source<const DeclContext *> SourceDC) -> bool {
312e5dd7070Spatrick auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));
313e5dd7070Spatrick if (SourceTag->hasExternalLexicalStorage())
314e5dd7070Spatrick SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);
315e5dd7070Spatrick if (!SourceTag->getDefinition())
316e5dd7070Spatrick return false;
317e5dd7070Spatrick Forward.MapImported(SourceTag, Tag);
318e5dd7070Spatrick if (llvm::Error Err = Forward.ImportDefinition(SourceTag))
319e5dd7070Spatrick llvm::consumeError(std::move(Err));
320e5dd7070Spatrick Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());
321e5dd7070Spatrick return true;
322e5dd7070Spatrick });
323e5dd7070Spatrick }
324e5dd7070Spatrick
CompleteType(ObjCInterfaceDecl * Interface)325e5dd7070Spatrick void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) {
326e5dd7070Spatrick assert(Interface->hasExternalLexicalStorage());
327e5dd7070Spatrick ForEachMatchingDC(
328e5dd7070Spatrick Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,
329e5dd7070Spatrick Source<const DeclContext *> SourceDC) -> bool {
330e5dd7070Spatrick auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(
331e5dd7070Spatrick cast<ObjCInterfaceDecl>(SourceDC.get()));
332e5dd7070Spatrick if (SourceInterface->hasExternalLexicalStorage())
333e5dd7070Spatrick SourceInterface->getASTContext().getExternalSource()->CompleteType(
334e5dd7070Spatrick SourceInterface);
335e5dd7070Spatrick if (!SourceInterface->getDefinition())
336e5dd7070Spatrick return false;
337e5dd7070Spatrick Forward.MapImported(SourceInterface, Interface);
338e5dd7070Spatrick if (llvm::Error Err = Forward.ImportDefinition(SourceInterface))
339e5dd7070Spatrick llvm::consumeError(std::move(Err));
340e5dd7070Spatrick return true;
341e5dd7070Spatrick });
342e5dd7070Spatrick }
343e5dd7070Spatrick
CanComplete(DeclContext * Interface)344e5dd7070Spatrick bool ExternalASTMerger::CanComplete(DeclContext *Interface) {
345e5dd7070Spatrick assert(Interface->hasExternalLexicalStorage() ||
346e5dd7070Spatrick Interface->hasExternalVisibleStorage());
347e5dd7070Spatrick bool FoundMatchingDC = false;
348e5dd7070Spatrick ForEachMatchingDC(Interface,
349e5dd7070Spatrick [&](ASTImporter &Forward, ASTImporter &Reverse,
350e5dd7070Spatrick Source<const DeclContext *> SourceDC) -> bool {
351e5dd7070Spatrick FoundMatchingDC = true;
352e5dd7070Spatrick return true;
353e5dd7070Spatrick });
354e5dd7070Spatrick return FoundMatchingDC;
355e5dd7070Spatrick }
356e5dd7070Spatrick
357e5dd7070Spatrick namespace {
IsSameDC(const DeclContext * D1,const DeclContext * D2)358e5dd7070Spatrick bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {
359e5dd7070Spatrick if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))
360e5dd7070Spatrick return true; // There are many cases where Objective-C is ambiguous.
361e5dd7070Spatrick if (auto *T1 = dyn_cast<TagDecl>(D1))
362e5dd7070Spatrick if (auto *T2 = dyn_cast<TagDecl>(D2))
363e5dd7070Spatrick if (T1->getFirstDecl() == T2->getFirstDecl())
364e5dd7070Spatrick return true;
365e5dd7070Spatrick return D1 == D2 || D1 == CanonicalizeDC(D2);
366e5dd7070Spatrick }
367e5dd7070Spatrick }
368e5dd7070Spatrick
MaybeRecordOrigin(const DeclContext * ToDC,DCOrigin Origin)369e5dd7070Spatrick void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC,
370e5dd7070Spatrick DCOrigin Origin) {
371e5dd7070Spatrick LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
372e5dd7070Spatrick ASTImporter &Reverse = Importer.GetReverse();
373e5dd7070Spatrick Source<const DeclContext *> FoundFromDC =
374e5dd7070Spatrick LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);
375e5dd7070Spatrick const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);
376e5dd7070Spatrick if (DoRecord)
377e5dd7070Spatrick RecordOriginImpl(ToDC, Origin, Importer);
378e5dd7070Spatrick if (LoggingEnabled())
379e5dd7070Spatrick logs() << "(ExternalASTMerger*)" << (void*)this
380e5dd7070Spatrick << (DoRecord ? " decided " : " decided NOT")
381e5dd7070Spatrick << " to record origin (DeclContext*)" << (void*)Origin.DC
382e5dd7070Spatrick << ", (ASTContext*)" << (void*)&Origin.AST
383e5dd7070Spatrick << "\n";
384e5dd7070Spatrick }
385e5dd7070Spatrick
ForceRecordOrigin(const DeclContext * ToDC,DCOrigin Origin)386e5dd7070Spatrick void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC,
387e5dd7070Spatrick DCOrigin Origin) {
388e5dd7070Spatrick RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));
389e5dd7070Spatrick }
390e5dd7070Spatrick
RecordOriginImpl(const DeclContext * ToDC,DCOrigin Origin,ASTImporter & Importer)391e5dd7070Spatrick void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
392e5dd7070Spatrick ASTImporter &Importer) {
393e5dd7070Spatrick Origins[ToDC] = Origin;
394e5dd7070Spatrick Importer.ASTImporter::MapImported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));
395e5dd7070Spatrick }
396e5dd7070Spatrick
ExternalASTMerger(const ImporterTarget & Target,llvm::ArrayRef<ImporterSource> Sources)397e5dd7070Spatrick ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,
398e5dd7070Spatrick llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {
399e5dd7070Spatrick SharedState = std::make_shared<ASTImporterSharedState>(
400e5dd7070Spatrick *Target.AST.getTranslationUnitDecl());
401e5dd7070Spatrick AddSources(Sources);
402e5dd7070Spatrick }
403e5dd7070Spatrick
FindOriginalDecl(Decl * D)404e5dd7070Spatrick Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) {
405e5dd7070Spatrick assert(&D->getASTContext() == &Target.AST);
406e5dd7070Spatrick for (const auto &I : Importers)
407e5dd7070Spatrick if (auto Result = I->GetOriginalDecl(D))
408e5dd7070Spatrick return Result;
409e5dd7070Spatrick return nullptr;
410e5dd7070Spatrick }
411e5dd7070Spatrick
AddSources(llvm::ArrayRef<ImporterSource> Sources)412e5dd7070Spatrick void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) {
413e5dd7070Spatrick for (const ImporterSource &S : Sources) {
414e5dd7070Spatrick assert(&S.getASTContext() != &Target.AST);
415e5dd7070Spatrick // Check that the associated merger actually imports into the source AST.
416e5dd7070Spatrick assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext());
417e5dd7070Spatrick Importers.push_back(std::make_unique<LazyASTImporter>(
418e5dd7070Spatrick *this, Target.AST, Target.FM, S, SharedState));
419e5dd7070Spatrick }
420e5dd7070Spatrick }
421e5dd7070Spatrick
RemoveSources(llvm::ArrayRef<ImporterSource> Sources)422e5dd7070Spatrick void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
423e5dd7070Spatrick if (LoggingEnabled())
424e5dd7070Spatrick for (const ImporterSource &S : Sources)
425e5dd7070Spatrick logs() << "(ExternalASTMerger*)" << (void *)this
426e5dd7070Spatrick << " removing source (ASTContext*)" << (void *)&S.getASTContext()
427e5dd7070Spatrick << "\n";
428*12c85518Srobert llvm::erase_if(Importers,
429e5dd7070Spatrick [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {
430e5dd7070Spatrick for (const ImporterSource &S : Sources) {
431e5dd7070Spatrick if (&Importer->getFromContext() == &S.getASTContext())
432e5dd7070Spatrick return true;
433e5dd7070Spatrick }
434e5dd7070Spatrick return false;
435*12c85518Srobert });
436e5dd7070Spatrick for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {
437e5dd7070Spatrick std::pair<const DeclContext *, DCOrigin> Origin = *OI;
438e5dd7070Spatrick bool Erase = false;
439e5dd7070Spatrick for (const ImporterSource &S : Sources) {
440e5dd7070Spatrick if (&S.getASTContext() == Origin.second.AST) {
441e5dd7070Spatrick Erase = true;
442e5dd7070Spatrick break;
443e5dd7070Spatrick }
444e5dd7070Spatrick }
445e5dd7070Spatrick if (Erase)
446e5dd7070Spatrick OI = Origins.erase(OI);
447e5dd7070Spatrick else
448e5dd7070Spatrick ++OI;
449e5dd7070Spatrick }
450e5dd7070Spatrick }
451e5dd7070Spatrick
452e5dd7070Spatrick template <typename DeclTy>
importSpecializations(DeclTy * D,ASTImporter * Importer)453e5dd7070Spatrick static bool importSpecializations(DeclTy *D, ASTImporter *Importer) {
454e5dd7070Spatrick for (auto *Spec : D->specializations()) {
455e5dd7070Spatrick auto ImportedSpecOrError = Importer->Import(Spec);
456e5dd7070Spatrick if (!ImportedSpecOrError) {
457e5dd7070Spatrick llvm::consumeError(ImportedSpecOrError.takeError());
458e5dd7070Spatrick return true;
459e5dd7070Spatrick }
460e5dd7070Spatrick }
461e5dd7070Spatrick return false;
462e5dd7070Spatrick }
463e5dd7070Spatrick
464e5dd7070Spatrick /// Imports specializations from template declarations that can be specialized.
importSpecializationsIfNeeded(Decl * D,ASTImporter * Importer)465e5dd7070Spatrick static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) {
466e5dd7070Spatrick if (!isa<TemplateDecl>(D))
467e5dd7070Spatrick return false;
468e5dd7070Spatrick if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D))
469e5dd7070Spatrick return importSpecializations(FunctionTD, Importer);
470e5dd7070Spatrick else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D))
471e5dd7070Spatrick return importSpecializations(ClassTD, Importer);
472e5dd7070Spatrick else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D))
473e5dd7070Spatrick return importSpecializations(VarTD, Importer);
474e5dd7070Spatrick return false;
475e5dd7070Spatrick }
476e5dd7070Spatrick
FindExternalVisibleDeclsByName(const DeclContext * DC,DeclarationName Name)477e5dd7070Spatrick bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
478e5dd7070Spatrick DeclarationName Name) {
479e5dd7070Spatrick llvm::SmallVector<NamedDecl *, 1> Decls;
480e5dd7070Spatrick llvm::SmallVector<Candidate, 4> Candidates;
481e5dd7070Spatrick
482e5dd7070Spatrick auto FilterFoundDecl = [&Candidates](const Candidate &C) {
483e5dd7070Spatrick if (!HasDeclOfSameType(Candidates, C))
484e5dd7070Spatrick Candidates.push_back(C);
485e5dd7070Spatrick };
486e5dd7070Spatrick
487e5dd7070Spatrick ForEachMatchingDC(DC,
488e5dd7070Spatrick [&](ASTImporter &Forward, ASTImporter &Reverse,
489e5dd7070Spatrick Source<const DeclContext *> SourceDC) -> bool {
490e5dd7070Spatrick auto FromNameOrErr = Reverse.Import(Name);
491e5dd7070Spatrick if (!FromNameOrErr) {
492e5dd7070Spatrick llvm::consumeError(FromNameOrErr.takeError());
493e5dd7070Spatrick return false;
494e5dd7070Spatrick }
495e5dd7070Spatrick DeclContextLookupResult Result =
496e5dd7070Spatrick SourceDC.get()->lookup(*FromNameOrErr);
497e5dd7070Spatrick for (NamedDecl *FromD : Result) {
498e5dd7070Spatrick FilterFoundDecl(std::make_pair(FromD, &Forward));
499e5dd7070Spatrick }
500e5dd7070Spatrick return false;
501e5dd7070Spatrick });
502e5dd7070Spatrick
503e5dd7070Spatrick if (Candidates.empty())
504e5dd7070Spatrick return false;
505e5dd7070Spatrick
506e5dd7070Spatrick Decls.reserve(Candidates.size());
507e5dd7070Spatrick for (const Candidate &C : Candidates) {
508e5dd7070Spatrick Decl *LookupRes = C.first.get();
509e5dd7070Spatrick ASTImporter *Importer = C.second;
510e5dd7070Spatrick auto NDOrErr = Importer->Import(LookupRes);
511e5dd7070Spatrick NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr)));
512e5dd7070Spatrick assert(ND);
513e5dd7070Spatrick // If we don't import specialization, they are not available via lookup
514e5dd7070Spatrick // because the lookup result is imported TemplateDecl and it does not
515e5dd7070Spatrick // reference its specializations until they are imported explicitly.
516e5dd7070Spatrick bool IsSpecImportFailed =
517e5dd7070Spatrick importSpecializationsIfNeeded(LookupRes, Importer);
518e5dd7070Spatrick assert(!IsSpecImportFailed);
519e5dd7070Spatrick (void)IsSpecImportFailed;
520e5dd7070Spatrick Decls.push_back(ND);
521e5dd7070Spatrick }
522e5dd7070Spatrick SetExternalVisibleDeclsForName(DC, Name, Decls);
523e5dd7070Spatrick return true;
524e5dd7070Spatrick }
525e5dd7070Spatrick
FindExternalLexicalDecls(const DeclContext * DC,llvm::function_ref<bool (Decl::Kind)> IsKindWeWant,SmallVectorImpl<Decl * > & Result)526e5dd7070Spatrick void ExternalASTMerger::FindExternalLexicalDecls(
527e5dd7070Spatrick const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
528e5dd7070Spatrick SmallVectorImpl<Decl *> &Result) {
529e5dd7070Spatrick ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
530e5dd7070Spatrick Source<const DeclContext *> SourceDC) -> bool {
531e5dd7070Spatrick for (const Decl *SourceDecl : SourceDC.get()->decls()) {
532e5dd7070Spatrick if (IsKindWeWant(SourceDecl->getKind())) {
533e5dd7070Spatrick auto ImportedDeclOrErr = Forward.Import(SourceDecl);
534e5dd7070Spatrick if (ImportedDeclOrErr)
535e5dd7070Spatrick assert(!(*ImportedDeclOrErr) ||
536e5dd7070Spatrick IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC));
537e5dd7070Spatrick else
538e5dd7070Spatrick llvm::consumeError(ImportedDeclOrErr.takeError());
539e5dd7070Spatrick }
540e5dd7070Spatrick }
541e5dd7070Spatrick return false;
542e5dd7070Spatrick });
543e5dd7070Spatrick }
544e5dd7070Spatrick
545