ExternalASTMerger.cpp revision 321369
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 ToTag->setMustBuildLookupTable(); 45 } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) { 46 ToNamespace->setHasExternalVisibleStorage(); 47 } 48 return ASTImporter::Imported(From, To); 49 } 50}; 51 52Source<const DeclContext *> 53LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, 54 ASTImporter &ReverseImporter) { 55 if (DC->isTranslationUnit()) { 56 return SourceTU; 57 } 58 Source<const DeclContext *> SourceParentDC = 59 LookupSameContext(SourceTU, DC->getParent(), ReverseImporter); 60 if (!SourceParentDC) { 61 // If we couldn't find the parent DC in this TranslationUnit, give up. 62 return nullptr; 63 } 64 auto ND = cast<NamedDecl>(DC); 65 DeclarationName Name = ND->getDeclName(); 66 Source<DeclarationName> SourceName = ReverseImporter.Import(Name); 67 DeclContext::lookup_result SearchResult = 68 SourceParentDC.get()->lookup(SourceName.get()); 69 size_t SearchResultSize = SearchResult.size(); 70 // Handle multiple candidates once we have a test for it. 71 // This may turn up when we import template specializations correctly. 72 assert(SearchResultSize < 2); 73 if (SearchResultSize == 0) { 74 // couldn't find the name, so we have to give up 75 return nullptr; 76 } else { 77 NamedDecl *SearchResultDecl = SearchResult[0]; 78 return dyn_cast<DeclContext>(SearchResultDecl); 79 } 80} 81 82bool IsForwardDeclaration(Decl *D) { 83 assert(!isa<ObjCInterfaceDecl>(D)); // TODO handle this case 84 if (auto TD = dyn_cast<TagDecl>(D)) { 85 return !TD->isThisDeclarationADefinition(); 86 } else if (auto FD = dyn_cast<FunctionDecl>(D)) { 87 return !FD->isThisDeclarationADefinition(); 88 } else { 89 return false; 90 } 91} 92 93template <typename CallbackType> 94void ForEachMatchingDC( 95 const DeclContext *DC, 96 llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers, 97 CallbackType Callback) { 98 for (const ExternalASTMerger::ImporterPair &IP : Importers) { 99 Source<TranslationUnitDecl *> SourceTU = 100 IP.Forward->getFromContext().getTranslationUnitDecl(); 101 if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse)) 102 Callback(IP, SourceDC); 103 } 104} 105 106bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { 107 return llvm::any_of(Decls, [&](const Candidate &D) { 108 return C.first.get()->getKind() == D.first.get()->getKind(); 109 }); 110} 111} // end namespace 112 113ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target, 114 llvm::ArrayRef<ImporterEndpoint> Sources) { 115 for (const ImporterEndpoint &S : Sources) { 116 Importers.push_back( 117 {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM), 118 llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM, 119 /*MinimalImport=*/true)}); 120 } 121} 122 123bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, 124 DeclarationName Name) { 125 llvm::SmallVector<NamedDecl *, 1> Decls; 126 llvm::SmallVector<Candidate, 4> CompleteDecls; 127 llvm::SmallVector<Candidate, 4> ForwardDecls; 128 129 auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) { 130 if (IsForwardDeclaration(C.first.get())) { 131 if (!HasDeclOfSameType(ForwardDecls, C)) { 132 ForwardDecls.push_back(C); 133 } 134 } else { 135 CompleteDecls.push_back(C); 136 } 137 }; 138 139 ForEachMatchingDC( 140 DC, Importers, 141 [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { 142 DeclarationName FromName = IP.Reverse->Import(Name); 143 DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); 144 for (NamedDecl *FromD : Result) { 145 FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); 146 } 147 }); 148 149 llvm::ArrayRef<Candidate> DeclsToReport = 150 CompleteDecls.empty() ? ForwardDecls : CompleteDecls; 151 152 if (DeclsToReport.empty()) { 153 return false; 154 } 155 156 Decls.reserve(DeclsToReport.size()); 157 for (const Candidate &C : DeclsToReport) { 158 NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get())); 159 assert(d); 160 Decls.push_back(d); 161 } 162 SetExternalVisibleDeclsForName(DC, Name, Decls); 163 return true; 164} 165 166void ExternalASTMerger::FindExternalLexicalDecls( 167 const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, 168 SmallVectorImpl<Decl *> &Result) { 169 ForEachMatchingDC( 170 DC, Importers, 171 [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) { 172 for (const Decl *SourceDecl : SourceDC.get()->decls()) { 173 if (IsKindWeWant(SourceDecl->getKind())) { 174 Decl *ImportedDecl = 175 IP.Forward->Import(const_cast<Decl *>(SourceDecl)); 176 assert(ImportedDecl->getDeclContext() == DC); 177 (void)ImportedDecl; 178 } 179 } 180 }); 181} 182 183