blob: f69b5d6284065395f7af5f19a15bb329e36f2c5b [file] [log] [blame]
Sean Callananb7160ca2017-04-11 19:33:35 +00001//===- 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;
Sean Callananf8edb1d2017-04-11 20:51:21 +000026 Source(T t) : t(t) {}
Sean Callananb7160ca2017-04-11 19:33:35 +000027 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();
Lang Hames8ca265f2017-06-17 00:12:38 +000044 ToTag->setMustBuildLookupTable();
Sean Callananb7160ca2017-04-11 19:33:35 +000045 } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) {
46 ToNamespace->setHasExternalVisibleStorage();
Sean Callanan1eac8792017-07-25 19:54:22 +000047 } else if (auto ToContainer = dyn_cast<ObjCContainerDecl>(To)) {
48 ToContainer->setHasExternalLexicalStorage();
49 ToContainer->setMustBuildLookupTable();
Sean Callananb7160ca2017-04-11 19:33:35 +000050 }
51 return ASTImporter::Imported(From, To);
52 }
53};
54
55Source<const DeclContext *>
56LookupSameContext(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
85bool IsForwardDeclaration(Decl *D) {
Sean Callananb7160ca2017-04-11 19:33:35 +000086 if (auto TD = dyn_cast<TagDecl>(D)) {
87 return !TD->isThisDeclarationADefinition();
88 } else if (auto FD = dyn_cast<FunctionDecl>(D)) {
89 return !FD->isThisDeclarationADefinition();
Sean Callanan1eac8792017-07-25 19:54:22 +000090 } else if (auto OID = dyn_cast<ObjCInterfaceDecl>(D)) {
91 return OID->isThisDeclarationADefinition();
Sean Callananb7160ca2017-04-11 19:33:35 +000092 } else {
93 return false;
94 }
95}
96
David Blaikie0a0c0332017-04-17 17:16:19 +000097template <typename CallbackType>
Sean Callananb7160ca2017-04-11 19:33:35 +000098void ForEachMatchingDC(
99 const DeclContext *DC,
100 llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers,
David Blaikie0a0c0332017-04-17 17:16:19 +0000101 CallbackType Callback) {
Sean Callananb7160ca2017-04-11 19:33:35 +0000102 for (const ExternalASTMerger::ImporterPair &IP : Importers) {
David Blaikie0a0c0332017-04-17 17:16:19 +0000103 Source<TranslationUnitDecl *> SourceTU =
104 IP.Forward->getFromContext().getTranslationUnitDecl();
105 if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse))
Sean Callananb7160ca2017-04-11 19:33:35 +0000106 Callback(IP, SourceDC);
Sean Callananb7160ca2017-04-11 19:33:35 +0000107 }
108}
109
110bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
David Blaikie0a0c0332017-04-17 17:16:19 +0000111 return llvm::any_of(Decls, [&](const Candidate &D) {
Sean Callananb7160ca2017-04-11 19:33:35 +0000112 return C.first.get()->getKind() == D.first.get()->getKind();
113 });
114}
115} // end namespace
116
117ExternalASTMerger::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
127bool 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
David Blaikie0a0c0332017-04-17 17:16:19 +0000143 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 });
Sean Callananb7160ca2017-04-11 19:33:35 +0000152
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
170void ExternalASTMerger::FindExternalLexicalDecls(
171 const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
172 SmallVectorImpl<Decl *> &Result) {
173 ForEachMatchingDC(
David Blaikie0a0c0332017-04-17 17:16:19 +0000174 DC, Importers,
175 [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
Sean Callanan4bb0d782017-04-11 19:50:37 +0000176 for (const Decl *SourceDecl : SourceDC.get()->decls()) {
177 if (IsKindWeWant(SourceDecl->getKind())) {
Sean Callananb7160ca2017-04-11 19:33:35 +0000178 Decl *ImportedDecl =
Sean Callanan4bb0d782017-04-11 19:50:37 +0000179 IP.Forward->Import(const_cast<Decl *>(SourceDecl));
Sean Callananb7160ca2017-04-11 19:33:35 +0000180 assert(ImportedDecl->getDeclContext() == DC);
Benjamin Kramer4ecc8482017-04-11 23:06:49 +0000181 (void)ImportedDecl;
Sean Callananb7160ca2017-04-11 19:33:35 +0000182 }
183 }
184 });
185}
Sean Callanan9092d472017-05-13 00:46:33 +0000186