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