1 //===- ExternalASTSource.h - Abstract 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 defines the ExternalASTSource interface, which enables 10 // construction of AST nodes from some external source. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H 15 #define LLVM_CLANG_AST_EXTERNALASTSOURCE_H 16 17 #include "clang/AST/CharUnits.h" 18 #include "clang/AST/DeclBase.h" 19 #include "clang/Basic/LLVM.h" 20 #include "clang/Basic/Module.h" 21 #include "llvm/ADT/ArrayRef.h" 22 #include "llvm/ADT/DenseMap.h" 23 #include "llvm/ADT/IntrusiveRefCntPtr.h" 24 #include "llvm/ADT/Optional.h" 25 #include "llvm/ADT/PointerUnion.h" 26 #include "llvm/ADT/STLExtras.h" 27 #include "llvm/ADT/SmallVector.h" 28 #include "llvm/ADT/StringRef.h" 29 #include "llvm/ADT/iterator.h" 30 #include "llvm/Support/PointerLikeTypeTraits.h" 31 #include <cassert> 32 #include <cstddef> 33 #include <cstdint> 34 #include <iterator> 35 #include <string> 36 #include <utility> 37 38 namespace clang { 39 40 class ASTConsumer; 41 class ASTContext; 42 class CXXBaseSpecifier; 43 class CXXCtorInitializer; 44 class CXXRecordDecl; 45 class DeclarationName; 46 class FieldDecl; 47 class IdentifierInfo; 48 class NamedDecl; 49 class ObjCInterfaceDecl; 50 class RecordDecl; 51 class Selector; 52 class Stmt; 53 class TagDecl; 54 55 /// Abstract interface for external sources of AST nodes. 56 /// 57 /// External AST sources provide AST nodes constructed from some 58 /// external source, such as a precompiled header. External AST 59 /// sources can resolve types and declarations from abstract IDs into 60 /// actual type and declaration nodes, and read parts of declaration 61 /// contexts. 62 class ExternalASTSource : public RefCountedBase<ExternalASTSource> { 63 friend class ExternalSemaSource; 64 65 /// Generation number for this external AST source. Must be increased 66 /// whenever we might have added new redeclarations for existing decls. 67 uint32_t CurrentGeneration = 0; 68 69 /// LLVM-style RTTI. 70 static char ID; 71 72 public: 73 ExternalASTSource() = default; 74 virtual ~ExternalASTSource(); 75 76 /// RAII class for safely pairing a StartedDeserializing call 77 /// with FinishedDeserializing. 78 class Deserializing { 79 ExternalASTSource *Source; 80 81 public: 82 explicit Deserializing(ExternalASTSource *source) : Source(source) { 83 assert(Source); 84 Source->StartedDeserializing(); 85 } 86 87 ~Deserializing() { 88 Source->FinishedDeserializing(); 89 } 90 }; 91 92 /// Get the current generation of this AST source. This number 93 /// is incremented each time the AST source lazily extends an existing 94 /// entity. 95 uint32_t getGeneration() const { return CurrentGeneration; } 96 97 /// Resolve a declaration ID into a declaration, potentially 98 /// building a new declaration. 99 /// 100 /// This method only needs to be implemented if the AST source ever 101 /// passes back decl sets as VisibleDeclaration objects. 102 /// 103 /// The default implementation of this method is a no-op. 104 virtual Decl *GetExternalDecl(uint32_t ID); 105 106 /// Resolve a selector ID into a selector. 107 /// 108 /// This operation only needs to be implemented if the AST source 109 /// returns non-zero for GetNumKnownSelectors(). 110 /// 111 /// The default implementation of this method is a no-op. 112 virtual Selector GetExternalSelector(uint32_t ID); 113 114 /// Returns the number of selectors known to the external AST 115 /// source. 116 /// 117 /// The default implementation of this method is a no-op. 118 virtual uint32_t GetNumExternalSelectors(); 119 120 /// Resolve the offset of a statement in the decl stream into 121 /// a statement. 122 /// 123 /// This operation is meant to be used via a LazyOffsetPtr. It only 124 /// needs to be implemented if the AST source uses methods like 125 /// FunctionDecl::setLazyBody when building decls. 126 /// 127 /// The default implementation of this method is a no-op. 128 virtual Stmt *GetExternalDeclStmt(uint64_t Offset); 129 130 /// Resolve the offset of a set of C++ constructor initializers in 131 /// the decl stream into an array of initializers. 132 /// 133 /// The default implementation of this method is a no-op. 134 virtual CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset); 135 136 /// Resolve the offset of a set of C++ base specifiers in the decl 137 /// stream into an array of specifiers. 138 /// 139 /// The default implementation of this method is a no-op. 140 virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); 141 142 /// Update an out-of-date identifier. 143 virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {} 144 145 /// Find all declarations with the given name in the given context, 146 /// and add them to the context by calling SetExternalVisibleDeclsForName 147 /// or SetNoExternalVisibleDeclsForName. 148 /// \return \c true if any declarations might have been found, \c false if 149 /// we definitely have no declarations with tbis name. 150 /// 151 /// The default implementation of this method is a no-op returning \c false. 152 virtual bool 153 FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); 154 155 /// Ensures that the table of all visible declarations inside this 156 /// context is up to date. 157 /// 158 /// The default implementation of this function is a no-op. 159 virtual void completeVisibleDeclsMap(const DeclContext *DC); 160 161 /// Retrieve the module that corresponds to the given module ID. 162 virtual Module *getModule(unsigned ID) { return nullptr; } 163 164 /// Determine whether D comes from a PCH which was built with a corresponding 165 /// object file. 166 virtual bool DeclIsFromPCHWithObjectFile(const Decl *D) { return false; } 167 168 /// Abstracts clang modules and precompiled header files and holds 169 /// everything needed to generate debug info for an imported module 170 /// or PCH. 171 class ASTSourceDescriptor { 172 StringRef PCHModuleName; 173 StringRef Path; 174 StringRef ASTFile; 175 ASTFileSignature Signature; 176 const Module *ClangModule = nullptr; 177 178 public: 179 ASTSourceDescriptor() = default; 180 ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile, 181 ASTFileSignature Signature) 182 : PCHModuleName(std::move(Name)), Path(std::move(Path)), 183 ASTFile(std::move(ASTFile)), Signature(Signature) {} 184 ASTSourceDescriptor(const Module &M); 185 186 std::string getModuleName() const; 187 StringRef getPath() const { return Path; } 188 StringRef getASTFile() const { return ASTFile; } 189 ASTFileSignature getSignature() const { return Signature; } 190 const Module *getModuleOrNull() const { return ClangModule; } 191 }; 192 193 /// Return a descriptor for the corresponding module, if one exists. 194 virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID); 195 196 enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy }; 197 198 virtual ExtKind hasExternalDefinitions(const Decl *D); 199 200 /// Finds all declarations lexically contained within the given 201 /// DeclContext, after applying an optional filter predicate. 202 /// 203 /// \param IsKindWeWant a predicate function that returns true if the passed 204 /// declaration kind is one we are looking for. 205 /// 206 /// The default implementation of this method is a no-op. 207 virtual void 208 FindExternalLexicalDecls(const DeclContext *DC, 209 llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, 210 SmallVectorImpl<Decl *> &Result); 211 212 /// Finds all declarations lexically contained within the given 213 /// DeclContext. 214 void FindExternalLexicalDecls(const DeclContext *DC, 215 SmallVectorImpl<Decl *> &Result) { 216 FindExternalLexicalDecls(DC, [](Decl::Kind) { return true; }, Result); 217 } 218 219 /// Get the decls that are contained in a file in the Offset/Length 220 /// range. \p Length can be 0 to indicate a point at \p Offset instead of 221 /// a range. 222 virtual void FindFileRegionDecls(FileID File, unsigned Offset, 223 unsigned Length, 224 SmallVectorImpl<Decl *> &Decls); 225 226 /// Gives the external AST source an opportunity to complete 227 /// the redeclaration chain for a declaration. Called each time we 228 /// need the most recent declaration of a declaration after the 229 /// generation count is incremented. 230 virtual void CompleteRedeclChain(const Decl *D); 231 232 /// Gives the external AST source an opportunity to complete 233 /// an incomplete type. 234 virtual void CompleteType(TagDecl *Tag); 235 236 /// Gives the external AST source an opportunity to complete an 237 /// incomplete Objective-C class. 238 /// 239 /// This routine will only be invoked if the "externally completed" bit is 240 /// set on the ObjCInterfaceDecl via the function 241 /// \c ObjCInterfaceDecl::setExternallyCompleted(). 242 virtual void CompleteType(ObjCInterfaceDecl *Class); 243 244 /// Loads comment ranges. 245 virtual void ReadComments(); 246 247 /// Notify ExternalASTSource that we started deserialization of 248 /// a decl or type so until FinishedDeserializing is called there may be 249 /// decls that are initializing. Must be paired with FinishedDeserializing. 250 /// 251 /// The default implementation of this method is a no-op. 252 virtual void StartedDeserializing(); 253 254 /// Notify ExternalASTSource that we finished the deserialization of 255 /// a decl or type. Must be paired with StartedDeserializing. 256 /// 257 /// The default implementation of this method is a no-op. 258 virtual void FinishedDeserializing(); 259 260 /// Function that will be invoked when we begin parsing a new 261 /// translation unit involving this external AST source. 262 /// 263 /// The default implementation of this method is a no-op. 264 virtual void StartTranslationUnit(ASTConsumer *Consumer); 265 266 /// Print any statistics that have been gathered regarding 267 /// the external AST source. 268 /// 269 /// The default implementation of this method is a no-op. 270 virtual void PrintStats(); 271 272 /// Perform layout on the given record. 273 /// 274 /// This routine allows the external AST source to provide an specific 275 /// layout for a record, overriding the layout that would normally be 276 /// constructed. It is intended for clients who receive specific layout 277 /// details rather than source code (such as LLDB). The client is expected 278 /// to fill in the field offsets, base offsets, virtual base offsets, and 279 /// complete object size. 280 /// 281 /// \param Record The record whose layout is being requested. 282 /// 283 /// \param Size The final size of the record, in bits. 284 /// 285 /// \param Alignment The final alignment of the record, in bits. 286 /// 287 /// \param FieldOffsets The offset of each of the fields within the record, 288 /// expressed in bits. All of the fields must be provided with offsets. 289 /// 290 /// \param BaseOffsets The offset of each of the direct, non-virtual base 291 /// classes. If any bases are not given offsets, the bases will be laid 292 /// out according to the ABI. 293 /// 294 /// \param VirtualBaseOffsets The offset of each of the virtual base classes 295 /// (either direct or not). If any bases are not given offsets, the bases will be laid 296 /// out according to the ABI. 297 /// 298 /// \returns true if the record layout was provided, false otherwise. 299 virtual bool layoutRecordType( 300 const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, 301 llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, 302 llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, 303 llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets); 304 305 //===--------------------------------------------------------------------===// 306 // Queries for performance analysis. 307 //===--------------------------------------------------------------------===// 308 309 struct MemoryBufferSizes { 310 size_t malloc_bytes; 311 size_t mmap_bytes; 312 313 MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) 314 : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} 315 }; 316 317 /// Return the amount of memory used by memory buffers, breaking down 318 /// by heap-backed versus mmap'ed memory. 319 MemoryBufferSizes getMemoryBufferSizes() const { 320 MemoryBufferSizes sizes(0, 0); 321 getMemoryBufferSizes(sizes); 322 return sizes; 323 } 324 325 virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const; 326 327 /// LLVM-style RTTI. 328 /// \{ 329 virtual bool isA(const void *ClassID) const { return ClassID == &ID; } 330 static bool classof(const ExternalASTSource *S) { return S->isA(&ID); } 331 /// \} 332 333 protected: 334 static DeclContextLookupResult 335 SetExternalVisibleDeclsForName(const DeclContext *DC, 336 DeclarationName Name, 337 ArrayRef<NamedDecl*> Decls); 338 339 static DeclContextLookupResult 340 SetNoExternalVisibleDeclsForName(const DeclContext *DC, 341 DeclarationName Name); 342 343 /// Increment the current generation. 344 uint32_t incrementGeneration(ASTContext &C); 345 }; 346 347 /// A lazy pointer to an AST node (of base type T) that resides 348 /// within an external AST source. 349 /// 350 /// The AST node is identified within the external AST source by a 351 /// 63-bit offset, and can be retrieved via an operation on the 352 /// external AST source itself. 353 template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)> 354 struct LazyOffsetPtr { 355 /// Either a pointer to an AST node or the offset within the 356 /// external AST source where the AST node can be found. 357 /// 358 /// If the low bit is clear, a pointer to the AST node. If the low 359 /// bit is set, the upper 63 bits are the offset. 360 mutable uint64_t Ptr = 0; 361 362 public: 363 LazyOffsetPtr() = default; 364 explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {} 365 366 explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) { 367 assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); 368 if (Offset == 0) 369 Ptr = 0; 370 } 371 372 LazyOffsetPtr &operator=(T *Ptr) { 373 this->Ptr = reinterpret_cast<uint64_t>(Ptr); 374 return *this; 375 } 376 377 LazyOffsetPtr &operator=(uint64_t Offset) { 378 assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); 379 if (Offset == 0) 380 Ptr = 0; 381 else 382 Ptr = (Offset << 1) | 0x01; 383 384 return *this; 385 } 386 387 /// Whether this pointer is non-NULL. 388 /// 389 /// This operation does not require the AST node to be deserialized. 390 explicit operator bool() const { return Ptr != 0; } 391 392 /// Whether this pointer is non-NULL. 393 /// 394 /// This operation does not require the AST node to be deserialized. 395 bool isValid() const { return Ptr != 0; } 396 397 /// Whether this pointer is currently stored as an offset. 398 bool isOffset() const { return Ptr & 0x01; } 399 400 /// Retrieve the pointer to the AST node that this lazy pointer points to. 401 /// 402 /// \param Source the external AST source. 403 /// 404 /// \returns a pointer to the AST node. 405 T* get(ExternalASTSource *Source) const { 406 if (isOffset()) { 407 assert(Source && 408 "Cannot deserialize a lazy pointer without an AST source"); 409 Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1)); 410 } 411 return reinterpret_cast<T*>(Ptr); 412 } 413 }; 414 415 /// A lazy value (of type T) that is within an AST node of type Owner, 416 /// where the value might change in later generations of the external AST 417 /// source. 418 template<typename Owner, typename T, void (ExternalASTSource::*Update)(Owner)> 419 struct LazyGenerationalUpdatePtr { 420 /// A cache of the value of this pointer, in the most recent generation in 421 /// which we queried it. 422 struct LazyData { 423 ExternalASTSource *ExternalSource; 424 uint32_t LastGeneration = 0; 425 T LastValue; 426 427 LazyData(ExternalASTSource *Source, T Value) 428 : ExternalSource(Source), LastValue(Value) {} 429 }; 430 431 // Our value is represented as simply T if there is no external AST source. 432 using ValueType = llvm::PointerUnion<T, LazyData*>; 433 ValueType Value; 434 435 LazyGenerationalUpdatePtr(ValueType V) : Value(V) {} 436 437 // Defined in ASTContext.h 438 static ValueType makeValue(const ASTContext &Ctx, T Value); 439 440 public: 441 explicit LazyGenerationalUpdatePtr(const ASTContext &Ctx, T Value = T()) 442 : Value(makeValue(Ctx, Value)) {} 443 444 /// Create a pointer that is not potentially updated by later generations of 445 /// the external AST source. 446 enum NotUpdatedTag { NotUpdated }; 447 LazyGenerationalUpdatePtr(NotUpdatedTag, T Value = T()) 448 : Value(Value) {} 449 450 /// Forcibly set this pointer (which must be lazy) as needing updates. 451 void markIncomplete() { 452 Value.template get<LazyData *>()->LastGeneration = 0; 453 } 454 455 /// Set the value of this pointer, in the current generation. 456 void set(T NewValue) { 457 if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) { 458 LazyVal->LastValue = NewValue; 459 return; 460 } 461 Value = NewValue; 462 } 463 464 /// Set the value of this pointer, for this and all future generations. 465 void setNotUpdated(T NewValue) { Value = NewValue; } 466 467 /// Get the value of this pointer, updating its owner if necessary. 468 T get(Owner O) { 469 if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) { 470 if (LazyVal->LastGeneration != LazyVal->ExternalSource->getGeneration()) { 471 LazyVal->LastGeneration = LazyVal->ExternalSource->getGeneration(); 472 (LazyVal->ExternalSource->*Update)(O); 473 } 474 return LazyVal->LastValue; 475 } 476 return Value.template get<T>(); 477 } 478 479 /// Get the most recently computed value of this pointer without updating it. 480 T getNotUpdated() const { 481 if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) 482 return LazyVal->LastValue; 483 return Value.template get<T>(); 484 } 485 486 void *getOpaqueValue() { return Value.getOpaqueValue(); } 487 static LazyGenerationalUpdatePtr getFromOpaqueValue(void *Ptr) { 488 return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr)); 489 } 490 }; 491 492 } // namespace clang 493 494 /// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be 495 /// placed into a PointerUnion. 496 namespace llvm { 497 498 template<typename Owner, typename T, 499 void (clang::ExternalASTSource::*Update)(Owner)> 500 struct PointerLikeTypeTraits< 501 clang::LazyGenerationalUpdatePtr<Owner, T, Update>> { 502 using Ptr = clang::LazyGenerationalUpdatePtr<Owner, T, Update>; 503 504 static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); } 505 static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); } 506 507 enum { 508 NumLowBitsAvailable = PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1 509 }; 510 }; 511 512 } // namespace llvm 513 514 namespace clang { 515 516 /// Represents a lazily-loaded vector of data. 517 /// 518 /// The lazily-loaded vector of data contains data that is partially loaded 519 /// from an external source and partially added by local translation. The 520 /// items loaded from the external source are loaded lazily, when needed for 521 /// iteration over the complete vector. 522 template<typename T, typename Source, 523 void (Source::*Loader)(SmallVectorImpl<T>&), 524 unsigned LoadedStorage = 2, unsigned LocalStorage = 4> 525 class LazyVector { 526 SmallVector<T, LoadedStorage> Loaded; 527 SmallVector<T, LocalStorage> Local; 528 529 public: 530 /// Iteration over the elements in the vector. 531 /// 532 /// In a complete iteration, the iterator walks the range [-M, N), 533 /// where negative values are used to indicate elements 534 /// loaded from the external source while non-negative values are used to 535 /// indicate elements added via \c push_back(). 536 /// However, to provide iteration in source order (for, e.g., chained 537 /// precompiled headers), dereferencing the iterator flips the negative 538 /// values (corresponding to loaded entities), so that position -M 539 /// corresponds to element 0 in the loaded entities vector, position -M+1 540 /// corresponds to element 1 in the loaded entities vector, etc. This 541 /// gives us a reasonably efficient, source-order walk. 542 /// 543 /// We define this as a wrapping iterator around an int. The 544 /// iterator_adaptor_base class forwards the iterator methods to basic integer 545 /// arithmetic. 546 class iterator 547 : public llvm::iterator_adaptor_base< 548 iterator, int, std::random_access_iterator_tag, T, int, T *, T &> { 549 friend class LazyVector; 550 551 LazyVector *Self; 552 553 iterator(LazyVector *Self, int Position) 554 : iterator::iterator_adaptor_base(Position), Self(Self) {} 555 556 bool isLoaded() const { return this->I < 0; } 557 558 public: 559 iterator() : iterator(nullptr, 0) {} 560 561 typename iterator::reference operator*() const { 562 if (isLoaded()) 563 return Self->Loaded.end()[this->I]; 564 return Self->Local.begin()[this->I]; 565 } 566 }; 567 568 iterator begin(Source *source, bool LocalOnly = false) { 569 if (LocalOnly) 570 return iterator(this, 0); 571 572 if (source) 573 (source->*Loader)(Loaded); 574 return iterator(this, -(int)Loaded.size()); 575 } 576 577 iterator end() { 578 return iterator(this, Local.size()); 579 } 580 581 void push_back(const T& LocalValue) { 582 Local.push_back(LocalValue); 583 } 584 585 void erase(iterator From, iterator To) { 586 if (From.isLoaded() && To.isLoaded()) { 587 Loaded.erase(&*From, &*To); 588 return; 589 } 590 591 if (From.isLoaded()) { 592 Loaded.erase(&*From, Loaded.end()); 593 From = begin(nullptr, true); 594 } 595 596 Local.erase(&*From, &*To); 597 } 598 }; 599 600 /// A lazy pointer to a statement. 601 using LazyDeclStmtPtr = 602 LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>; 603 604 /// A lazy pointer to a declaration. 605 using LazyDeclPtr = 606 LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>; 607 608 /// A lazy pointer to a set of CXXCtorInitializers. 609 using LazyCXXCtorInitializersPtr = 610 LazyOffsetPtr<CXXCtorInitializer *, uint64_t, 611 &ExternalASTSource::GetExternalCXXCtorInitializers>; 612 613 /// A lazy pointer to a set of CXXBaseSpecifiers. 614 using LazyCXXBaseSpecifiersPtr = 615 LazyOffsetPtr<CXXBaseSpecifier, uint64_t, 616 &ExternalASTSource::GetExternalCXXBaseSpecifiers>; 617 618 } // namespace clang 619 620 #endif // LLVM_CLANG_AST_EXTERNALASTSOURCE_H 621