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