541 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the ExternalASTMerger, which vends a combination of10// ASTs from several different ASTContext/FileManager pairs11//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 {26 T t;27 Source(T t) : t(t) {}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); }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 is37/// the DC we actually want to work with most of the time.38const DeclContext *CanonicalizeDC(const DeclContext *DC) {39 if (isa<LinkageSpecDecl>(DC))40 return DC->getRedeclContext();41 return DC;42}43 44Source<const DeclContext *>45LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,46 ASTImporter &ReverseImporter) {47 DC = CanonicalizeDC(DC);48 if (DC->isTranslationUnit()) {49 return SourceTU;50 }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.55 return nullptr;56 }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());62 return nullptr;63 }64 Source<DeclarationName> SourceName = *SourceNameOrErr;65 DeclContext::lookup_result SearchResult =66 SourceParentDC.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 no70 // guarantee that the one we wanted is the one we pick. (E.g.,71 // if we have two specializations of the same template it is72 // very hard to determine which is the one you want.)73 //74 // The Origins map fixes this problem by allowing the origin to be75 // explicitly recorded, so we trigger that recording by returning76 // 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 unsupported83 } else {84 return 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 few93/// others), which instructs Clang to refer to ExternalASTMerger. Also, it94/// forces MinimalImport to true, which is necessary to make this work.95/// - It maintains a reverse importer for use with names. This allows lookup of96/// arbitrary names in the source context.97/// - It updates the ExternalASTMerger's origin map as needed whenever a98/// it sees a DeclContext.99class LazyASTImporter : public ASTImporter {100private:101 ExternalASTMerger &Parent;102 ASTImporter Reverse;103 const ExternalASTMerger::OriginMap &FromOrigins;104 /// @see ExternalASTMerger::ImporterSource::Temporary105 bool TemporarySource;106 /// Map of imported declarations back to the declarations they originated107 /// from.108 llvm::DenseMap<Decl *, Decl *> ToOrigin;109 /// @see ExternalASTMerger::ImporterSource::Merger110 ExternalASTMerger *SourceMerger;111 llvm::raw_ostream &logs() { return Parent.logs(); }112public: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(),118 S.getFileManager(),119 /*MinimalImport=*/true, SharedState),120 Parent(_Parent),121 Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager,122 /*MinimalImport=*/true),123 FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()),124 SourceMerger(S.getMerger()) {}125 126 llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {127 if (!TemporarySource || !SourceMerger)128 return ASTImporter::ImportImpl(FromD);129 130 // If we get here, then this source is importing from a temporary ASTContext131 // that also has another ExternalASTMerger attached. It could be132 // possible that the current ExternalASTMerger and the temporary ASTContext133 // share a common ImporterSource, which means that the temporary134 // AST could contain declarations that were imported from a source135 // that this ExternalASTMerger can access directly. Instead of importing136 // such declarations from the temporary ASTContext, they should instead137 // be directly imported by this ExternalASTMerger from the original138 // source. This way the ExternalASTMerger can safely do a minimal import139 // without creating incomplete declarations originated from a temporary140 // ASTContext. If we would try to complete such declarations later on, we141 // would fail to do so as their temporary AST could be deleted (which means142 // that the missing parts of the minimally imported declaration in that143 // ASTContext were also deleted).144 //145 // The following code tracks back any declaration that needs to be146 // imported from the temporary ASTContext to a persistent ASTContext.147 // Then the ExternalASTMerger tries to import from the persistent148 // ASTContext directly by using the associated ASTImporter. If that149 // succeeds, this ASTImporter just maps the declarations imported by150 // the other (persistent) ASTImporter to this (temporary) ASTImporter.151 // The steps can be visualized like this:152 //153 // Target AST <--- 3. Indirect import --- Persistent AST154 // ^ of persistent decl ^155 // | |156 // 1. Current import 2. Tracking back to persistent decl157 // 4. Map persistent decl |158 // & pretend we imported. |159 // | |160 // Temporary AST -------------------------------'161 162 // First, ask the ExternalASTMerger of the source where the temporary163 // declaration originated from.164 Decl *Persistent = SourceMerger->FindOriginalDecl(FromD);165 // FromD isn't from a persistent AST, so just do a normal import.166 if (!Persistent)167 return ASTImporter::ImportImpl(FromD);168 // Now ask the current ExternalASTMerger to try import the persistent169 // 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 we177 // had errors with importing the temporary decl.178 if (!DeclOrErr)179 return DeclOrErr.takeError();180 Decl *D = *DeclOrErr;181 // Tell the current ASTImporter that this has already been imported182 // to prevent any further queries for the temporary decl.183 MapImported(FromD, D);184 return D;185 }186 187 /// Implements the ASTImporter interface for tracking back a declaration188 /// to its original declaration it came from.189 Decl *GetOriginalDecl(Decl *To) override {190 return ToOrigin.lookup(To);191 }192 193 /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin194 /// map is kept up to date. Also set the appropriate flags.195 void Imported(Decl *From, Decl *To) override {196 ToOrigin[To] = From;197 198 if (auto *ToDC = dyn_cast<DeclContext>(To)) {199 const bool LoggingEnabled = Parent.LoggingEnabled();200 if (LoggingEnabled)201 logs() << "(ExternalASTMerger*)" << (void*)&Parent202 << " imported (DeclContext*)" << (void*)ToDC203 << ", (ASTContext*)" << (void*)&getToContext()204 << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)205 << ", (ASTContext*)" << (void*)&getFromContext()206 << "\n";207 Source<DeclContext *> FromDC(208 cast<DeclContext>(From)->getPrimaryContext());209 if (auto It = FromOrigins.find(FromDC);210 It != FromOrigins.end() &&211 Parent.HasImporterForOrigin(*It->second.AST)) {212 if (LoggingEnabled)213 logs() << "(ExternalASTMerger*)" << (void *)&Parent214 << " forced origin (DeclContext*)" << (void *)It->second.DC215 << ", (ASTContext*)" << (void *)It->second.AST << "\n";216 Parent.ForceRecordOrigin(ToDC, It->second);217 } else {218 if (LoggingEnabled)219 logs() << "(ExternalASTMerger*)" << (void*)&Parent220 << " maybe recording origin (DeclContext*)" << (void*)FromDC221 << ", (ASTContext*)" << (void*)&getFromContext()222 << "\n";223 Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});224 }225 }226 if (auto *ToTag = dyn_cast<TagDecl>(To)) {227 ToTag->setHasExternalLexicalStorage();228 ToTag->getPrimaryContext()->setMustBuildLookupTable();229 assert(Parent.CanComplete(ToTag));230 } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {231 ToNamespace->setHasExternalVisibleStorage();232 assert(Parent.CanComplete(ToNamespace));233 } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {234 ToContainer->setHasExternalLexicalStorage();235 ToContainer->getPrimaryContext()->setMustBuildLookupTable();236 assert(Parent.CanComplete(ToContainer));237 }238 }239 ASTImporter &GetReverse() { return Reverse; }240};241 242bool HasDeclOfSameType(ArrayRef<Candidate> Decls, const Candidate &C) {243 if (isa<FunctionDecl>(C.first.get()))244 return false;245 return llvm::any_of(Decls, [&](const Candidate &D) {246 return C.first.get()->getKind() == D.first.get()->getKind();247 });248}249 250} // end namespace251 252ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) {253 for (const std::unique_ptr<ASTImporter> &I : Importers)254 if (&I->getFromContext() == &OriginContext)255 return *I;256 llvm_unreachable("We should have an importer for this origin!");257}258 259namespace {260LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,261 ASTContext &OriginContext) {262 return static_cast<LazyASTImporter &>(263 Merger.ImporterForOrigin(OriginContext));264}265}266 267bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) {268 for (const std::unique_ptr<ASTImporter> &I : Importers)269 if (&I->getFromContext() == &OriginContext)270 return true;271 return false;272}273 274template <typename CallbackType>275void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,276 CallbackType Callback) {277 if (auto It = Origins.find(DC); It != Origins.end()) {278 ExternalASTMerger::DCOrigin Origin = It->second;279 LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);280 Callback(Importer, Importer.GetReverse(), Origin.DC);281 } else {282 bool DidCallback = false;283 for (const std::unique_ptr<ASTImporter> &Importer : Importers) {284 Source<TranslationUnitDecl *> SourceTU =285 Importer->getFromContext().getTranslationUnitDecl();286 ASTImporter &Reverse =287 static_cast<LazyASTImporter *>(Importer.get())->GetReverse();288 if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {289 DidCallback = true;290 if (Callback(*Importer, Reverse, SourceDC))291 break;292 }293 }294 if (!DidCallback && LoggingEnabled())295 logs() << "(ExternalASTMerger*)" << (void*)this296 << " asserting for (DeclContext*)" << (const void*)DC297 << ", (ASTContext*)" << (void*)&Target.AST298 << "\n";299 assert(DidCallback && "Couldn't find a source context matching our DC");300 }301}302 303void ExternalASTMerger::CompleteType(TagDecl *Tag) {304 assert(Tag->hasExternalLexicalStorage());305 ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,306 Source<const DeclContext *> SourceDC) -> bool {307 auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));308 if (SourceTag->hasExternalLexicalStorage())309 SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);310 if (!SourceTag->getDefinition())311 return false;312 Forward.MapImported(SourceTag, Tag);313 if (llvm::Error Err = Forward.ImportDefinition(SourceTag))314 llvm::consumeError(std::move(Err));315 Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());316 return true;317 });318}319 320void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) {321 assert(Interface->hasExternalLexicalStorage());322 ForEachMatchingDC(323 Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,324 Source<const DeclContext *> SourceDC) -> bool {325 auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(326 cast<ObjCInterfaceDecl>(SourceDC.get()));327 if (SourceInterface->hasExternalLexicalStorage())328 SourceInterface->getASTContext().getExternalSource()->CompleteType(329 SourceInterface);330 if (!SourceInterface->getDefinition())331 return false;332 Forward.MapImported(SourceInterface, Interface);333 if (llvm::Error Err = Forward.ImportDefinition(SourceInterface))334 llvm::consumeError(std::move(Err));335 return true;336 });337}338 339bool ExternalASTMerger::CanComplete(DeclContext *Interface) {340 assert(Interface->hasExternalLexicalStorage() ||341 Interface->hasExternalVisibleStorage());342 bool FoundMatchingDC = false;343 ForEachMatchingDC(Interface,344 [&](ASTImporter &Forward, ASTImporter &Reverse,345 Source<const DeclContext *> SourceDC) -> bool {346 FoundMatchingDC = true;347 return true;348 });349 return FoundMatchingDC;350}351 352namespace {353bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {354 if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))355 return true; // There are many cases where Objective-C is ambiguous.356 if (auto *T1 = dyn_cast<TagDecl>(D1))357 if (auto *T2 = dyn_cast<TagDecl>(D2))358 if (T1->getFirstDecl() == T2->getFirstDecl())359 return true;360 return D1 == D2 || D1 == CanonicalizeDC(D2);361}362}363 364void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC,365 DCOrigin Origin) {366 LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);367 ASTImporter &Reverse = Importer.GetReverse();368 Source<const DeclContext *> FoundFromDC =369 LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);370 const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);371 if (DoRecord)372 RecordOriginImpl(ToDC, Origin, Importer);373 if (LoggingEnabled())374 logs() << "(ExternalASTMerger*)" << (void*)this375 << (DoRecord ? " decided " : " decided NOT")376 << " to record origin (DeclContext*)" << (void*)Origin.DC377 << ", (ASTContext*)" << (void*)&Origin.AST378 << "\n";379}380 381void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC,382 DCOrigin Origin) {383 RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));384}385 386void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,387 ASTImporter &Importer) {388 Origins[ToDC] = Origin;389 Importer.ASTImporter::MapImported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));390}391 392ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,393 ArrayRef<ImporterSource> Sources)394 : LogStream(&llvm::nulls()), Target(Target) {395 SharedState = std::make_shared<ASTImporterSharedState>(396 *Target.AST.getTranslationUnitDecl());397 AddSources(Sources);398}399 400Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) {401 assert(&D->getASTContext() == &Target.AST);402 for (const auto &I : Importers)403 if (auto Result = I->GetOriginalDecl(D))404 return Result;405 return nullptr;406}407 408void ExternalASTMerger::AddSources(ArrayRef<ImporterSource> Sources) {409 for (const ImporterSource &S : Sources) {410 assert(&S.getASTContext() != &Target.AST);411 // Check that the associated merger actually imports into the source AST.412 assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext());413 Importers.push_back(std::make_unique<LazyASTImporter>(414 *this, Target.AST, Target.FM, S, SharedState));415 }416}417 418void ExternalASTMerger::RemoveSources(ArrayRef<ImporterSource> Sources) {419 if (LoggingEnabled())420 for (const ImporterSource &S : Sources)421 logs() << "(ExternalASTMerger*)" << (void *)this422 << " removing source (ASTContext*)" << (void *)&S.getASTContext()423 << "\n";424 llvm::erase_if(Importers,425 [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {426 for (const ImporterSource &S : Sources) {427 if (&Importer->getFromContext() == &S.getASTContext())428 return true;429 }430 return false;431 });432 for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {433 std::pair<const DeclContext *, DCOrigin> Origin = *OI;434 bool Erase = false;435 for (const ImporterSource &S : Sources) {436 if (&S.getASTContext() == Origin.second.AST) {437 Erase = true;438 break;439 }440 }441 if (Erase)442 OI = Origins.erase(OI);443 else444 ++OI;445 }446}447 448template <typename DeclTy>449static bool importSpecializations(DeclTy *D, ASTImporter *Importer) {450 for (auto *Spec : D->specializations()) {451 auto ImportedSpecOrError = Importer->Import(Spec);452 if (!ImportedSpecOrError) {453 llvm::consumeError(ImportedSpecOrError.takeError());454 return true;455 }456 }457 return false;458}459 460/// Imports specializations from template declarations that can be specialized.461static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) {462 if (!isa<TemplateDecl>(D))463 return false;464 if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D))465 return importSpecializations(FunctionTD, Importer);466 else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D))467 return importSpecializations(ClassTD, Importer);468 else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D))469 return importSpecializations(VarTD, Importer);470 return false;471}472 473bool ExternalASTMerger::FindExternalVisibleDeclsByName(474 const DeclContext *DC, DeclarationName Name,475 const DeclContext *OriginalDC) {476 llvm::SmallVector<NamedDecl *, 1> Decls;477 llvm::SmallVector<Candidate, 4> Candidates;478 479 auto FilterFoundDecl = [&Candidates](const Candidate &C) {480 if (!HasDeclOfSameType(Candidates, C))481 Candidates.push_back(C);482 };483 484 ForEachMatchingDC(DC,485 [&](ASTImporter &Forward, ASTImporter &Reverse,486 Source<const DeclContext *> SourceDC) -> bool {487 auto FromNameOrErr = Reverse.Import(Name);488 if (!FromNameOrErr) {489 llvm::consumeError(FromNameOrErr.takeError());490 return false;491 }492 DeclContextLookupResult Result =493 SourceDC.get()->lookup(*FromNameOrErr);494 for (NamedDecl *FromD : Result) {495 FilterFoundDecl(std::make_pair(FromD, &Forward));496 }497 return false;498 });499 500 if (Candidates.empty())501 return false;502 503 Decls.reserve(Candidates.size());504 for (const Candidate &C : Candidates) {505 Decl *LookupRes = C.first.get();506 ASTImporter *Importer = C.second;507 auto NDOrErr = Importer->Import(LookupRes);508 NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr)));509 assert(ND);510 // If we don't import specialization, they are not available via lookup511 // because the lookup result is imported TemplateDecl and it does not512 // reference its specializations until they are imported explicitly.513 bool IsSpecImportFailed =514 importSpecializationsIfNeeded(LookupRes, Importer);515 assert(!IsSpecImportFailed);516 (void)IsSpecImportFailed;517 Decls.push_back(ND);518 }519 SetExternalVisibleDeclsForName(DC, Name, Decls);520 return true;521}522 523void ExternalASTMerger::FindExternalLexicalDecls(524 const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,525 SmallVectorImpl<Decl *> &Result) {526 ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,527 Source<const DeclContext *> SourceDC) -> bool {528 for (const Decl *SourceDecl : SourceDC.get()->decls()) {529 if (IsKindWeWant(SourceDecl->getKind())) {530 auto ImportedDeclOrErr = Forward.Import(SourceDecl);531 if (ImportedDeclOrErr)532 assert(!(*ImportedDeclOrErr) ||533 IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC));534 else535 llvm::consumeError(ImportedDeclOrErr.takeError());536 }537 }538 return false;539 });540}541