Path: blob/main/contrib/llvm-project/clang/lib/AST/ExternalASTMerger.cpp
35260 views
//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the ExternalASTMerger, which vends a combination of9// ASTs from several different ASTContext/FileManager pairs10//11//===----------------------------------------------------------------------===//1213#include "clang/AST/ASTContext.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclCXX.h"16#include "clang/AST/DeclObjC.h"17#include "clang/AST/DeclTemplate.h"18#include "clang/AST/ExternalASTMerger.h"1920using namespace clang;2122namespace {2324template <typename T> struct Source {25T t;26Source(T t) : t(t) {}27operator T() { return t; }28template <typename U = T> U &get() { return t; }29template <typename U = T> const U &get() const { return t; }30template <typename U> operator Source<U>() { return Source<U>(t); }31};3233typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;3435/// For the given DC, return the DC that is safe to perform lookups on. This is36/// the DC we actually want to work with most of the time.37const DeclContext *CanonicalizeDC(const DeclContext *DC) {38if (isa<LinkageSpecDecl>(DC))39return DC->getRedeclContext();40return DC;41}4243Source<const DeclContext *>44LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,45ASTImporter &ReverseImporter) {46DC = CanonicalizeDC(DC);47if (DC->isTranslationUnit()) {48return SourceTU;49}50Source<const DeclContext *> SourceParentDC =51LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);52if (!SourceParentDC) {53// If we couldn't find the parent DC in this TranslationUnit, give up.54return nullptr;55}56auto *ND = cast<NamedDecl>(DC);57DeclarationName Name = ND->getDeclName();58auto SourceNameOrErr = ReverseImporter.Import(Name);59if (!SourceNameOrErr) {60llvm::consumeError(SourceNameOrErr.takeError());61return nullptr;62}63Source<DeclarationName> SourceName = *SourceNameOrErr;64DeclContext::lookup_result SearchResult =65SourceParentDC.get()->lookup(SourceName.get());6667// There are two cases here. First, we might not find the name.68// We might also find multiple copies, in which case we have no69// guarantee that the one we wanted is the one we pick. (E.g.,70// if we have two specializations of the same template it is71// very hard to determine which is the one you want.)72//73// The Origins map fixes this problem by allowing the origin to be74// explicitly recorded, so we trigger that recording by returning75// nothing (rather than a possibly-inaccurate guess) here.76if (SearchResult.isSingleResult()) {77NamedDecl *SearchResultDecl = SearchResult.front();78if (isa<DeclContext>(SearchResultDecl) &&79SearchResultDecl->getKind() == DC->getDeclKind())80return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();81return nullptr; // This type of lookup is unsupported82} else {83return nullptr;84}85}8687/// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.88///89/// There are several modifications:90///91/// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few92/// others), which instructs Clang to refer to ExternalASTMerger. Also, it93/// forces MinimalImport to true, which is necessary to make this work.94/// - It maintains a reverse importer for use with names. This allows lookup of95/// arbitrary names in the source context.96/// - It updates the ExternalASTMerger's origin map as needed whenever a97/// it sees a DeclContext.98class LazyASTImporter : public ASTImporter {99private:100ExternalASTMerger &Parent;101ASTImporter Reverse;102const ExternalASTMerger::OriginMap &FromOrigins;103/// @see ExternalASTMerger::ImporterSource::Temporary104bool TemporarySource;105/// Map of imported declarations back to the declarations they originated106/// from.107llvm::DenseMap<Decl *, Decl *> ToOrigin;108/// @see ExternalASTMerger::ImporterSource::Merger109ExternalASTMerger *SourceMerger;110llvm::raw_ostream &logs() { return Parent.logs(); }111public:112LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,113FileManager &ToFileManager,114const ExternalASTMerger::ImporterSource &S,115std::shared_ptr<ASTImporterSharedState> SharedState)116: ASTImporter(ToContext, ToFileManager, S.getASTContext(),117S.getFileManager(),118/*MinimalImport=*/true, SharedState),119Parent(_Parent),120Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager,121/*MinimalImport=*/true),122FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()),123SourceMerger(S.getMerger()) {}124125llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {126if (!TemporarySource || !SourceMerger)127return ASTImporter::ImportImpl(FromD);128129// If we get here, then this source is importing from a temporary ASTContext130// that also has another ExternalASTMerger attached. It could be131// possible that the current ExternalASTMerger and the temporary ASTContext132// share a common ImporterSource, which means that the temporary133// AST could contain declarations that were imported from a source134// that this ExternalASTMerger can access directly. Instead of importing135// such declarations from the temporary ASTContext, they should instead136// be directly imported by this ExternalASTMerger from the original137// source. This way the ExternalASTMerger can safely do a minimal import138// without creating incomplete declarations originated from a temporary139// ASTContext. If we would try to complete such declarations later on, we140// would fail to do so as their temporary AST could be deleted (which means141// that the missing parts of the minimally imported declaration in that142// ASTContext were also deleted).143//144// The following code tracks back any declaration that needs to be145// imported from the temporary ASTContext to a persistent ASTContext.146// Then the ExternalASTMerger tries to import from the persistent147// ASTContext directly by using the associated ASTImporter. If that148// succeeds, this ASTImporter just maps the declarations imported by149// the other (persistent) ASTImporter to this (temporary) ASTImporter.150// The steps can be visualized like this:151//152// Target AST <--- 3. Indirect import --- Persistent AST153// ^ of persistent decl ^154// | |155// 1. Current import 2. Tracking back to persistent decl156// 4. Map persistent decl |157// & pretend we imported. |158// | |159// Temporary AST -------------------------------'160161// First, ask the ExternalASTMerger of the source where the temporary162// declaration originated from.163Decl *Persistent = SourceMerger->FindOriginalDecl(FromD);164// FromD isn't from a persistent AST, so just do a normal import.165if (!Persistent)166return ASTImporter::ImportImpl(FromD);167// Now ask the current ExternalASTMerger to try import the persistent168// declaration into the target.169ASTContext &PersistentCtx = Persistent->getASTContext();170ASTImporter &OtherImporter = Parent.ImporterForOrigin(PersistentCtx);171// Check that we never end up in the current Importer again.172assert((&PersistentCtx != &getFromContext()) && (&OtherImporter != this) &&173"Delegated to same Importer?");174auto DeclOrErr = OtherImporter.Import(Persistent);175// Errors when importing the persistent decl are treated as if we176// had errors with importing the temporary decl.177if (!DeclOrErr)178return DeclOrErr.takeError();179Decl *D = *DeclOrErr;180// Tell the current ASTImporter that this has already been imported181// to prevent any further queries for the temporary decl.182MapImported(FromD, D);183return D;184}185186/// Implements the ASTImporter interface for tracking back a declaration187/// to its original declaration it came from.188Decl *GetOriginalDecl(Decl *To) override {189return ToOrigin.lookup(To);190}191192/// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin193/// map is kept up to date. Also set the appropriate flags.194void Imported(Decl *From, Decl *To) override {195ToOrigin[To] = From;196197if (auto *ToDC = dyn_cast<DeclContext>(To)) {198const bool LoggingEnabled = Parent.LoggingEnabled();199if (LoggingEnabled)200logs() << "(ExternalASTMerger*)" << (void*)&Parent201<< " imported (DeclContext*)" << (void*)ToDC202<< ", (ASTContext*)" << (void*)&getToContext()203<< " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)204<< ", (ASTContext*)" << (void*)&getFromContext()205<< "\n";206Source<DeclContext *> FromDC(207cast<DeclContext>(From)->getPrimaryContext());208if (FromOrigins.count(FromDC) &&209Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) {210if (LoggingEnabled)211logs() << "(ExternalASTMerger*)" << (void*)&Parent212<< " forced origin (DeclContext*)"213<< (void*)FromOrigins.at(FromDC).DC214<< ", (ASTContext*)"215<< (void*)FromOrigins.at(FromDC).AST216<< "\n";217Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC));218} else {219if (LoggingEnabled)220logs() << "(ExternalASTMerger*)" << (void*)&Parent221<< " maybe recording origin (DeclContext*)" << (void*)FromDC222<< ", (ASTContext*)" << (void*)&getFromContext()223<< "\n";224Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});225}226}227if (auto *ToTag = dyn_cast<TagDecl>(To)) {228ToTag->setHasExternalLexicalStorage();229ToTag->getPrimaryContext()->setMustBuildLookupTable();230assert(Parent.CanComplete(ToTag));231} else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {232ToNamespace->setHasExternalVisibleStorage();233assert(Parent.CanComplete(ToNamespace));234} else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {235ToContainer->setHasExternalLexicalStorage();236ToContainer->getPrimaryContext()->setMustBuildLookupTable();237assert(Parent.CanComplete(ToContainer));238}239}240ASTImporter &GetReverse() { return Reverse; }241};242243bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {244if (isa<FunctionDecl>(C.first.get()))245return false;246return llvm::any_of(Decls, [&](const Candidate &D) {247return C.first.get()->getKind() == D.first.get()->getKind();248});249}250251} // end namespace252253ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) {254for (const std::unique_ptr<ASTImporter> &I : Importers)255if (&I->getFromContext() == &OriginContext)256return *I;257llvm_unreachable("We should have an importer for this origin!");258}259260namespace {261LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,262ASTContext &OriginContext) {263return static_cast<LazyASTImporter &>(264Merger.ImporterForOrigin(OriginContext));265}266}267268bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) {269for (const std::unique_ptr<ASTImporter> &I : Importers)270if (&I->getFromContext() == &OriginContext)271return true;272return false;273}274275template <typename CallbackType>276void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,277CallbackType Callback) {278if (Origins.count(DC)) {279ExternalASTMerger::DCOrigin Origin = Origins[DC];280LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);281Callback(Importer, Importer.GetReverse(), Origin.DC);282} else {283bool DidCallback = false;284for (const std::unique_ptr<ASTImporter> &Importer : Importers) {285Source<TranslationUnitDecl *> SourceTU =286Importer->getFromContext().getTranslationUnitDecl();287ASTImporter &Reverse =288static_cast<LazyASTImporter *>(Importer.get())->GetReverse();289if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {290DidCallback = true;291if (Callback(*Importer, Reverse, SourceDC))292break;293}294}295if (!DidCallback && LoggingEnabled())296logs() << "(ExternalASTMerger*)" << (void*)this297<< " asserting for (DeclContext*)" << (const void*)DC298<< ", (ASTContext*)" << (void*)&Target.AST299<< "\n";300assert(DidCallback && "Couldn't find a source context matching our DC");301}302}303304void ExternalASTMerger::CompleteType(TagDecl *Tag) {305assert(Tag->hasExternalLexicalStorage());306ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,307Source<const DeclContext *> SourceDC) -> bool {308auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));309if (SourceTag->hasExternalLexicalStorage())310SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);311if (!SourceTag->getDefinition())312return false;313Forward.MapImported(SourceTag, Tag);314if (llvm::Error Err = Forward.ImportDefinition(SourceTag))315llvm::consumeError(std::move(Err));316Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());317return true;318});319}320321void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) {322assert(Interface->hasExternalLexicalStorage());323ForEachMatchingDC(324Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,325Source<const DeclContext *> SourceDC) -> bool {326auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(327cast<ObjCInterfaceDecl>(SourceDC.get()));328if (SourceInterface->hasExternalLexicalStorage())329SourceInterface->getASTContext().getExternalSource()->CompleteType(330SourceInterface);331if (!SourceInterface->getDefinition())332return false;333Forward.MapImported(SourceInterface, Interface);334if (llvm::Error Err = Forward.ImportDefinition(SourceInterface))335llvm::consumeError(std::move(Err));336return true;337});338}339340bool ExternalASTMerger::CanComplete(DeclContext *Interface) {341assert(Interface->hasExternalLexicalStorage() ||342Interface->hasExternalVisibleStorage());343bool FoundMatchingDC = false;344ForEachMatchingDC(Interface,345[&](ASTImporter &Forward, ASTImporter &Reverse,346Source<const DeclContext *> SourceDC) -> bool {347FoundMatchingDC = true;348return true;349});350return FoundMatchingDC;351}352353namespace {354bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {355if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))356return true; // There are many cases where Objective-C is ambiguous.357if (auto *T1 = dyn_cast<TagDecl>(D1))358if (auto *T2 = dyn_cast<TagDecl>(D2))359if (T1->getFirstDecl() == T2->getFirstDecl())360return true;361return D1 == D2 || D1 == CanonicalizeDC(D2);362}363}364365void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC,366DCOrigin Origin) {367LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);368ASTImporter &Reverse = Importer.GetReverse();369Source<const DeclContext *> FoundFromDC =370LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);371const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);372if (DoRecord)373RecordOriginImpl(ToDC, Origin, Importer);374if (LoggingEnabled())375logs() << "(ExternalASTMerger*)" << (void*)this376<< (DoRecord ? " decided " : " decided NOT")377<< " to record origin (DeclContext*)" << (void*)Origin.DC378<< ", (ASTContext*)" << (void*)&Origin.AST379<< "\n";380}381382void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC,383DCOrigin Origin) {384RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));385}386387void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,388ASTImporter &Importer) {389Origins[ToDC] = Origin;390Importer.ASTImporter::MapImported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));391}392393ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,394llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {395SharedState = std::make_shared<ASTImporterSharedState>(396*Target.AST.getTranslationUnitDecl());397AddSources(Sources);398}399400Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) {401assert(&D->getASTContext() == &Target.AST);402for (const auto &I : Importers)403if (auto Result = I->GetOriginalDecl(D))404return Result;405return nullptr;406}407408void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) {409for (const ImporterSource &S : Sources) {410assert(&S.getASTContext() != &Target.AST);411// Check that the associated merger actually imports into the source AST.412assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext());413Importers.push_back(std::make_unique<LazyASTImporter>(414*this, Target.AST, Target.FM, S, SharedState));415}416}417418void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {419if (LoggingEnabled())420for (const ImporterSource &S : Sources)421logs() << "(ExternalASTMerger*)" << (void *)this422<< " removing source (ASTContext*)" << (void *)&S.getASTContext()423<< "\n";424llvm::erase_if(Importers,425[&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {426for (const ImporterSource &S : Sources) {427if (&Importer->getFromContext() == &S.getASTContext())428return true;429}430return false;431});432for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {433std::pair<const DeclContext *, DCOrigin> Origin = *OI;434bool Erase = false;435for (const ImporterSource &S : Sources) {436if (&S.getASTContext() == Origin.second.AST) {437Erase = true;438break;439}440}441if (Erase)442OI = Origins.erase(OI);443else444++OI;445}446}447448template <typename DeclTy>449static bool importSpecializations(DeclTy *D, ASTImporter *Importer) {450for (auto *Spec : D->specializations()) {451auto ImportedSpecOrError = Importer->Import(Spec);452if (!ImportedSpecOrError) {453llvm::consumeError(ImportedSpecOrError.takeError());454return true;455}456}457return false;458}459460/// Imports specializations from template declarations that can be specialized.461static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) {462if (!isa<TemplateDecl>(D))463return false;464if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D))465return importSpecializations(FunctionTD, Importer);466else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D))467return importSpecializations(ClassTD, Importer);468else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D))469return importSpecializations(VarTD, Importer);470return false;471}472473bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,474DeclarationName Name) {475llvm::SmallVector<NamedDecl *, 1> Decls;476llvm::SmallVector<Candidate, 4> Candidates;477478auto FilterFoundDecl = [&Candidates](const Candidate &C) {479if (!HasDeclOfSameType(Candidates, C))480Candidates.push_back(C);481};482483ForEachMatchingDC(DC,484[&](ASTImporter &Forward, ASTImporter &Reverse,485Source<const DeclContext *> SourceDC) -> bool {486auto FromNameOrErr = Reverse.Import(Name);487if (!FromNameOrErr) {488llvm::consumeError(FromNameOrErr.takeError());489return false;490}491DeclContextLookupResult Result =492SourceDC.get()->lookup(*FromNameOrErr);493for (NamedDecl *FromD : Result) {494FilterFoundDecl(std::make_pair(FromD, &Forward));495}496return false;497});498499if (Candidates.empty())500return false;501502Decls.reserve(Candidates.size());503for (const Candidate &C : Candidates) {504Decl *LookupRes = C.first.get();505ASTImporter *Importer = C.second;506auto NDOrErr = Importer->Import(LookupRes);507NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr)));508assert(ND);509// If we don't import specialization, they are not available via lookup510// because the lookup result is imported TemplateDecl and it does not511// reference its specializations until they are imported explicitly.512bool IsSpecImportFailed =513importSpecializationsIfNeeded(LookupRes, Importer);514assert(!IsSpecImportFailed);515(void)IsSpecImportFailed;516Decls.push_back(ND);517}518SetExternalVisibleDeclsForName(DC, Name, Decls);519return true;520}521522void ExternalASTMerger::FindExternalLexicalDecls(523const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,524SmallVectorImpl<Decl *> &Result) {525ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,526Source<const DeclContext *> SourceDC) -> bool {527for (const Decl *SourceDecl : SourceDC.get()->decls()) {528if (IsKindWeWant(SourceDecl->getKind())) {529auto ImportedDeclOrErr = Forward.Import(SourceDecl);530if (ImportedDeclOrErr)531assert(!(*ImportedDeclOrErr) ||532IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC));533else534llvm::consumeError(ImportedDeclOrErr.takeError());535}536}537return false;538});539}540541542