1 | //===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements the ExternalASTMerger, which vends a combination of |
10 | // ASTs from several different ASTContext/FileManager pairs |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/AST/ASTContext.h" |
15 | #include "clang/AST/Decl.h" |
16 | #include "clang/AST/DeclCXX.h" |
17 | #include "clang/AST/DeclObjC.h" |
18 | #include "clang/AST/DeclTemplate.h" |
19 | #include "clang/AST/ExternalASTMerger.h" |
20 | |
21 | using namespace clang; |
22 | |
23 | namespace { |
24 | |
25 | template <typename T> struct Source { |
26 | T t; |
27 | Source(T t) : t(t) {} |
28 | operator T() { return t; } |
29 | template <typename U = T> U &get() { return t; } |
30 | template <typename U = T> const U &get() const { return t; } |
31 | template <typename U> operator Source<U>() { return Source<U>(t); } |
32 | }; |
33 | |
34 | typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate; |
35 | |
36 | /// For the given DC, return the DC that is safe to perform lookups on. This is |
37 | /// the DC we actually want to work with most of the time. |
38 | const DeclContext *CanonicalizeDC(const DeclContext *DC) { |
39 | if (isa<LinkageSpecDecl>(Val: DC)) |
40 | return DC->getRedeclContext(); |
41 | return DC; |
42 | } |
43 | |
44 | Source<const DeclContext *> |
45 | LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, |
46 | ASTImporter &ReverseImporter) { |
47 | DC = CanonicalizeDC(DC); |
48 | if (DC->isTranslationUnit()) { |
49 | return SourceTU; |
50 | } |
51 | Source<const DeclContext *> SourceParentDC = |
52 | LookupSameContext(SourceTU, DC: DC->getParent(), ReverseImporter); |
53 | if (!SourceParentDC) { |
54 | // If we couldn't find the parent DC in this TranslationUnit, give up. |
55 | return nullptr; |
56 | } |
57 | auto *ND = cast<NamedDecl>(Val: DC); |
58 | DeclarationName Name = ND->getDeclName(); |
59 | auto SourceNameOrErr = ReverseImporter.Import(FromName: Name); |
60 | if (!SourceNameOrErr) { |
61 | llvm::consumeError(Err: SourceNameOrErr.takeError()); |
62 | return nullptr; |
63 | } |
64 | Source<DeclarationName> SourceName = *SourceNameOrErr; |
65 | DeclContext::lookup_result SearchResult = |
66 | SourceParentDC.get()->lookup(Name: SourceName.get()); |
67 | |
68 | // There are two cases here. First, we might not find the name. |
69 | // We might also find multiple copies, in which case we have no |
70 | // guarantee that the one we wanted is the one we pick. (E.g., |
71 | // if we have two specializations of the same template it is |
72 | // very hard to determine which is the one you want.) |
73 | // |
74 | // The Origins map fixes this problem by allowing the origin to be |
75 | // explicitly recorded, so we trigger that recording by returning |
76 | // nothing (rather than a possibly-inaccurate guess) here. |
77 | if (SearchResult.isSingleResult()) { |
78 | NamedDecl *SearchResultDecl = SearchResult.front(); |
79 | if (isa<DeclContext>(Val: SearchResultDecl) && |
80 | SearchResultDecl->getKind() == DC->getDeclKind()) |
81 | return cast<DeclContext>(Val: SearchResultDecl)->getPrimaryContext(); |
82 | return nullptr; // This type of lookup is unsupported |
83 | } else { |
84 | return nullptr; |
85 | } |
86 | } |
87 | |
88 | /// A custom implementation of ASTImporter, for ExternalASTMerger's purposes. |
89 | /// |
90 | /// There are several modifications: |
91 | /// |
92 | /// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few |
93 | /// others), which instructs Clang to refer to ExternalASTMerger. Also, it |
94 | /// forces MinimalImport to true, which is necessary to make this work. |
95 | /// - It maintains a reverse importer for use with names. This allows lookup of |
96 | /// arbitrary names in the source context. |
97 | /// - It updates the ExternalASTMerger's origin map as needed whenever a |
98 | /// it sees a DeclContext. |
99 | class LazyASTImporter : public ASTImporter { |
100 | private: |
101 | ExternalASTMerger &Parent; |
102 | ASTImporter Reverse; |
103 | const ExternalASTMerger::OriginMap &FromOrigins; |
104 | /// @see ExternalASTMerger::ImporterSource::Temporary |
105 | bool TemporarySource; |
106 | /// Map of imported declarations back to the declarations they originated |
107 | /// from. |
108 | llvm::DenseMap<Decl *, Decl *> ToOrigin; |
109 | /// @see ExternalASTMerger::ImporterSource::Merger |
110 | ExternalASTMerger *SourceMerger; |
111 | llvm::raw_ostream &logs() { return Parent.logs(); } |
112 | public: |
113 | LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext, |
114 | FileManager &ToFileManager, |
115 | const ExternalASTMerger::ImporterSource &S, |
116 | std::shared_ptr<ASTImporterSharedState> SharedState) |
117 | : ASTImporter(ToContext, ToFileManager, S.getASTContext(), |
118 | S.getFileManager(), |
119 | /*MinimalImport=*/true, SharedState), |
120 | Parent(_Parent), |
121 | Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager, |
122 | /*MinimalImport=*/true), |
123 | FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()), |
124 | SourceMerger(S.getMerger()) {} |
125 | |
126 | llvm::Expected<Decl *> ImportImpl(Decl *FromD) override { |
127 | if (!TemporarySource || !SourceMerger) |
128 | return ASTImporter::ImportImpl(From: FromD); |
129 | |
130 | // If we get here, then this source is importing from a temporary ASTContext |
131 | // that also has another ExternalASTMerger attached. It could be |
132 | // possible that the current ExternalASTMerger and the temporary ASTContext |
133 | // share a common ImporterSource, which means that the temporary |
134 | // AST could contain declarations that were imported from a source |
135 | // that this ExternalASTMerger can access directly. Instead of importing |
136 | // such declarations from the temporary ASTContext, they should instead |
137 | // be directly imported by this ExternalASTMerger from the original |
138 | // source. This way the ExternalASTMerger can safely do a minimal import |
139 | // without creating incomplete declarations originated from a temporary |
140 | // ASTContext. If we would try to complete such declarations later on, we |
141 | // would fail to do so as their temporary AST could be deleted (which means |
142 | // that the missing parts of the minimally imported declaration in that |
143 | // ASTContext were also deleted). |
144 | // |
145 | // The following code tracks back any declaration that needs to be |
146 | // imported from the temporary ASTContext to a persistent ASTContext. |
147 | // Then the ExternalASTMerger tries to import from the persistent |
148 | // ASTContext directly by using the associated ASTImporter. If that |
149 | // succeeds, this ASTImporter just maps the declarations imported by |
150 | // the other (persistent) ASTImporter to this (temporary) ASTImporter. |
151 | // The steps can be visualized like this: |
152 | // |
153 | // Target AST <--- 3. Indirect import --- Persistent AST |
154 | // ^ of persistent decl ^ |
155 | // | | |
156 | // 1. Current import 2. Tracking back to persistent decl |
157 | // 4. Map persistent decl | |
158 | // & pretend we imported. | |
159 | // | | |
160 | // Temporary AST -------------------------------' |
161 | |
162 | // First, ask the ExternalASTMerger of the source where the temporary |
163 | // declaration originated from. |
164 | Decl *Persistent = SourceMerger->FindOriginalDecl(D: FromD); |
165 | // FromD isn't from a persistent AST, so just do a normal import. |
166 | if (!Persistent) |
167 | return ASTImporter::ImportImpl(From: FromD); |
168 | // Now ask the current ExternalASTMerger to try import the persistent |
169 | // declaration into the target. |
170 | ASTContext &PersistentCtx = Persistent->getASTContext(); |
171 | ASTImporter &OtherImporter = Parent.ImporterForOrigin(OriginContext&: PersistentCtx); |
172 | // Check that we never end up in the current Importer again. |
173 | assert((&PersistentCtx != &getFromContext()) && (&OtherImporter != this) && |
174 | "Delegated to same Importer?"); |
175 | auto DeclOrErr = OtherImporter.Import(FromD: Persistent); |
176 | // Errors when importing the persistent decl are treated as if we |
177 | // had errors with importing the temporary decl. |
178 | if (!DeclOrErr) |
179 | return DeclOrErr.takeError(); |
180 | Decl *D = *DeclOrErr; |
181 | // Tell the current ASTImporter that this has already been imported |
182 | // to prevent any further queries for the temporary decl. |
183 | MapImported(From: FromD, To: D); |
184 | return D; |
185 | } |
186 | |
187 | /// Implements the ASTImporter interface for tracking back a declaration |
188 | /// to its original declaration it came from. |
189 | Decl *GetOriginalDecl(Decl *To) override { |
190 | return ToOrigin.lookup(Val: To); |
191 | } |
192 | |
193 | /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin |
194 | /// map is kept up to date. Also set the appropriate flags. |
195 | void Imported(Decl *From, Decl *To) override { |
196 | ToOrigin[To] = From; |
197 | |
198 | if (auto *ToDC = dyn_cast<DeclContext>(Val: To)) { |
199 | const bool LoggingEnabled = Parent.LoggingEnabled(); |
200 | if (LoggingEnabled) |
201 | logs() << "(ExternalASTMerger*)"<< (void*)&Parent |
202 | << " imported (DeclContext*)"<< (void*)ToDC |
203 | << ", (ASTContext*)"<< (void*)&getToContext() |
204 | << " from (DeclContext*)"<< (void*)llvm::cast<DeclContext>(Val: From) |
205 | << ", (ASTContext*)"<< (void*)&getFromContext() |
206 | << "\n"; |
207 | Source<DeclContext *> FromDC( |
208 | cast<DeclContext>(Val: From)->getPrimaryContext()); |
209 | if (auto It = FromOrigins.find(x: FromDC); |
210 | It != FromOrigins.end() && |
211 | Parent.HasImporterForOrigin(OriginContext&: *It->second.AST)) { |
212 | if (LoggingEnabled) |
213 | logs() << "(ExternalASTMerger*)"<< (void *)&Parent |
214 | << " forced origin (DeclContext*)"<< (void *)It->second.DC |
215 | << ", (ASTContext*)"<< (void *)It->second.AST << "\n"; |
216 | Parent.ForceRecordOrigin(ToDC, Origin: It->second); |
217 | } else { |
218 | if (LoggingEnabled) |
219 | logs() << "(ExternalASTMerger*)"<< (void*)&Parent |
220 | << " maybe recording origin (DeclContext*)"<< (void*)FromDC |
221 | << ", (ASTContext*)"<< (void*)&getFromContext() |
222 | << "\n"; |
223 | Parent.MaybeRecordOrigin(ToDC, Origin: {.DC: FromDC, .AST: &getFromContext()}); |
224 | } |
225 | } |
226 | if (auto *ToTag = dyn_cast<TagDecl>(Val: To)) { |
227 | ToTag->setHasExternalLexicalStorage(); |
228 | ToTag->getPrimaryContext()->setMustBuildLookupTable(); |
229 | assert(Parent.CanComplete(ToTag)); |
230 | } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(Val: To)) { |
231 | ToNamespace->setHasExternalVisibleStorage(); |
232 | assert(Parent.CanComplete(ToNamespace)); |
233 | } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(Val: To)) { |
234 | ToContainer->setHasExternalLexicalStorage(); |
235 | ToContainer->getPrimaryContext()->setMustBuildLookupTable(); |
236 | assert(Parent.CanComplete(ToContainer)); |
237 | } |
238 | } |
239 | ASTImporter &GetReverse() { return Reverse; } |
240 | }; |
241 | |
242 | bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) { |
243 | if (isa<FunctionDecl>(Val: C.first.get())) |
244 | return false; |
245 | return llvm::any_of(Range&: Decls, P: [&](const Candidate &D) { |
246 | return C.first.get()->getKind() == D.first.get()->getKind(); |
247 | }); |
248 | } |
249 | |
250 | } // end namespace |
251 | |
252 | ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) { |
253 | for (const std::unique_ptr<ASTImporter> &I : Importers) |
254 | if (&I->getFromContext() == &OriginContext) |
255 | return *I; |
256 | llvm_unreachable("We should have an importer for this origin!"); |
257 | } |
258 | |
259 | namespace { |
260 | LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger, |
261 | ASTContext &OriginContext) { |
262 | return static_cast<LazyASTImporter &>( |
263 | Merger.ImporterForOrigin(OriginContext)); |
264 | } |
265 | } |
266 | |
267 | bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) { |
268 | for (const std::unique_ptr<ASTImporter> &I : Importers) |
269 | if (&I->getFromContext() == &OriginContext) |
270 | return true; |
271 | return false; |
272 | } |
273 | |
274 | template <typename CallbackType> |
275 | void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC, |
276 | CallbackType Callback) { |
277 | if (auto It = Origins.find(x: DC); It != Origins.end()) { |
278 | ExternalASTMerger::DCOrigin Origin = It->second; |
279 | LazyASTImporter &Importer = LazyImporterForOrigin(Merger&: *this, OriginContext&: *Origin.AST); |
280 | Callback(Importer, Importer.GetReverse(), Origin.DC); |
281 | } else { |
282 | bool DidCallback = false; |
283 | for (const std::unique_ptr<ASTImporter> &Importer : Importers) { |
284 | Source<TranslationUnitDecl *> SourceTU = |
285 | Importer->getFromContext().getTranslationUnitDecl(); |
286 | ASTImporter &Reverse = |
287 | static_cast<LazyASTImporter *>(Importer.get())->GetReverse(); |
288 | if (auto SourceDC = LookupSameContext(SourceTU, DC, ReverseImporter&: Reverse)) { |
289 | DidCallback = true; |
290 | if (Callback(*Importer, Reverse, SourceDC)) |
291 | break; |
292 | } |
293 | } |
294 | if (!DidCallback && LoggingEnabled()) |
295 | logs() << "(ExternalASTMerger*)"<< (void*)this |
296 | << " asserting for (DeclContext*)"<< (const void*)DC |
297 | << ", (ASTContext*)"<< (void*)&Target.AST |
298 | << "\n"; |
299 | assert(DidCallback && "Couldn't find a source context matching our DC"); |
300 | } |
301 | } |
302 | |
303 | void ExternalASTMerger::CompleteType(TagDecl *Tag) { |
304 | assert(Tag->hasExternalLexicalStorage()); |
305 | ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse, |
306 | Source<const DeclContext *> SourceDC) -> bool { |
307 | auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(Val: SourceDC.get())); |
308 | if (SourceTag->hasExternalLexicalStorage()) |
309 | SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag); |
310 | if (!SourceTag->getDefinition()) |
311 | return false; |
312 | Forward.MapImported(SourceTag, Tag); |
313 | if (llvm::Error Err = Forward.ImportDefinition(SourceTag)) |
314 | llvm::consumeError(Err: std::move(Err)); |
315 | Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); |
316 | return true; |
317 | }); |
318 | } |
319 | |
320 | void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) { |
321 | assert(Interface->hasExternalLexicalStorage()); |
322 | ForEachMatchingDC( |
323 | Interface, [&](ASTImporter &Forward, ASTImporter &Reverse, |
324 | Source<const DeclContext *> SourceDC) -> bool { |
325 | auto *SourceInterface = const_cast<ObjCInterfaceDecl *>( |
326 | cast<ObjCInterfaceDecl>(Val: SourceDC.get())); |
327 | if (SourceInterface->hasExternalLexicalStorage()) |
328 | SourceInterface->getASTContext().getExternalSource()->CompleteType( |
329 | SourceInterface); |
330 | if (!SourceInterface->getDefinition()) |
331 | return false; |
332 | Forward.MapImported(SourceInterface, Interface); |
333 | if (llvm::Error Err = Forward.ImportDefinition(SourceInterface)) |
334 | llvm::consumeError(Err: std::move(Err)); |
335 | return true; |
336 | }); |
337 | } |
338 | |
339 | bool ExternalASTMerger::CanComplete(DeclContext *Interface) { |
340 | assert(Interface->hasExternalLexicalStorage() || |
341 | Interface->hasExternalVisibleStorage()); |
342 | bool FoundMatchingDC = false; |
343 | ForEachMatchingDC(DC: Interface, |
344 | Callback: [&](ASTImporter &Forward, ASTImporter &Reverse, |
345 | Source<const DeclContext *> SourceDC) -> bool { |
346 | FoundMatchingDC = true; |
347 | return true; |
348 | }); |
349 | return FoundMatchingDC; |
350 | } |
351 | |
352 | namespace { |
353 | bool IsSameDC(const DeclContext *D1, const DeclContext *D2) { |
354 | if (isa<ObjCContainerDecl>(Val: D1) && isa<ObjCContainerDecl>(Val: D2)) |
355 | return true; // There are many cases where Objective-C is ambiguous. |
356 | if (auto *T1 = dyn_cast<TagDecl>(Val: D1)) |
357 | if (auto *T2 = dyn_cast<TagDecl>(Val: D2)) |
358 | if (T1->getFirstDecl() == T2->getFirstDecl()) |
359 | return true; |
360 | return D1 == D2 || D1 == CanonicalizeDC(DC: D2); |
361 | } |
362 | } |
363 | |
364 | void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC, |
365 | DCOrigin Origin) { |
366 | LazyASTImporter &Importer = LazyImporterForOrigin(Merger&: *this, OriginContext&: *Origin.AST); |
367 | ASTImporter &Reverse = Importer.GetReverse(); |
368 | Source<const DeclContext *> FoundFromDC = |
369 | LookupSameContext(SourceTU: Origin.AST->getTranslationUnitDecl(), DC: ToDC, ReverseImporter&: Reverse); |
370 | const bool DoRecord = !FoundFromDC || !IsSameDC(D1: FoundFromDC.get(), D2: Origin.DC); |
371 | if (DoRecord) |
372 | RecordOriginImpl(ToDC, Origin, importer&: Importer); |
373 | if (LoggingEnabled()) |
374 | logs() << "(ExternalASTMerger*)"<< (void*)this |
375 | << (DoRecord ? " decided ": " decided NOT") |
376 | << " to record origin (DeclContext*)"<< (void*)Origin.DC |
377 | << ", (ASTContext*)"<< (void*)&Origin.AST |
378 | << "\n"; |
379 | } |
380 | |
381 | void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC, |
382 | DCOrigin Origin) { |
383 | RecordOriginImpl(ToDC, Origin, importer&: ImporterForOrigin(OriginContext&: *Origin.AST)); |
384 | } |
385 | |
386 | void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, |
387 | ASTImporter &Importer) { |
388 | Origins[ToDC] = Origin; |
389 | Importer.ASTImporter::MapImported(From: cast<Decl>(Val: Origin.DC), To: const_cast<Decl*>(cast<Decl>(Val: ToDC))); |
390 | } |
391 | |
392 | ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target, |
393 | llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) { |
394 | SharedState = std::make_shared<ASTImporterSharedState>( |
395 | args&: *Target.AST.getTranslationUnitDecl()); |
396 | AddSources(Sources); |
397 | } |
398 | |
399 | Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) { |
400 | assert(&D->getASTContext() == &Target.AST); |
401 | for (const auto &I : Importers) |
402 | if (auto Result = I->GetOriginalDecl(To: D)) |
403 | return Result; |
404 | return nullptr; |
405 | } |
406 | |
407 | void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) { |
408 | for (const ImporterSource &S : Sources) { |
409 | assert(&S.getASTContext() != &Target.AST); |
410 | // Check that the associated merger actually imports into the source AST. |
411 | assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext()); |
412 | Importers.push_back(x: std::make_unique<LazyASTImporter>( |
413 | args&: *this, args&: Target.AST, args&: Target.FM, args: S, args&: SharedState)); |
414 | } |
415 | } |
416 | |
417 | void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) { |
418 | if (LoggingEnabled()) |
419 | for (const ImporterSource &S : Sources) |
420 | logs() << "(ExternalASTMerger*)"<< (void *)this |
421 | << " removing source (ASTContext*)"<< (void *)&S.getASTContext() |
422 | << "\n"; |
423 | llvm::erase_if(C&: Importers, |
424 | P: [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool { |
425 | for (const ImporterSource &S : Sources) { |
426 | if (&Importer->getFromContext() == &S.getASTContext()) |
427 | return true; |
428 | } |
429 | return false; |
430 | }); |
431 | for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) { |
432 | std::pair<const DeclContext *, DCOrigin> Origin = *OI; |
433 | bool Erase = false; |
434 | for (const ImporterSource &S : Sources) { |
435 | if (&S.getASTContext() == Origin.second.AST) { |
436 | Erase = true; |
437 | break; |
438 | } |
439 | } |
440 | if (Erase) |
441 | OI = Origins.erase(position: OI); |
442 | else |
443 | ++OI; |
444 | } |
445 | } |
446 | |
447 | template <typename DeclTy> |
448 | static bool importSpecializations(DeclTy *D, ASTImporter *Importer) { |
449 | for (auto *Spec : D->specializations()) { |
450 | auto ImportedSpecOrError = Importer->Import(Spec); |
451 | if (!ImportedSpecOrError) { |
452 | llvm::consumeError(Err: ImportedSpecOrError.takeError()); |
453 | return true; |
454 | } |
455 | } |
456 | return false; |
457 | } |
458 | |
459 | /// Imports specializations from template declarations that can be specialized. |
460 | static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) { |
461 | if (!isa<TemplateDecl>(Val: D)) |
462 | return false; |
463 | if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(Val: D)) |
464 | return importSpecializations(D: FunctionTD, Importer); |
465 | else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(Val: D)) |
466 | return importSpecializations(D: ClassTD, Importer); |
467 | else if (auto *VarTD = dyn_cast<VarTemplateDecl>(Val: D)) |
468 | return importSpecializations(D: VarTD, Importer); |
469 | return false; |
470 | } |
471 | |
472 | bool ExternalASTMerger::FindExternalVisibleDeclsByName( |
473 | const DeclContext *DC, DeclarationName Name, |
474 | const DeclContext *OriginalDC) { |
475 | llvm::SmallVector<NamedDecl *, 1> Decls; |
476 | llvm::SmallVector<Candidate, 4> Candidates; |
477 | |
478 | auto FilterFoundDecl = [&Candidates](const Candidate &C) { |
479 | if (!HasDeclOfSameType(Decls: Candidates, C)) |
480 | Candidates.push_back(Elt: C); |
481 | }; |
482 | |
483 | ForEachMatchingDC(DC, |
484 | Callback: [&](ASTImporter &Forward, ASTImporter &Reverse, |
485 | Source<const DeclContext *> SourceDC) -> bool { |
486 | auto FromNameOrErr = Reverse.Import(FromName: Name); |
487 | if (!FromNameOrErr) { |
488 | llvm::consumeError(Err: FromNameOrErr.takeError()); |
489 | return false; |
490 | } |
491 | DeclContextLookupResult Result = |
492 | SourceDC.get()->lookup(Name: *FromNameOrErr); |
493 | for (NamedDecl *FromD : Result) { |
494 | FilterFoundDecl(std::make_pair(x&: FromD, y: &Forward)); |
495 | } |
496 | return false; |
497 | }); |
498 | |
499 | if (Candidates.empty()) |
500 | return false; |
501 | |
502 | Decls.reserve(N: Candidates.size()); |
503 | for (const Candidate &C : Candidates) { |
504 | Decl *LookupRes = C.first.get(); |
505 | ASTImporter *Importer = C.second; |
506 | auto NDOrErr = Importer->Import(FromD: LookupRes); |
507 | NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr))); |
508 | assert(ND); |
509 | // If we don't import specialization, they are not available via lookup |
510 | // because the lookup result is imported TemplateDecl and it does not |
511 | // reference its specializations until they are imported explicitly. |
512 | bool IsSpecImportFailed = |
513 | importSpecializationsIfNeeded(D: LookupRes, Importer); |
514 | assert(!IsSpecImportFailed); |
515 | (void)IsSpecImportFailed; |
516 | Decls.push_back(Elt: ND); |
517 | } |
518 | SetExternalVisibleDeclsForName(DC, Name, Decls); |
519 | return true; |
520 | } |
521 | |
522 | void ExternalASTMerger::FindExternalLexicalDecls( |
523 | const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, |
524 | SmallVectorImpl<Decl *> &Result) { |
525 | ForEachMatchingDC(DC, Callback: [&](ASTImporter &Forward, ASTImporter &Reverse, |
526 | Source<const DeclContext *> SourceDC) -> bool { |
527 | for (const Decl *SourceDecl : SourceDC.get()->decls()) { |
528 | if (IsKindWeWant(SourceDecl->getKind())) { |
529 | auto ImportedDeclOrErr = Forward.Import(FromD: SourceDecl); |
530 | if (ImportedDeclOrErr) |
531 | assert(!(*ImportedDeclOrErr) || |
532 | IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC)); |
533 | else |
534 | llvm::consumeError(Err: ImportedDeclOrErr.takeError()); |
535 | } |
536 | } |
537 | return false; |
538 | }); |
539 | } |
540 |
Definitions
- Source
- Source
- operator T
- get
- get
- operator Source<U>
- CanonicalizeDC
- LookupSameContext
- LazyASTImporter
- logs
- LazyASTImporter
- ImportImpl
- GetOriginalDecl
- Imported
- GetReverse
- HasDeclOfSameType
- ImporterForOrigin
- LazyImporterForOrigin
- HasImporterForOrigin
- ForEachMatchingDC
- CompleteType
- CompleteType
- CanComplete
- IsSameDC
- MaybeRecordOrigin
- ForceRecordOrigin
- RecordOriginImpl
- ExternalASTMerger
- FindOriginalDecl
- AddSources
- RemoveSources
- importSpecializations
- importSpecializationsIfNeeded
- FindExternalVisibleDeclsByName
Learn to use CMake with our Intro Training
Find out more