1 //===- ExternalASTMerger.cpp - 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 implements the ExternalASTMerger, which vends a combination of
10 // ASTs from several different ASTContext/FileManager pairs
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/ASTContext.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/DeclObjC.h"
18 #include "clang/AST/DeclTemplate.h"
19 #include "clang/AST/ExternalASTMerger.h"
21 using namespace clang
;
25 template <typename T
> struct Source
{
28 operator T() { return t
; }
29 template <typename U
= T
> U
&get() { return t
; }
30 template <typename U
= T
> const U
&get() const { return t
; }
31 template <typename U
> operator Source
<U
>() { return Source
<U
>(t
); }
34 typedef std::pair
<Source
<NamedDecl
*>, ASTImporter
*> Candidate
;
36 /// For the given DC, return the DC that is safe to perform lookups on. This is
37 /// the DC we actually want to work with most of the time.
38 const DeclContext
*CanonicalizeDC(const DeclContext
*DC
) {
39 if (isa
<LinkageSpecDecl
>(DC
))
40 return DC
->getRedeclContext();
44 Source
<const DeclContext
*>
45 LookupSameContext(Source
<TranslationUnitDecl
*> SourceTU
, const DeclContext
*DC
,
46 ASTImporter
&ReverseImporter
) {
47 DC
= CanonicalizeDC(DC
);
48 if (DC
->isTranslationUnit()) {
51 Source
<const DeclContext
*> SourceParentDC
=
52 LookupSameContext(SourceTU
, DC
->getParent(), ReverseImporter
);
53 if (!SourceParentDC
) {
54 // If we couldn't find the parent DC in this TranslationUnit, give up.
57 auto *ND
= cast
<NamedDecl
>(DC
);
58 DeclarationName Name
= ND
->getDeclName();
59 auto SourceNameOrErr
= ReverseImporter
.Import(Name
);
60 if (!SourceNameOrErr
) {
61 llvm::consumeError(SourceNameOrErr
.takeError());
64 Source
<DeclarationName
> SourceName
= *SourceNameOrErr
;
65 DeclContext::lookup_result SearchResult
=
66 SourceParentDC
.get()->lookup(SourceName
.get());
68 // There are two cases here. First, we might not find the name.
69 // We might also find multiple copies, in which case we have no
70 // guarantee that the one we wanted is the one we pick. (E.g.,
71 // if we have two specializations of the same template it is
72 // very hard to determine which is the one you want.)
74 // The Origins map fixes this problem by allowing the origin to be
75 // explicitly recorded, so we trigger that recording by returning
76 // nothing (rather than a possibly-inaccurate guess) here.
77 if (SearchResult
.isSingleResult()) {
78 NamedDecl
*SearchResultDecl
= SearchResult
.front();
79 if (isa
<DeclContext
>(SearchResultDecl
) &&
80 SearchResultDecl
->getKind() == DC
->getDeclKind())
81 return cast
<DeclContext
>(SearchResultDecl
)->getPrimaryContext();
82 return nullptr; // This type of lookup is unsupported
88 /// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.
90 /// There are several modifications:
92 /// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few
93 /// others), which instructs Clang to refer to ExternalASTMerger. Also, it
94 /// forces MinimalImport to true, which is necessary to make this work.
95 /// - It maintains a reverse importer for use with names. This allows lookup of
96 /// arbitrary names in the source context.
97 /// - It updates the ExternalASTMerger's origin map as needed whenever a
98 /// it sees a DeclContext.
99 class LazyASTImporter
: public ASTImporter
{
101 ExternalASTMerger
&Parent
;
103 const ExternalASTMerger::OriginMap
&FromOrigins
;
104 /// @see ExternalASTMerger::ImporterSource::Temporary
105 bool TemporarySource
;
106 /// Map of imported declarations back to the declarations they originated
108 llvm::DenseMap
<Decl
*, Decl
*> ToOrigin
;
109 /// @see ExternalASTMerger::ImporterSource::Merger
110 ExternalASTMerger
*SourceMerger
;
111 llvm::raw_ostream
&logs() { return Parent
.logs(); }
113 LazyASTImporter(ExternalASTMerger
&_Parent
, ASTContext
&ToContext
,
114 FileManager
&ToFileManager
,
115 const ExternalASTMerger::ImporterSource
&S
,
116 std::shared_ptr
<ASTImporterSharedState
> SharedState
)
117 : ASTImporter(ToContext
, ToFileManager
, S
.getASTContext(),
119 /*MinimalImport=*/true, SharedState
),
121 Reverse(S
.getASTContext(), S
.getFileManager(), ToContext
, ToFileManager
,
122 /*MinimalImport=*/true),
123 FromOrigins(S
.getOriginMap()), TemporarySource(S
.isTemporary()),
124 SourceMerger(S
.getMerger()) {}
126 llvm::Expected
<Decl
*> ImportImpl(Decl
*FromD
) override
{
127 if (!TemporarySource
|| !SourceMerger
)
128 return ASTImporter::ImportImpl(FromD
);
130 // If we get here, then this source is importing from a temporary ASTContext
131 // that also has another ExternalASTMerger attached. It could be
132 // possible that the current ExternalASTMerger and the temporary ASTContext
133 // share a common ImporterSource, which means that the temporary
134 // AST could contain declarations that were imported from a source
135 // that this ExternalASTMerger can access directly. Instead of importing
136 // such declarations from the temporary ASTContext, they should instead
137 // be directly imported by this ExternalASTMerger from the original
138 // source. This way the ExternalASTMerger can safely do a minimal import
139 // without creating incomplete declarations originated from a temporary
140 // ASTContext. If we would try to complete such declarations later on, we
141 // would fail to do so as their temporary AST could be deleted (which means
142 // that the missing parts of the minimally imported declaration in that
143 // ASTContext were also deleted).
145 // The following code tracks back any declaration that needs to be
146 // imported from the temporary ASTContext to a persistent ASTContext.
147 // Then the ExternalASTMerger tries to import from the persistent
148 // ASTContext directly by using the associated ASTImporter. If that
149 // succeeds, this ASTImporter just maps the declarations imported by
150 // the other (persistent) ASTImporter to this (temporary) ASTImporter.
151 // The steps can be visualized like this:
153 // Target AST <--- 3. Indirect import --- Persistent AST
154 // ^ of persistent decl ^
156 // 1. Current import 2. Tracking back to persistent decl
157 // 4. Map persistent decl |
158 // & pretend we imported. |
160 // Temporary AST -------------------------------'
162 // First, ask the ExternalASTMerger of the source where the temporary
163 // declaration originated from.
164 Decl
*Persistent
= SourceMerger
->FindOriginalDecl(FromD
);
165 // FromD isn't from a persistent AST, so just do a normal import.
167 return ASTImporter::ImportImpl(FromD
);
168 // Now ask the current ExternalASTMerger to try import the persistent
169 // declaration into the target.
170 ASTContext
&PersistentCtx
= Persistent
->getASTContext();
171 ASTImporter
&OtherImporter
= Parent
.ImporterForOrigin(PersistentCtx
);
172 // Check that we never end up in the current Importer again.
173 assert((&PersistentCtx
!= &getFromContext()) && (&OtherImporter
!= this) &&
174 "Delegated to same Importer?");
175 auto DeclOrErr
= OtherImporter
.Import(Persistent
);
176 // Errors when importing the persistent decl are treated as if we
177 // had errors with importing the temporary decl.
179 return DeclOrErr
.takeError();
180 Decl
*D
= *DeclOrErr
;
181 // Tell the current ASTImporter that this has already been imported
182 // to prevent any further queries for the temporary decl.
183 MapImported(FromD
, D
);
187 /// Implements the ASTImporter interface for tracking back a declaration
188 /// to its original declaration it came from.
189 Decl
*GetOriginalDecl(Decl
*To
) override
{
190 auto It
= ToOrigin
.find(To
);
191 if (It
!= ToOrigin
.end())
196 /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
197 /// map is kept up to date. Also set the appropriate flags.
198 void Imported(Decl
*From
, Decl
*To
) override
{
201 if (auto *ToDC
= dyn_cast
<DeclContext
>(To
)) {
202 const bool LoggingEnabled
= Parent
.LoggingEnabled();
204 logs() << "(ExternalASTMerger*)" << (void*)&Parent
205 << " imported (DeclContext*)" << (void*)ToDC
206 << ", (ASTContext*)" << (void*)&getToContext()
207 << " from (DeclContext*)" << (void*)llvm::cast
<DeclContext
>(From
)
208 << ", (ASTContext*)" << (void*)&getFromContext()
210 Source
<DeclContext
*> FromDC(
211 cast
<DeclContext
>(From
)->getPrimaryContext());
212 if (FromOrigins
.count(FromDC
) &&
213 Parent
.HasImporterForOrigin(*FromOrigins
.at(FromDC
).AST
)) {
215 logs() << "(ExternalASTMerger*)" << (void*)&Parent
216 << " forced origin (DeclContext*)"
217 << (void*)FromOrigins
.at(FromDC
).DC
219 << (void*)FromOrigins
.at(FromDC
).AST
221 Parent
.ForceRecordOrigin(ToDC
, FromOrigins
.at(FromDC
));
224 logs() << "(ExternalASTMerger*)" << (void*)&Parent
225 << " maybe recording origin (DeclContext*)" << (void*)FromDC
226 << ", (ASTContext*)" << (void*)&getFromContext()
228 Parent
.MaybeRecordOrigin(ToDC
, {FromDC
, &getFromContext()});
231 if (auto *ToTag
= dyn_cast
<TagDecl
>(To
)) {
232 ToTag
->setHasExternalLexicalStorage();
233 ToTag
->getPrimaryContext()->setMustBuildLookupTable();
234 assert(Parent
.CanComplete(ToTag
));
235 } else if (auto *ToNamespace
= dyn_cast
<NamespaceDecl
>(To
)) {
236 ToNamespace
->setHasExternalVisibleStorage();
237 assert(Parent
.CanComplete(ToNamespace
));
238 } else if (auto *ToContainer
= dyn_cast
<ObjCContainerDecl
>(To
)) {
239 ToContainer
->setHasExternalLexicalStorage();
240 ToContainer
->getPrimaryContext()->setMustBuildLookupTable();
241 assert(Parent
.CanComplete(ToContainer
));
244 ASTImporter
&GetReverse() { return Reverse
; }
247 bool HasDeclOfSameType(llvm::ArrayRef
<Candidate
> Decls
, const Candidate
&C
) {
248 if (isa
<FunctionDecl
>(C
.first
.get()))
250 return llvm::any_of(Decls
, [&](const Candidate
&D
) {
251 return C
.first
.get()->getKind() == D
.first
.get()->getKind();
257 ASTImporter
&ExternalASTMerger::ImporterForOrigin(ASTContext
&OriginContext
) {
258 for (const std::unique_ptr
<ASTImporter
> &I
: Importers
)
259 if (&I
->getFromContext() == &OriginContext
)
261 llvm_unreachable("We should have an importer for this origin!");
265 LazyASTImporter
&LazyImporterForOrigin(ExternalASTMerger
&Merger
,
266 ASTContext
&OriginContext
) {
267 return static_cast<LazyASTImporter
&>(
268 Merger
.ImporterForOrigin(OriginContext
));
272 bool ExternalASTMerger::HasImporterForOrigin(ASTContext
&OriginContext
) {
273 for (const std::unique_ptr
<ASTImporter
> &I
: Importers
)
274 if (&I
->getFromContext() == &OriginContext
)
279 template <typename CallbackType
>
280 void ExternalASTMerger::ForEachMatchingDC(const DeclContext
*DC
,
281 CallbackType Callback
) {
282 if (Origins
.count(DC
)) {
283 ExternalASTMerger::DCOrigin Origin
= Origins
[DC
];
284 LazyASTImporter
&Importer
= LazyImporterForOrigin(*this, *Origin
.AST
);
285 Callback(Importer
, Importer
.GetReverse(), Origin
.DC
);
287 bool DidCallback
= false;
288 for (const std::unique_ptr
<ASTImporter
> &Importer
: Importers
) {
289 Source
<TranslationUnitDecl
*> SourceTU
=
290 Importer
->getFromContext().getTranslationUnitDecl();
291 ASTImporter
&Reverse
=
292 static_cast<LazyASTImporter
*>(Importer
.get())->GetReverse();
293 if (auto SourceDC
= LookupSameContext(SourceTU
, DC
, Reverse
)) {
295 if (Callback(*Importer
, Reverse
, SourceDC
))
299 if (!DidCallback
&& LoggingEnabled())
300 logs() << "(ExternalASTMerger*)" << (void*)this
301 << " asserting for (DeclContext*)" << (const void*)DC
302 << ", (ASTContext*)" << (void*)&Target
.AST
304 assert(DidCallback
&& "Couldn't find a source context matching our DC");
308 void ExternalASTMerger::CompleteType(TagDecl
*Tag
) {
309 assert(Tag
->hasExternalLexicalStorage());
310 ForEachMatchingDC(Tag
, [&](ASTImporter
&Forward
, ASTImporter
&Reverse
,
311 Source
<const DeclContext
*> SourceDC
) -> bool {
312 auto *SourceTag
= const_cast<TagDecl
*>(cast
<TagDecl
>(SourceDC
.get()));
313 if (SourceTag
->hasExternalLexicalStorage())
314 SourceTag
->getASTContext().getExternalSource()->CompleteType(SourceTag
);
315 if (!SourceTag
->getDefinition())
317 Forward
.MapImported(SourceTag
, Tag
);
318 if (llvm::Error Err
= Forward
.ImportDefinition(SourceTag
))
319 llvm::consumeError(std::move(Err
));
320 Tag
->setCompleteDefinition(SourceTag
->isCompleteDefinition());
325 void ExternalASTMerger::CompleteType(ObjCInterfaceDecl
*Interface
) {
326 assert(Interface
->hasExternalLexicalStorage());
328 Interface
, [&](ASTImporter
&Forward
, ASTImporter
&Reverse
,
329 Source
<const DeclContext
*> SourceDC
) -> bool {
330 auto *SourceInterface
= const_cast<ObjCInterfaceDecl
*>(
331 cast
<ObjCInterfaceDecl
>(SourceDC
.get()));
332 if (SourceInterface
->hasExternalLexicalStorage())
333 SourceInterface
->getASTContext().getExternalSource()->CompleteType(
335 if (!SourceInterface
->getDefinition())
337 Forward
.MapImported(SourceInterface
, Interface
);
338 if (llvm::Error Err
= Forward
.ImportDefinition(SourceInterface
))
339 llvm::consumeError(std::move(Err
));
344 bool ExternalASTMerger::CanComplete(DeclContext
*Interface
) {
345 assert(Interface
->hasExternalLexicalStorage() ||
346 Interface
->hasExternalVisibleStorage());
347 bool FoundMatchingDC
= false;
348 ForEachMatchingDC(Interface
,
349 [&](ASTImporter
&Forward
, ASTImporter
&Reverse
,
350 Source
<const DeclContext
*> SourceDC
) -> bool {
351 FoundMatchingDC
= true;
354 return FoundMatchingDC
;
358 bool IsSameDC(const DeclContext
*D1
, const DeclContext
*D2
) {
359 if (isa
<ObjCContainerDecl
>(D1
) && isa
<ObjCContainerDecl
>(D2
))
360 return true; // There are many cases where Objective-C is ambiguous.
361 if (auto *T1
= dyn_cast
<TagDecl
>(D1
))
362 if (auto *T2
= dyn_cast
<TagDecl
>(D2
))
363 if (T1
->getFirstDecl() == T2
->getFirstDecl())
365 return D1
== D2
|| D1
== CanonicalizeDC(D2
);
369 void ExternalASTMerger::MaybeRecordOrigin(const DeclContext
*ToDC
,
371 LazyASTImporter
&Importer
= LazyImporterForOrigin(*this, *Origin
.AST
);
372 ASTImporter
&Reverse
= Importer
.GetReverse();
373 Source
<const DeclContext
*> FoundFromDC
=
374 LookupSameContext(Origin
.AST
->getTranslationUnitDecl(), ToDC
, Reverse
);
375 const bool DoRecord
= !FoundFromDC
|| !IsSameDC(FoundFromDC
.get(), Origin
.DC
);
377 RecordOriginImpl(ToDC
, Origin
, Importer
);
378 if (LoggingEnabled())
379 logs() << "(ExternalASTMerger*)" << (void*)this
380 << (DoRecord
? " decided " : " decided NOT")
381 << " to record origin (DeclContext*)" << (void*)Origin
.DC
382 << ", (ASTContext*)" << (void*)&Origin
.AST
386 void ExternalASTMerger::ForceRecordOrigin(const DeclContext
*ToDC
,
388 RecordOriginImpl(ToDC
, Origin
, ImporterForOrigin(*Origin
.AST
));
391 void ExternalASTMerger::RecordOriginImpl(const DeclContext
*ToDC
, DCOrigin Origin
,
392 ASTImporter
&Importer
) {
393 Origins
[ToDC
] = Origin
;
394 Importer
.ASTImporter::MapImported(cast
<Decl
>(Origin
.DC
), const_cast<Decl
*>(cast
<Decl
>(ToDC
)));
397 ExternalASTMerger::ExternalASTMerger(const ImporterTarget
&Target
,
398 llvm::ArrayRef
<ImporterSource
> Sources
) : LogStream(&llvm::nulls()), Target(Target
) {
399 SharedState
= std::make_shared
<ASTImporterSharedState
>(
400 *Target
.AST
.getTranslationUnitDecl());
404 Decl
*ExternalASTMerger::FindOriginalDecl(Decl
*D
) {
405 assert(&D
->getASTContext() == &Target
.AST
);
406 for (const auto &I
: Importers
)
407 if (auto Result
= I
->GetOriginalDecl(D
))
412 void ExternalASTMerger::AddSources(llvm::ArrayRef
<ImporterSource
> Sources
) {
413 for (const ImporterSource
&S
: Sources
) {
414 assert(&S
.getASTContext() != &Target
.AST
);
415 // Check that the associated merger actually imports into the source AST.
416 assert(!S
.getMerger() || &S
.getMerger()->Target
.AST
== &S
.getASTContext());
417 Importers
.push_back(std::make_unique
<LazyASTImporter
>(
418 *this, Target
.AST
, Target
.FM
, S
, SharedState
));
422 void ExternalASTMerger::RemoveSources(llvm::ArrayRef
<ImporterSource
> Sources
) {
423 if (LoggingEnabled())
424 for (const ImporterSource
&S
: Sources
)
425 logs() << "(ExternalASTMerger*)" << (void *)this
426 << " removing source (ASTContext*)" << (void *)&S
.getASTContext()
428 llvm::erase_if(Importers
,
429 [&Sources
](std::unique_ptr
<ASTImporter
> &Importer
) -> bool {
430 for (const ImporterSource
&S
: Sources
) {
431 if (&Importer
->getFromContext() == &S
.getASTContext())
436 for (OriginMap::iterator OI
= Origins
.begin(), OE
= Origins
.end(); OI
!= OE
; ) {
437 std::pair
<const DeclContext
*, DCOrigin
> Origin
= *OI
;
439 for (const ImporterSource
&S
: Sources
) {
440 if (&S
.getASTContext() == Origin
.second
.AST
) {
446 OI
= Origins
.erase(OI
);
452 template <typename DeclTy
>
453 static bool importSpecializations(DeclTy
*D
, ASTImporter
*Importer
) {
454 for (auto *Spec
: D
->specializations()) {
455 auto ImportedSpecOrError
= Importer
->Import(Spec
);
456 if (!ImportedSpecOrError
) {
457 llvm::consumeError(ImportedSpecOrError
.takeError());
464 /// Imports specializations from template declarations that can be specialized.
465 static bool importSpecializationsIfNeeded(Decl
*D
, ASTImporter
*Importer
) {
466 if (!isa
<TemplateDecl
>(D
))
468 if (auto *FunctionTD
= dyn_cast
<FunctionTemplateDecl
>(D
))
469 return importSpecializations(FunctionTD
, Importer
);
470 else if (auto *ClassTD
= dyn_cast
<ClassTemplateDecl
>(D
))
471 return importSpecializations(ClassTD
, Importer
);
472 else if (auto *VarTD
= dyn_cast
<VarTemplateDecl
>(D
))
473 return importSpecializations(VarTD
, Importer
);
477 bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext
*DC
,
478 DeclarationName Name
) {
479 llvm::SmallVector
<NamedDecl
*, 1> Decls
;
480 llvm::SmallVector
<Candidate
, 4> Candidates
;
482 auto FilterFoundDecl
= [&Candidates
](const Candidate
&C
) {
483 if (!HasDeclOfSameType(Candidates
, C
))
484 Candidates
.push_back(C
);
487 ForEachMatchingDC(DC
,
488 [&](ASTImporter
&Forward
, ASTImporter
&Reverse
,
489 Source
<const DeclContext
*> SourceDC
) -> bool {
490 auto FromNameOrErr
= Reverse
.Import(Name
);
491 if (!FromNameOrErr
) {
492 llvm::consumeError(FromNameOrErr
.takeError());
495 DeclContextLookupResult Result
=
496 SourceDC
.get()->lookup(*FromNameOrErr
);
497 for (NamedDecl
*FromD
: Result
) {
498 FilterFoundDecl(std::make_pair(FromD
, &Forward
));
503 if (Candidates
.empty())
506 Decls
.reserve(Candidates
.size());
507 for (const Candidate
&C
: Candidates
) {
508 Decl
*LookupRes
= C
.first
.get();
509 ASTImporter
*Importer
= C
.second
;
510 auto NDOrErr
= Importer
->Import(LookupRes
);
511 NamedDecl
*ND
= cast
<NamedDecl
>(llvm::cantFail(std::move(NDOrErr
)));
513 // If we don't import specialization, they are not available via lookup
514 // because the lookup result is imported TemplateDecl and it does not
515 // reference its specializations until they are imported explicitly.
516 bool IsSpecImportFailed
=
517 importSpecializationsIfNeeded(LookupRes
, Importer
);
518 assert(!IsSpecImportFailed
);
519 (void)IsSpecImportFailed
;
522 SetExternalVisibleDeclsForName(DC
, Name
, Decls
);
526 void ExternalASTMerger::FindExternalLexicalDecls(
527 const DeclContext
*DC
, llvm::function_ref
<bool(Decl::Kind
)> IsKindWeWant
,
528 SmallVectorImpl
<Decl
*> &Result
) {
529 ForEachMatchingDC(DC
, [&](ASTImporter
&Forward
, ASTImporter
&Reverse
,
530 Source
<const DeclContext
*> SourceDC
) -> bool {
531 for (const Decl
*SourceDecl
: SourceDC
.get()->decls()) {
532 if (IsKindWeWant(SourceDecl
->getKind())) {
533 auto ImportedDeclOrErr
= Forward
.Import(SourceDecl
);
534 if (ImportedDeclOrErr
)
535 assert(!(*ImportedDeclOrErr
) ||
536 IsSameDC((*ImportedDeclOrErr
)->getDeclContext(), DC
));
538 llvm::consumeError(ImportedDeclOrErr
.takeError());