xref: /llvm-project/clang/lib/AST/ExternalASTMerger.cpp (revision 1eac879d85c418650c639baa4fcceeef19e7356a)
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