ExternalASTMerger.cpp revision 317030
1//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the ExternalASTMerger, which vends a combination of 11// ASTs from several different ASTContext/FileManager pairs 12// 13//===----------------------------------------------------------------------===// 14 15#include "clang/AST/ASTContext.h" 16#include "clang/AST/Decl.h" 17#include "clang/AST/DeclObjC.h" 18#include "clang/AST/ExternalASTMerger.h" 19 20using namespace clang; 21 22namespace { 23 24template <typename T> struct Source { 25 T t; 26 Source(T t) : t(t) {} 27 operator T() { return t; } 28 template <typename U = T> U &get() { return t; } 29 template <typename U = T> const U &get() const { return t; } 30 template <typename U> operator Source<U>() { return Source<U>(t); } 31}; 32 33typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate; 34 35class LazyASTImporter : public ASTImporter { 36public: 37 LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager, 38 ASTContext &FromContext, FileManager &FromFileManager) 39 : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, 40 /*MinimalImport=*/true) {} 41 Decl *Imported(Decl *From, Decl *To) override { 42 if (auto ToTag = dyn_cast<TagDecl>(To)) { 43 ToTag->setHasExternalLexicalStorage(); 44 } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) { 45 ToNamespace->setHasExternalVisibleStorage(); 46 } 47 return ASTImporter::Imported(From, To); 48 } 49}; 50 51Source<const DeclContext *> 52LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, 53 ASTImporter &ReverseImporter) { 54 if (DC->isTranslationUnit()) { 55 return SourceTU; 56 } 57 Source<const DeclContext *> SourceParentDC = 58 LookupSameContext(SourceTU, DC->getParent(), ReverseImporter); 59 if (!SourceParentDC) { 60 // If we couldn't find the parent DC in this TranslationUnit, give up. 61 return nullptr; 62 } 63 auto ND = cast<NamedDecl>(DC); 64 DeclarationName Name = ND->getDeclName(); 65 Source<DeclarationName> SourceName = ReverseImporter.Import(Name); 66 DeclContext::lookup_result SearchResult = 67 SourceParentDC.get()->lookup(SourceName.get()); 68 size_t SearchResultSize = SearchResult.size(); 69 // Handle multiple candidates once we have a test for it. 70 // This may turn up when we import template specializations correctly. 71 assert(SearchResultSize < 2); 72 if (SearchResultSize == 0) { 73 // couldn't find the name, so we have to give up 74 return nullptr; 75 } else { 76 NamedDecl *SearchResultDecl = SearchResult[0]; 77 return dyn_cast<DeclContext>(SearchResultDecl); 78 } 79} 80 81bool IsForwardDeclaration(Decl *D) { 82 assert(!isa<ObjCInterfaceDecl>(D)); // TODO handle this case 83 if (auto TD = dyn_cast<TagDecl>(D)) { 84 return !TD->isThisDeclarationADefinition(); 85 } else if (auto FD = dyn_cast<FunctionDecl>(D)) { 86 return !FD->isThisDeclarationADefinition(); 87 } else { 88 return false; 89 } 90} 91 92void ForEachMatchingDC( 93 const DeclContext *DC, 94 llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers, 95 std::function<void(const ExternalASTMerger::ImporterPair &IP, 96 Source<const DeclContext *> SourceDC)> 97 Callback) { 98 for (const ExternalASTMerger::ImporterPair &IP : Importers) { 99 Source<TranslationUnitDecl *> SourceTU( 100 IP.Forward->getFromContext().getTranslationUnitDecl()); 101 Source<const DeclContext *> SourceDC = 102 LookupSameContext(SourceTU, DC, *IP.Reverse); 103 if (SourceDC.get()) { 104 Callback(IP, SourceDC); 105 } 106 } 107} 108 109bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { 110 return std::any_of(Decls.begin(), Decls.end(), [&C](const Candidate &D) { 111 return C.first.get()->getKind() == D.first.get()->getKind(); 112 }); 113} 114} // end namespace 115 116ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target, 117 llvm::ArrayRef<ImporterEndpoint> Sources) { 118 for (const ImporterEndpoint &S : Sources) { 119 Importers.push_back( 120 {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM), 121 llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM, 122 /*MinimalImport=*/true)}); 123 } 124} 125 126bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, 127 DeclarationName Name) { 128 llvm::SmallVector<NamedDecl *, 1> Decls; 129 llvm::SmallVector<Candidate, 4> CompleteDecls; 130 llvm::SmallVector<Candidate, 4> ForwardDecls; 131 132 auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) { 133 if (IsForwardDeclaration(C.first.get())) { 134 if (!HasDeclOfSameType(ForwardDecls, C)) { 135 ForwardDecls.push_back(C); 136 } 137 } else { 138 CompleteDecls.push_back(C); 139 } 140 }; 141 142 ForEachMatchingDC(DC, Importers, [Name, &FilterFoundDecl]( 143 const ImporterPair &IP, 144 Source<const DeclContext *> SourceDC) { 145 DeclarationName FromName = IP.Reverse->Import(Name); 146 DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); 147 for (NamedDecl *FromD : Result) { 148 FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); 149 } 150 }); 151 152 llvm::ArrayRef<Candidate> DeclsToReport = 153 CompleteDecls.empty() ? ForwardDecls : CompleteDecls; 154 155 if (DeclsToReport.empty()) { 156 return false; 157 } 158 159 Decls.reserve(DeclsToReport.size()); 160 for (const Candidate &C : DeclsToReport) { 161 NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get())); 162 assert(d); 163 Decls.push_back(d); 164 } 165 SetExternalVisibleDeclsForName(DC, Name, Decls); 166 return true; 167} 168 169void ExternalASTMerger::FindExternalLexicalDecls( 170 const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, 171 SmallVectorImpl<Decl *> &Result) { 172 ForEachMatchingDC( 173 DC, Importers, [DC, IsKindWeWant](const ImporterPair &IP, 174 Source<const DeclContext *> SourceDC) { 175 for (const Decl *SourceDecl : SourceDC.get()->decls()) { 176 if (IsKindWeWant(SourceDecl->getKind())) { 177 Decl *ImportedDecl = 178 IP.Forward->Import(const_cast<Decl *>(SourceDecl)); 179 assert(ImportedDecl->getDeclContext() == DC); 180 (void)ImportedDecl; 181 (void)DC; 182 } 183 } 184 }); 185} 186