diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp new file mode 100644 index 0000000..4f4a997 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp @@ -0,0 +1,182 @@ +//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/DeclObjC.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; + +class LazyASTImporter : public ASTImporter { +public: + LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager) + : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, + /*MinimalImport=*/true) {} + Decl *Imported(Decl *From, Decl *To) override { + if (auto ToTag = dyn_cast<TagDecl>(To)) { + ToTag->setHasExternalLexicalStorage(); + ToTag->setMustBuildLookupTable(); + } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) { + ToNamespace->setHasExternalVisibleStorage(); + } + return ASTImporter::Imported(From, To); + } +}; + +Source<const DeclContext *> +LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, + ASTImporter &ReverseImporter) { + 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(); + Source<DeclarationName> SourceName = ReverseImporter.Import(Name); + DeclContext::lookup_result SearchResult = + SourceParentDC.get()->lookup(SourceName.get()); + size_t SearchResultSize = SearchResult.size(); + // Handle multiple candidates once we have a test for it. + // This may turn up when we import template specializations correctly. + assert(SearchResultSize < 2); + if (SearchResultSize == 0) { + // couldn't find the name, so we have to give up + return nullptr; + } else { + NamedDecl *SearchResultDecl = SearchResult[0]; + return dyn_cast<DeclContext>(SearchResultDecl); + } +} + +bool IsForwardDeclaration(Decl *D) { + assert(!isa<ObjCInterfaceDecl>(D)); // TODO handle this case + if (auto TD = dyn_cast<TagDecl>(D)) { + return !TD->isThisDeclarationADefinition(); + } else if (auto FD = dyn_cast<FunctionDecl>(D)) { + return !FD->isThisDeclarationADefinition(); + } else { + return false; + } +} + +template <typename CallbackType> +void ForEachMatchingDC( + const DeclContext *DC, + llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers, + CallbackType Callback) { + for (const ExternalASTMerger::ImporterPair &IP : Importers) { + Source<TranslationUnitDecl *> SourceTU = + IP.Forward->getFromContext().getTranslationUnitDecl(); + if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse)) + Callback(IP, SourceDC); + } +} + +bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { + return llvm::any_of(Decls, [&](const Candidate &D) { + return C.first.get()->getKind() == D.first.get()->getKind(); + }); +} +} // end namespace + +ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target, + llvm::ArrayRef<ImporterEndpoint> Sources) { + for (const ImporterEndpoint &S : Sources) { + Importers.push_back( + {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM), + llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM, + /*MinimalImport=*/true)}); + } +} + +bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) { + llvm::SmallVector<NamedDecl *, 1> Decls; + llvm::SmallVector<Candidate, 4> CompleteDecls; + llvm::SmallVector<Candidate, 4> ForwardDecls; + + auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) { + if (IsForwardDeclaration(C.first.get())) { + if (!HasDeclOfSameType(ForwardDecls, C)) { + ForwardDecls.push_back(C); + } + } else { + CompleteDecls.push_back(C); + } + }; + + ForEachMatchingDC( + DC, Importers, + [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { + DeclarationName FromName = IP.Reverse->Import(Name); + DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); + for (NamedDecl *FromD : Result) { + FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); + } + }); + + llvm::ArrayRef<Candidate> DeclsToReport = + CompleteDecls.empty() ? ForwardDecls : CompleteDecls; + + if (DeclsToReport.empty()) { + return false; + } + + Decls.reserve(DeclsToReport.size()); + for (const Candidate &C : DeclsToReport) { + NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get())); + assert(d); + Decls.push_back(d); + } + SetExternalVisibleDeclsForName(DC, Name, Decls); + return true; +} + +void ExternalASTMerger::FindExternalLexicalDecls( + const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Result) { + ForEachMatchingDC( + DC, Importers, + [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { + for (const Decl *SourceDecl : SourceDC.get()->decls()) { + if (IsKindWeWant(SourceDecl->getKind())) { + Decl *ImportedDecl = + IP.Forward->Import(const_cast<Decl *>(SourceDecl)); + assert(ImportedDecl->getDeclContext() == DC); + (void)ImportedDecl; + } + } + }); +} + |