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 20 using namespace clang; 21 22 namespace { 23 24 template <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 33 typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate; 34 35 class LazyASTImporter : public ASTImporter { 36 public: 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 52 Source<const DeclContext *> 53 LookupSameContext(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 82 bool 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 93 template <typename CallbackType> 94 void 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 106 bool 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 113 ExternalASTMerger::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 123 bool 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 166 void 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 void ExternalASTMerger::CompleteType(TagDecl *Tag) { 184 SmallVector<Decl *, 0> Result; 185 FindExternalLexicalDecls(Tag, [](Decl::Kind) { return true; }, Result); 186 Tag->setHasExternalLexicalStorage(false); 187 } 188