diff options
Diffstat (limited to 'lib/AST/ExternalASTMerger.cpp')
| -rw-r--r-- | lib/AST/ExternalASTMerger.cpp | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp deleted file mode 100644 index f678c2dd3b59e..0000000000000 --- a/lib/AST/ExternalASTMerger.cpp +++ /dev/null @@ -1,548 +0,0 @@ -//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the ExternalASTMerger, which vends a combination of -// ASTs from several different ASTContext/FileManager pairs -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/ExternalASTMerger.h" - -using namespace clang; - -namespace { - -template <typename T> struct Source { - T t; - Source(T t) : t(t) {} - operator T() { return t; } - template <typename U = T> U &get() { return t; } - template <typename U = T> const U &get() const { return t; } - template <typename U> operator Source<U>() { return Source<U>(t); } -}; - -typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate; - -/// For the given DC, return the DC that is safe to perform lookups on. This is -/// the DC we actually want to work with most of the time. -const DeclContext *CanonicalizeDC(const DeclContext *DC) { - if (isa<LinkageSpecDecl>(DC)) - return DC->getRedeclContext(); - return DC; -} - -Source<const DeclContext *> -LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, - ASTImporter &ReverseImporter) { - DC = CanonicalizeDC(DC); - if (DC->isTranslationUnit()) { - return SourceTU; - } - Source<const DeclContext *> SourceParentDC = - LookupSameContext(SourceTU, DC->getParent(), ReverseImporter); - if (!SourceParentDC) { - // If we couldn't find the parent DC in this TranslationUnit, give up. - return nullptr; - } - auto *ND = cast<NamedDecl>(DC); - DeclarationName Name = ND->getDeclName(); - auto SourceNameOrErr = ReverseImporter.Import(Name); - if (!SourceNameOrErr) { - llvm::consumeError(SourceNameOrErr.takeError()); - return nullptr; - } - Source<DeclarationName> SourceName = *SourceNameOrErr; - DeclContext::lookup_result SearchResult = - SourceParentDC.get()->lookup(SourceName.get()); - size_t SearchResultSize = SearchResult.size(); - if (SearchResultSize == 0 || SearchResultSize > 1) { - // There are two cases here. First, we might not find the name. - // We might also find multiple copies, in which case we have no - // guarantee that the one we wanted is the one we pick. (E.g., - // if we have two specializations of the same template it is - // very hard to determine which is the one you want.) - // - // The Origins map fixes this problem by allowing the origin to be - // explicitly recorded, so we trigger that recording by returning - // nothing (rather than a possibly-inaccurate guess) here. - return nullptr; - } else { - NamedDecl *SearchResultDecl = SearchResult[0]; - if (isa<DeclContext>(SearchResultDecl) && - SearchResultDecl->getKind() == DC->getDeclKind()) - return cast<DeclContext>(SearchResultDecl)->getPrimaryContext(); - return nullptr; // This type of lookup is unsupported - } -} - -/// A custom implementation of ASTImporter, for ExternalASTMerger's purposes. -/// -/// There are several modifications: -/// -/// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few -/// others), which instructs Clang to refer to ExternalASTMerger. Also, it -/// forces MinimalImport to true, which is necessary to make this work. -/// - It maintains a reverse importer for use with names. This allows lookup of -/// arbitrary names in the source context. -/// - It updates the ExternalASTMerger's origin map as needed whenever a -/// it sees a DeclContext. -class LazyASTImporter : public ASTImporter { -private: - ExternalASTMerger &Parent; - ASTImporter Reverse; - const ExternalASTMerger::OriginMap &FromOrigins; - /// @see ExternalASTMerger::ImporterSource::Temporary - bool TemporarySource; - /// Map of imported declarations back to the declarations they originated - /// from. - llvm::DenseMap<Decl *, Decl *> ToOrigin; - /// @see ExternalASTMerger::ImporterSource::Merger - ExternalASTMerger *SourceMerger; - llvm::raw_ostream &logs() { return Parent.logs(); } -public: - LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext, - FileManager &ToFileManager, - const ExternalASTMerger::ImporterSource &S, - std::shared_ptr<ASTImporterSharedState> SharedState) - : ASTImporter(ToContext, ToFileManager, S.getASTContext(), - S.getFileManager(), - /*MinimalImport=*/true, SharedState), - Parent(_Parent), - Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager, - /*MinimalImport=*/true), - FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()), - SourceMerger(S.getMerger()) {} - - llvm::Expected<Decl *> ImportImpl(Decl *FromD) override { - if (!TemporarySource || !SourceMerger) - return ASTImporter::ImportImpl(FromD); - - // If we get here, then this source is importing from a temporary ASTContext - // that also has another ExternalASTMerger attached. It could be - // possible that the current ExternalASTMerger and the temporary ASTContext - // share a common ImporterSource, which means that the temporary - // AST could contain declarations that were imported from a source - // that this ExternalASTMerger can access directly. Instead of importing - // such declarations from the temporary ASTContext, they should instead - // be directly imported by this ExternalASTMerger from the original - // source. This way the ExternalASTMerger can safely do a minimal import - // without creating incomplete declarations originated from a temporary - // ASTContext. If we would try to complete such declarations later on, we - // would fail to do so as their temporary AST could be deleted (which means - // that the missing parts of the minimally imported declaration in that - // ASTContext were also deleted). - // - // The following code tracks back any declaration that needs to be - // imported from the temporary ASTContext to a persistent ASTContext. - // Then the ExternalASTMerger tries to import from the persistent - // ASTContext directly by using the associated ASTImporter. If that - // succeeds, this ASTImporter just maps the declarations imported by - // the other (persistent) ASTImporter to this (temporary) ASTImporter. - // The steps can be visualized like this: - // - // Target AST <--- 3. Indirect import --- Persistent AST - // ^ of persistent decl ^ - // | | - // 1. Current import 2. Tracking back to persistent decl - // 4. Map persistent decl | - // & pretend we imported. | - // | | - // Temporary AST -------------------------------' - - // First, ask the ExternalASTMerger of the source where the temporary - // declaration originated from. - Decl *Persistent = SourceMerger->FindOriginalDecl(FromD); - // FromD isn't from a persistent AST, so just do a normal import. - if (!Persistent) - return ASTImporter::ImportImpl(FromD); - // Now ask the current ExternalASTMerger to try import the persistent - // declaration into the target. - ASTContext &PersistentCtx = Persistent->getASTContext(); - ASTImporter &OtherImporter = Parent.ImporterForOrigin(PersistentCtx); - // Check that we never end up in the current Importer again. - assert((&PersistentCtx != &getFromContext()) && (&OtherImporter != this) && - "Delegated to same Importer?"); - auto DeclOrErr = OtherImporter.Import(Persistent); - // Errors when importing the persistent decl are treated as if we - // had errors with importing the temporary decl. - if (!DeclOrErr) - return DeclOrErr.takeError(); - Decl *D = *DeclOrErr; - // Tell the current ASTImporter that this has already been imported - // to prevent any further queries for the temporary decl. - MapImported(FromD, D); - return D; - } - - /// Implements the ASTImporter interface for tracking back a declaration - /// to its original declaration it came from. - Decl *GetOriginalDecl(Decl *To) override { - auto It = ToOrigin.find(To); - if (It != ToOrigin.end()) - return It->second; - return nullptr; - } - - /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin - /// map is kept up to date. Also set the appropriate flags. - void Imported(Decl *From, Decl *To) override { - ToOrigin[To] = From; - - if (auto *ToDC = dyn_cast<DeclContext>(To)) { - const bool LoggingEnabled = Parent.LoggingEnabled(); - if (LoggingEnabled) - logs() << "(ExternalASTMerger*)" << (void*)&Parent - << " imported (DeclContext*)" << (void*)ToDC - << ", (ASTContext*)" << (void*)&getToContext() - << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From) - << ", (ASTContext*)" << (void*)&getFromContext() - << "\n"; - Source<DeclContext *> FromDC( - cast<DeclContext>(From)->getPrimaryContext()); - if (FromOrigins.count(FromDC) && - Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) { - if (LoggingEnabled) - logs() << "(ExternalASTMerger*)" << (void*)&Parent - << " forced origin (DeclContext*)" - << (void*)FromOrigins.at(FromDC).DC - << ", (ASTContext*)" - << (void*)FromOrigins.at(FromDC).AST - << "\n"; - Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC)); - } else { - if (LoggingEnabled) - logs() << "(ExternalASTMerger*)" << (void*)&Parent - << " maybe recording origin (DeclContext*)" << (void*)FromDC - << ", (ASTContext*)" << (void*)&getFromContext() - << "\n"; - Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()}); - } - } - if (auto *ToTag = dyn_cast<TagDecl>(To)) { - ToTag->setHasExternalLexicalStorage(); - ToTag->getPrimaryContext()->setMustBuildLookupTable(); - assert(Parent.CanComplete(ToTag)); - } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) { - ToNamespace->setHasExternalVisibleStorage(); - assert(Parent.CanComplete(ToNamespace)); - } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) { - ToContainer->setHasExternalLexicalStorage(); - ToContainer->getPrimaryContext()->setMustBuildLookupTable(); - assert(Parent.CanComplete(ToContainer)); - } - } - ASTImporter &GetReverse() { return Reverse; } -}; - -bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { - if (isa<FunctionDecl>(C.first.get())) - return false; - return llvm::any_of(Decls, [&](const Candidate &D) { - return C.first.get()->getKind() == D.first.get()->getKind(); - }); -} - -} // end namespace - -ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) { - for (const std::unique_ptr<ASTImporter> &I : Importers) - if (&I->getFromContext() == &OriginContext) - return *I; - llvm_unreachable("We should have an importer for this origin!"); -} - -namespace { -LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger, - ASTContext &OriginContext) { - return static_cast<LazyASTImporter &>( - Merger.ImporterForOrigin(OriginContext)); -} -} - -bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) { - for (const std::unique_ptr<ASTImporter> &I : Importers) - if (&I->getFromContext() == &OriginContext) - return true; - return false; -} - -template <typename CallbackType> -void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC, - CallbackType Callback) { - if (Origins.count(DC)) { - ExternalASTMerger::DCOrigin Origin = Origins[DC]; - LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); - Callback(Importer, Importer.GetReverse(), Origin.DC); - } else { - bool DidCallback = false; - for (const std::unique_ptr<ASTImporter> &Importer : Importers) { - Source<TranslationUnitDecl *> SourceTU = - Importer->getFromContext().getTranslationUnitDecl(); - ASTImporter &Reverse = - static_cast<LazyASTImporter *>(Importer.get())->GetReverse(); - if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) { - DidCallback = true; - if (Callback(*Importer, Reverse, SourceDC)) - break; - } - } - if (!DidCallback && LoggingEnabled()) - logs() << "(ExternalASTMerger*)" << (void*)this - << " asserting for (DeclContext*)" << (const void*)DC - << ", (ASTContext*)" << (void*)&Target.AST - << "\n"; - assert(DidCallback && "Couldn't find a source context matching our DC"); - } -} - -void ExternalASTMerger::CompleteType(TagDecl *Tag) { - assert(Tag->hasExternalLexicalStorage()); - ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse, - Source<const DeclContext *> SourceDC) -> bool { - auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get())); - if (SourceTag->hasExternalLexicalStorage()) - SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag); - if (!SourceTag->getDefinition()) - return false; - Forward.MapImported(SourceTag, Tag); - if (llvm::Error Err = Forward.ImportDefinition(SourceTag)) - llvm::consumeError(std::move(Err)); - Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); - return true; - }); -} - -void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) { - assert(Interface->hasExternalLexicalStorage()); - ForEachMatchingDC( - Interface, [&](ASTImporter &Forward, ASTImporter &Reverse, - Source<const DeclContext *> SourceDC) -> bool { - auto *SourceInterface = const_cast<ObjCInterfaceDecl *>( - cast<ObjCInterfaceDecl>(SourceDC.get())); - if (SourceInterface->hasExternalLexicalStorage()) - SourceInterface->getASTContext().getExternalSource()->CompleteType( - SourceInterface); - if (!SourceInterface->getDefinition()) - return false; - Forward.MapImported(SourceInterface, Interface); - if (llvm::Error Err = Forward.ImportDefinition(SourceInterface)) - llvm::consumeError(std::move(Err)); - return true; - }); -} - -bool ExternalASTMerger::CanComplete(DeclContext *Interface) { - assert(Interface->hasExternalLexicalStorage() || - Interface->hasExternalVisibleStorage()); - bool FoundMatchingDC = false; - ForEachMatchingDC(Interface, - [&](ASTImporter &Forward, ASTImporter &Reverse, - Source<const DeclContext *> SourceDC) -> bool { - FoundMatchingDC = true; - return true; - }); - return FoundMatchingDC; -} - -namespace { -bool IsSameDC(const DeclContext *D1, const DeclContext *D2) { - if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2)) - return true; // There are many cases where Objective-C is ambiguous. - if (auto *T1 = dyn_cast<TagDecl>(D1)) - if (auto *T2 = dyn_cast<TagDecl>(D2)) - if (T1->getFirstDecl() == T2->getFirstDecl()) - return true; - return D1 == D2 || D1 == CanonicalizeDC(D2); -} -} - -void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC, - DCOrigin Origin) { - LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); - ASTImporter &Reverse = Importer.GetReverse(); - Source<const DeclContext *> FoundFromDC = - LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse); - const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC); - if (DoRecord) - RecordOriginImpl(ToDC, Origin, Importer); - if (LoggingEnabled()) - logs() << "(ExternalASTMerger*)" << (void*)this - << (DoRecord ? " decided " : " decided NOT") - << " to record origin (DeclContext*)" << (void*)Origin.DC - << ", (ASTContext*)" << (void*)&Origin.AST - << "\n"; -} - -void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC, - DCOrigin Origin) { - RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST)); -} - -void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, - ASTImporter &Importer) { - Origins[ToDC] = Origin; - Importer.ASTImporter::MapImported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC))); -} - -ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target, - llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) { - SharedState = std::make_shared<ASTImporterSharedState>( - *Target.AST.getTranslationUnitDecl()); - AddSources(Sources); -} - -Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) { - assert(&D->getASTContext() == &Target.AST); - for (const auto &I : Importers) - if (auto Result = I->GetOriginalDecl(D)) - return Result; - return nullptr; -} - -void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) { - for (const ImporterSource &S : Sources) { - assert(&S.getASTContext() != &Target.AST); - // Check that the associated merger actually imports into the source AST. - assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext()); - Importers.push_back(std::make_unique<LazyASTImporter>( - *this, Target.AST, Target.FM, S, SharedState)); - } -} - -void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) { - if (LoggingEnabled()) - for (const ImporterSource &S : Sources) - logs() << "(ExternalASTMerger*)" << (void *)this - << " removing source (ASTContext*)" << (void *)&S.getASTContext() - << "\n"; - Importers.erase( - std::remove_if(Importers.begin(), Importers.end(), - [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool { - for (const ImporterSource &S : Sources) { - if (&Importer->getFromContext() == &S.getASTContext()) - return true; - } - return false; - }), - Importers.end()); - for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) { - std::pair<const DeclContext *, DCOrigin> Origin = *OI; - bool Erase = false; - for (const ImporterSource &S : Sources) { - if (&S.getASTContext() == Origin.second.AST) { - Erase = true; - break; - } - } - if (Erase) - OI = Origins.erase(OI); - else - ++OI; - } -} - -template <typename DeclTy> -static bool importSpecializations(DeclTy *D, ASTImporter *Importer) { - for (auto *Spec : D->specializations()) { - auto ImportedSpecOrError = Importer->Import(Spec); - if (!ImportedSpecOrError) { - llvm::consumeError(ImportedSpecOrError.takeError()); - return true; - } - } - return false; -} - -/// Imports specializations from template declarations that can be specialized. -static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) { - if (!isa<TemplateDecl>(D)) - return false; - if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D)) - return importSpecializations(FunctionTD, Importer); - else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D)) - return importSpecializations(ClassTD, Importer); - else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D)) - return importSpecializations(VarTD, Importer); - return false; -} - -bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, - DeclarationName Name) { - llvm::SmallVector<NamedDecl *, 1> Decls; - llvm::SmallVector<Candidate, 4> Candidates; - - auto FilterFoundDecl = [&Candidates](const Candidate &C) { - if (!HasDeclOfSameType(Candidates, C)) - Candidates.push_back(C); - }; - - ForEachMatchingDC(DC, - [&](ASTImporter &Forward, ASTImporter &Reverse, - Source<const DeclContext *> SourceDC) -> bool { - auto FromNameOrErr = Reverse.Import(Name); - if (!FromNameOrErr) { - llvm::consumeError(FromNameOrErr.takeError()); - return false; - } - DeclContextLookupResult Result = - SourceDC.get()->lookup(*FromNameOrErr); - for (NamedDecl *FromD : Result) { - FilterFoundDecl(std::make_pair(FromD, &Forward)); - } - return false; - }); - - if (Candidates.empty()) - return false; - - Decls.reserve(Candidates.size()); - for (const Candidate &C : Candidates) { - Decl *LookupRes = C.first.get(); - ASTImporter *Importer = C.second; - auto NDOrErr = Importer->Import(LookupRes); - assert(NDOrErr); - (void)static_cast<bool>(NDOrErr); - NamedDecl *ND = cast_or_null<NamedDecl>(*NDOrErr); - assert(ND); - // If we don't import specialization, they are not available via lookup - // because the lookup result is imported TemplateDecl and it does not - // reference its specializations until they are imported explicitly. - bool IsSpecImportFailed = - importSpecializationsIfNeeded(LookupRes, Importer); - assert(!IsSpecImportFailed); - (void)IsSpecImportFailed; - Decls.push_back(ND); - } - SetExternalVisibleDeclsForName(DC, Name, Decls); - return true; -} - -void ExternalASTMerger::FindExternalLexicalDecls( - const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, - SmallVectorImpl<Decl *> &Result) { - ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, - Source<const DeclContext *> SourceDC) -> bool { - for (const Decl *SourceDecl : SourceDC.get()->decls()) { - if (IsKindWeWant(SourceDecl->getKind())) { - auto ImportedDeclOrErr = Forward.Import(SourceDecl); - if (ImportedDeclOrErr) - assert(!(*ImportedDeclOrErr) || - IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC)); - else - llvm::consumeError(ImportedDeclOrErr.takeError()); - } - } - return false; - }); -} - |
