1 //===-- ASTUtils.h ----------------------------------------------*- 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 #ifndef liblldb_ASTUtils_h_
10 #define liblldb_ASTUtils_h_
11 
12 #include "clang/Sema/Lookup.h"
13 #include "clang/Sema/MultiplexExternalSemaSource.h"
14 #include "clang/Sema/Sema.h"
15 #include "clang/Sema/SemaConsumer.h"
16 
17 namespace lldb_private {
18 
19 /// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take
20 /// ownership of the provided source.
21 class ExternalASTSourceWrapper : public clang::ExternalSemaSource {
22   ExternalASTSource *m_Source;
23 
24 public:
25   ExternalASTSourceWrapper(ExternalASTSource *Source) : m_Source(Source) {
26     assert(m_Source && "Can't wrap nullptr ExternalASTSource");
27   }
28 
29   ~ExternalASTSourceWrapper() override;
30 
31   clang::Decl *GetExternalDecl(uint32_t ID) override {
32     return m_Source->GetExternalDecl(ID);
33   }
34 
35   clang::Selector GetExternalSelector(uint32_t ID) override {
36     return m_Source->GetExternalSelector(ID);
37   }
38 
39   uint32_t GetNumExternalSelectors() override {
40     return m_Source->GetNumExternalSelectors();
41   }
42 
43   clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
44     return m_Source->GetExternalDeclStmt(Offset);
45   }
46 
47   clang::CXXCtorInitializer **
48   GetExternalCXXCtorInitializers(uint64_t Offset) override {
49     return m_Source->GetExternalCXXCtorInitializers(Offset);
50   }
51 
52   clang::CXXBaseSpecifier *
53   GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
54     return m_Source->GetExternalCXXBaseSpecifiers(Offset);
55   }
56 
57   void updateOutOfDateIdentifier(clang::IdentifierInfo &II) override {
58     m_Source->updateOutOfDateIdentifier(II);
59   }
60 
61   bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
62                                       clang::DeclarationName Name) override {
63     return m_Source->FindExternalVisibleDeclsByName(DC, Name);
64   }
65 
66   void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
67     m_Source->completeVisibleDeclsMap(DC);
68   }
69 
70   clang::Module *getModule(unsigned ID) override {
71     return m_Source->getModule(ID);
72   }
73 
74   llvm::Optional<ASTSourceDescriptor>
75   getSourceDescriptor(unsigned ID) override {
76     return m_Source->getSourceDescriptor(ID);
77   }
78 
79   ExtKind hasExternalDefinitions(const clang::Decl *D) override {
80     return m_Source->hasExternalDefinitions(D);
81   }
82 
83   void FindExternalLexicalDecls(
84       const clang::DeclContext *DC,
85       llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
86       llvm::SmallVectorImpl<clang::Decl *> &Result) override {
87     m_Source->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
88   }
89 
90   void
91   FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
92                       llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
93     m_Source->FindFileRegionDecls(File, Offset, Length, Decls);
94   }
95 
96   void CompleteRedeclChain(const clang::Decl *D) override {
97     m_Source->CompleteRedeclChain(D);
98   }
99 
100   void CompleteType(clang::TagDecl *Tag) override {
101     m_Source->CompleteType(Tag);
102   }
103 
104   void CompleteType(clang::ObjCInterfaceDecl *Class) override {
105     m_Source->CompleteType(Class);
106   }
107 
108   void ReadComments() override { m_Source->ReadComments(); }
109 
110   void StartedDeserializing() override { m_Source->StartedDeserializing(); }
111 
112   void FinishedDeserializing() override { m_Source->FinishedDeserializing(); }
113 
114   void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
115     m_Source->StartTranslationUnit(Consumer);
116   }
117 
118   void PrintStats() override;
119 
120   bool layoutRecordType(
121       const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
122       llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
123       llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
124           &BaseOffsets,
125       llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
126           &VirtualBaseOffsets) override {
127     return m_Source->layoutRecordType(Record, Size, Alignment, FieldOffsets,
128                                       BaseOffsets, VirtualBaseOffsets);
129   }
130 };
131 
132 /// Wraps an ASTConsumer into an SemaConsumer. Doesn't take ownership of the
133 /// provided consumer. If the provided ASTConsumer is also a SemaConsumer,
134 /// the wrapper will also forward SemaConsumer functions.
135 class ASTConsumerForwarder : public clang::SemaConsumer {
136   clang::ASTConsumer *m_c;
137   clang::SemaConsumer *m_sc;
138 
139 public:
140   ASTConsumerForwarder(clang::ASTConsumer *c) : m_c(c) {
141     m_sc = llvm::dyn_cast<clang::SemaConsumer>(m_c);
142   }
143 
144   ~ASTConsumerForwarder() override;
145 
146   void Initialize(clang::ASTContext &Context) override {
147     m_c->Initialize(Context);
148   }
149 
150   bool HandleTopLevelDecl(clang::DeclGroupRef D) override {
151     return m_c->HandleTopLevelDecl(D);
152   }
153 
154   void HandleInlineFunctionDefinition(clang::FunctionDecl *D) override {
155     m_c->HandleInlineFunctionDefinition(D);
156   }
157 
158   void HandleInterestingDecl(clang::DeclGroupRef D) override {
159     m_c->HandleInterestingDecl(D);
160   }
161 
162   void HandleTranslationUnit(clang::ASTContext &Ctx) override {
163     m_c->HandleTranslationUnit(Ctx);
164   }
165 
166   void HandleTagDeclDefinition(clang::TagDecl *D) override {
167     m_c->HandleTagDeclDefinition(D);
168   }
169 
170   void HandleTagDeclRequiredDefinition(const clang::TagDecl *D) override {
171     m_c->HandleTagDeclRequiredDefinition(D);
172   }
173 
174   void HandleCXXImplicitFunctionInstantiation(clang::FunctionDecl *D) override {
175     m_c->HandleCXXImplicitFunctionInstantiation(D);
176   }
177 
178   void HandleTopLevelDeclInObjCContainer(clang::DeclGroupRef D) override {
179     m_c->HandleTopLevelDeclInObjCContainer(D);
180   }
181 
182   void HandleImplicitImportDecl(clang::ImportDecl *D) override {
183     m_c->HandleImplicitImportDecl(D);
184   }
185 
186   void CompleteTentativeDefinition(clang::VarDecl *D) override {
187     m_c->CompleteTentativeDefinition(D);
188   }
189 
190   void AssignInheritanceModel(clang::CXXRecordDecl *RD) override {
191     m_c->AssignInheritanceModel(RD);
192   }
193 
194   void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *D) override {
195     m_c->HandleCXXStaticMemberVarInstantiation(D);
196   }
197 
198   void HandleVTable(clang::CXXRecordDecl *RD) override {
199     m_c->HandleVTable(RD);
200   }
201 
202   clang::ASTMutationListener *GetASTMutationListener() override {
203     return m_c->GetASTMutationListener();
204   }
205 
206   clang::ASTDeserializationListener *GetASTDeserializationListener() override {
207     return m_c->GetASTDeserializationListener();
208   }
209 
210   void PrintStats() override;
211 
212   void InitializeSema(clang::Sema &S) override {
213     if (m_sc)
214       m_sc->InitializeSema(S);
215   }
216 
217   /// Inform the semantic consumer that Sema is no longer available.
218   void ForgetSema() override {
219     if (m_sc)
220       m_sc->ForgetSema();
221   }
222 
223   bool shouldSkipFunctionBody(clang::Decl *D) override {
224     return m_c->shouldSkipFunctionBody(D);
225   }
226 };
227 
228 /// A ExternalSemaSource multiplexer that prioritizes its sources.
229 ///
230 /// This ExternalSemaSource will forward all requests to its attached sources.
231 /// However, unlike a normal multiplexer it will not forward a request to all
232 /// sources, but instead give priority to certain sources. If a source with a
233 /// higher priority can fulfill a request, all sources with a lower priority
234 /// will not receive the request.
235 ///
236 /// This class is mostly use to multiplex between sources of different
237 /// 'quality', e.g. a C++ modules and debug information. The C++ module will
238 /// provide more accurate replies to the requests, but might not be able to
239 /// answer all requests. The debug information will be used as a fallback then
240 /// to provide information that is not in the C++ module.
241 class SemaSourceWithPriorities : public clang::ExternalSemaSource {
242 
243 private:
244   /// The sources ordered in decreasing priority.
245   llvm::SmallVector<clang::ExternalSemaSource *, 2> Sources;
246 
247 public:
248   /// Construct a SemaSourceWithPriorities with a 'high quality' source that
249   /// has the higher priority and a 'low quality' source that will be used
250   /// as a fallback.
251   SemaSourceWithPriorities(clang::ExternalSemaSource &high_quality_source,
252                            clang::ExternalSemaSource &low_quality_source) {
253     Sources.push_back(&high_quality_source);
254     Sources.push_back(&low_quality_source);
255   }
256 
257   ~SemaSourceWithPriorities() override;
258 
259   void addSource(clang::ExternalSemaSource &source) {
260     Sources.push_back(&source);
261   }
262 
263   //===--------------------------------------------------------------------===//
264   // ExternalASTSource.
265   //===--------------------------------------------------------------------===//
266 
267   clang::Decl *GetExternalDecl(uint32_t ID) override {
268     for (size_t i = 0; i < Sources.size(); ++i)
269       if (clang::Decl *Result = Sources[i]->GetExternalDecl(ID))
270         return Result;
271     return nullptr;
272   }
273 
274   void CompleteRedeclChain(const clang::Decl *D) override {
275     for (size_t i = 0; i < Sources.size(); ++i)
276       Sources[i]->CompleteRedeclChain(D);
277   }
278 
279   clang::Selector GetExternalSelector(uint32_t ID) override {
280     clang::Selector Sel;
281     for (size_t i = 0; i < Sources.size(); ++i) {
282       Sel = Sources[i]->GetExternalSelector(ID);
283       if (!Sel.isNull())
284         return Sel;
285     }
286     return Sel;
287   }
288 
289   uint32_t GetNumExternalSelectors() override {
290     for (size_t i = 0; i < Sources.size(); ++i)
291       if (uint32_t total = Sources[i]->GetNumExternalSelectors())
292         return total;
293     return 0;
294   }
295 
296   clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
297     for (size_t i = 0; i < Sources.size(); ++i)
298       if (clang::Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset))
299         return Result;
300     return nullptr;
301   }
302 
303   clang::CXXBaseSpecifier *
304   GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
305     for (size_t i = 0; i < Sources.size(); ++i)
306       if (clang::CXXBaseSpecifier *R =
307               Sources[i]->GetExternalCXXBaseSpecifiers(Offset))
308         return R;
309     return nullptr;
310   }
311 
312   clang::CXXCtorInitializer **
313   GetExternalCXXCtorInitializers(uint64_t Offset) override {
314     for (auto *S : Sources)
315       if (auto *R = S->GetExternalCXXCtorInitializers(Offset))
316         return R;
317     return nullptr;
318   }
319 
320   ExtKind hasExternalDefinitions(const clang::Decl *D) override {
321     for (const auto &S : Sources)
322       if (auto EK = S->hasExternalDefinitions(D))
323         if (EK != EK_ReplyHazy)
324           return EK;
325     return EK_ReplyHazy;
326   }
327 
328   bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
329                                       clang::DeclarationName Name) override {
330     for (size_t i = 0; i < Sources.size(); ++i)
331       if (Sources[i]->FindExternalVisibleDeclsByName(DC, Name))
332         return true;
333     return false;
334   }
335 
336   void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
337     // FIXME: Only one source should be able to complete the decls map.
338     for (size_t i = 0; i < Sources.size(); ++i)
339       Sources[i]->completeVisibleDeclsMap(DC);
340   }
341 
342   void FindExternalLexicalDecls(
343       const clang::DeclContext *DC,
344       llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
345       llvm::SmallVectorImpl<clang::Decl *> &Result) override {
346     for (size_t i = 0; i < Sources.size(); ++i) {
347       Sources[i]->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
348       if (!Result.empty())
349         return;
350     }
351   }
352 
353   void
354   FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
355                       llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
356     for (size_t i = 0; i < Sources.size(); ++i)
357       Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls);
358   }
359 
360   void CompleteType(clang::TagDecl *Tag) override {
361     while (!Tag->isCompleteDefinition())
362       for (size_t i = 0; i < Sources.size(); ++i) {
363         // FIXME: We are technically supposed to loop here too until
364         // Tag->isCompleteDefinition() is true, but if our low quality source
365         // is failing to complete the tag this code will deadlock.
366         Sources[i]->CompleteType(Tag);
367         if (Tag->isCompleteDefinition())
368           break;
369       }
370   }
371 
372   void CompleteType(clang::ObjCInterfaceDecl *Class) override {
373     for (size_t i = 0; i < Sources.size(); ++i)
374       Sources[i]->CompleteType(Class);
375   }
376 
377   void ReadComments() override {
378     for (size_t i = 0; i < Sources.size(); ++i)
379       Sources[i]->ReadComments();
380   }
381 
382   void StartedDeserializing() override {
383     for (size_t i = 0; i < Sources.size(); ++i)
384       Sources[i]->StartedDeserializing();
385   }
386 
387   void FinishedDeserializing() override {
388     for (size_t i = 0; i < Sources.size(); ++i)
389       Sources[i]->FinishedDeserializing();
390   }
391 
392   void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
393     for (size_t i = 0; i < Sources.size(); ++i)
394       Sources[i]->StartTranslationUnit(Consumer);
395   }
396 
397   void PrintStats() override;
398 
399   clang::Module *getModule(unsigned ID) override {
400     for (size_t i = 0; i < Sources.size(); ++i)
401       if (auto M = Sources[i]->getModule(ID))
402         return M;
403     return nullptr;
404   }
405 
406   bool DeclIsFromPCHWithObjectFile(const clang::Decl *D) override {
407     for (auto *S : Sources)
408       if (S->DeclIsFromPCHWithObjectFile(D))
409         return true;
410     return false;
411   }
412 
413   bool layoutRecordType(
414       const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
415       llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
416       llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
417           &BaseOffsets,
418       llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
419           &VirtualBaseOffsets) override {
420     for (size_t i = 0; i < Sources.size(); ++i)
421       if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets,
422                                        BaseOffsets, VirtualBaseOffsets))
423         return true;
424     return false;
425   }
426 
427   void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
428     for (auto &Source : Sources)
429       Source->getMemoryBufferSizes(sizes);
430   }
431 
432   //===--------------------------------------------------------------------===//
433   // ExternalSemaSource.
434   //===--------------------------------------------------------------------===//
435 
436   void InitializeSema(clang::Sema &S) override {
437     for (auto &Source : Sources)
438       Source->InitializeSema(S);
439   }
440 
441   void ForgetSema() override {
442     for (auto &Source : Sources)
443       Source->ForgetSema();
444   }
445 
446   void ReadMethodPool(clang::Selector Sel) override {
447     for (auto &Source : Sources)
448       Source->ReadMethodPool(Sel);
449   }
450 
451   void updateOutOfDateSelector(clang::Selector Sel) override {
452     for (auto &Source : Sources)
453       Source->updateOutOfDateSelector(Sel);
454   }
455 
456   void ReadKnownNamespaces(
457       llvm::SmallVectorImpl<clang::NamespaceDecl *> &Namespaces) override {
458     for (auto &Source : Sources)
459       Source->ReadKnownNamespaces(Namespaces);
460   }
461 
462   void ReadUndefinedButUsed(
463       llvm::MapVector<clang::NamedDecl *, clang::SourceLocation> &Undefined)
464       override {
465     for (auto &Source : Sources)
466       Source->ReadUndefinedButUsed(Undefined);
467   }
468 
469   void ReadMismatchingDeleteExpressions(
470       llvm::MapVector<clang::FieldDecl *,
471                       llvm::SmallVector<std::pair<clang::SourceLocation, bool>,
472                                         4>> &Exprs) override {
473     for (auto &Source : Sources)
474       Source->ReadMismatchingDeleteExpressions(Exprs);
475   }
476 
477   bool LookupUnqualified(clang::LookupResult &R, clang::Scope *S) override {
478     for (auto &Source : Sources) {
479       Source->LookupUnqualified(R, S);
480       if (!R.empty())
481         break;
482     }
483 
484     return !R.empty();
485   }
486 
487   void ReadTentativeDefinitions(
488       llvm::SmallVectorImpl<clang::VarDecl *> &Defs) override {
489     for (auto &Source : Sources)
490       Source->ReadTentativeDefinitions(Defs);
491   }
492 
493   void ReadUnusedFileScopedDecls(
494       llvm::SmallVectorImpl<const clang::DeclaratorDecl *> &Decls) override {
495     for (auto &Source : Sources)
496       Source->ReadUnusedFileScopedDecls(Decls);
497   }
498 
499   void ReadDelegatingConstructors(
500       llvm::SmallVectorImpl<clang::CXXConstructorDecl *> &Decls) override {
501     for (auto &Source : Sources)
502       Source->ReadDelegatingConstructors(Decls);
503   }
504 
505   void ReadExtVectorDecls(
506       llvm::SmallVectorImpl<clang::TypedefNameDecl *> &Decls) override {
507     for (auto &Source : Sources)
508       Source->ReadExtVectorDecls(Decls);
509   }
510 
511   void ReadUnusedLocalTypedefNameCandidates(
512       llvm::SmallSetVector<const clang::TypedefNameDecl *, 4> &Decls) override {
513     for (auto &Source : Sources)
514       Source->ReadUnusedLocalTypedefNameCandidates(Decls);
515   }
516 
517   void ReadReferencedSelectors(
518       llvm::SmallVectorImpl<std::pair<clang::Selector, clang::SourceLocation>>
519           &Sels) override {
520     for (auto &Source : Sources)
521       Source->ReadReferencedSelectors(Sels);
522   }
523 
524   void ReadWeakUndeclaredIdentifiers(
525       llvm::SmallVectorImpl<std::pair<clang::IdentifierInfo *, clang::WeakInfo>>
526           &WI) override {
527     for (auto &Source : Sources)
528       Source->ReadWeakUndeclaredIdentifiers(WI);
529   }
530 
531   void ReadUsedVTables(
532       llvm::SmallVectorImpl<clang::ExternalVTableUse> &VTables) override {
533     for (auto &Source : Sources)
534       Source->ReadUsedVTables(VTables);
535   }
536 
537   void ReadPendingInstantiations(
538       llvm::SmallVectorImpl<
539           std::pair<clang::ValueDecl *, clang::SourceLocation>> &Pending)
540       override {
541     for (auto &Source : Sources)
542       Source->ReadPendingInstantiations(Pending);
543   }
544 
545   void ReadLateParsedTemplates(
546       llvm::MapVector<const clang::FunctionDecl *,
547                       std::unique_ptr<clang::LateParsedTemplate>> &LPTMap)
548       override {
549     for (auto &Source : Sources)
550       Source->ReadLateParsedTemplates(LPTMap);
551   }
552 
553   clang::TypoCorrection
554   CorrectTypo(const clang::DeclarationNameInfo &Typo, int LookupKind,
555               clang::Scope *S, clang::CXXScopeSpec *SS,
556               clang::CorrectionCandidateCallback &CCC,
557               clang::DeclContext *MemberContext, bool EnteringContext,
558               const clang::ObjCObjectPointerType *OPT) override {
559     for (auto &Source : Sources) {
560       if (clang::TypoCorrection C =
561               Source->CorrectTypo(Typo, LookupKind, S, SS, CCC,
562                                       MemberContext, EnteringContext, OPT))
563         return C;
564     }
565     return clang::TypoCorrection();
566   }
567 
568   bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc,
569                                         clang::QualType T) override {
570     for (auto &Source : Sources) {
571       if (Source->MaybeDiagnoseMissingCompleteType(Loc, T))
572         return true;
573     }
574     return false;
575   }
576 };
577 
578 } // namespace lldb_private
579 #endif // liblldb_ASTUtils_h_
580