forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			547 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			547 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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);
 | |
|     NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(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;
 | |
|   });
 | |
| }
 | |
| 
 |