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(std::move(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     } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) {
45       ToNamespace->setHasExternalVisibleStorage();
46     }
47     return ASTImporter::Imported(From, To);
48   }
49 };
50 
51 Source<const DeclContext *>
52 LookupSameContext(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 
81 bool 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 
92 void 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 
109 bool 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 
116 ExternalASTMerger::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 
126 bool 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 
169 void 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 (Source<const Decl *> SourceDecl : SourceDC.get()->decls()) {
176           if (IsKindWeWant(SourceDecl.get()->getKind())) {
177             Decl *ImportedDecl =
178                 IP.Forward->Import(const_cast<Decl *>(SourceDecl.get()));
179             assert(ImportedDecl->getDeclContext() == DC);
180           }
181         }
182       });
183 }
184