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