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