1 //===-- ClangASTImporter.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_CLANGASTIMPORTER_H 10 #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H 11 12 #include <map> 13 #include <memory> 14 #include <set> 15 #include <vector> 16 17 #include "clang/AST/ASTContext.h" 18 #include "clang/AST/ASTImporter.h" 19 #include "clang/AST/CharUnits.h" 20 #include "clang/AST/Decl.h" 21 #include "clang/AST/DeclCXX.h" 22 #include "clang/Basic/FileManager.h" 23 #include "clang/Basic/FileSystemOptions.h" 24 25 #include "lldb/Host/FileSystem.h" 26 #include "lldb/Symbol/CompilerDeclContext.h" 27 #include "lldb/Utility/LLDBAssert.h" 28 #include "lldb/lldb-types.h" 29 30 #include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" 31 32 #include "llvm/ADT/DenseMap.h" 33 34 namespace lldb_private { 35 36 class ClangASTMetadata; 37 class TypeSystemClang; 38 39 /// Manages and observes all Clang AST node importing in LLDB. 40 /// 41 /// The ClangASTImporter takes care of two things: 42 /// 43 /// 1. Keeps track of all ASTImporter instances in LLDB. 44 /// 45 /// Clang's ASTImporter takes care of importing types from one ASTContext to 46 /// another. This class expands this concept by allowing copying from several 47 /// ASTContext instances to several other ASTContext instances. Instead of 48 /// constructing a new ASTImporter manually to copy over a type/decl, this class 49 /// can be asked to do this. It will construct a ASTImporter for the caller (and 50 /// will cache the ASTImporter instance for later use) and then perform the 51 /// import. 52 /// 53 /// This mainly prevents that a caller might construct several ASTImporter 54 /// instances for the same source/target ASTContext combination. As the 55 /// ASTImporter has an internal state that keeps track of already imported 56 /// declarations and so on, using only one ASTImporter instance is more 57 /// efficient and less error-prone than using multiple. 58 /// 59 /// 2. Keeps track of from where declarations were imported (origin-tracking). 60 /// The ASTImporter instances in this class usually only performa a minimal 61 /// import, i.e., only a shallow copy is made that is filled out on demand 62 /// when more information is requested later on. This requires record-keeping 63 /// of where any shallow clone originally came from so that the right original 64 /// declaration can be found and used as the source of any missing information. 65 class ClangASTImporter { 66 public: 67 struct LayoutInfo { 68 LayoutInfo() = default; 69 typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 70 OffsetMap; 71 72 uint64_t bit_size = 0; 73 uint64_t alignment = 0; 74 llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets; 75 OffsetMap base_offsets; 76 OffsetMap vbase_offsets; 77 }; 78 79 ClangASTImporter() 80 : m_file_manager(clang::FileSystemOptions(), 81 FileSystem::Instance().GetVirtualFileSystem()) {} 82 83 /// Copies the given type and the respective declarations to the destination 84 /// type system. 85 /// 86 /// This function does a shallow copy and requires that the target AST 87 /// has an ExternalASTSource which queries this ClangASTImporter instance 88 /// for any additional information that is maybe lacking in the shallow copy. 89 /// This also means that the type system of src_type can *not* be deleted 90 /// after this function has been called. If you need to delete the source 91 /// type system you either need to delete the destination type system first 92 /// or use \ref ClangASTImporter::DeportType. 93 /// 94 /// \see ClangASTImporter::DeportType 95 CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type); 96 97 /// \see ClangASTImporter::CopyType 98 clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); 99 100 /// Copies the given type and the respective declarations to the destination 101 /// type system. 102 /// 103 /// Unlike CopyType this function ensures that types/declarations which are 104 /// originally from the AST of src_type are fully copied over. The type 105 /// system of src_type can safely be deleted after calling this function. 106 /// \see ClangASTImporter::CopyType 107 CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type); 108 109 /// Copies the given decl to the destination type system. 110 /// \see ClangASTImporter::DeportType 111 clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); 112 113 /// Sets the layout for the given RecordDecl. The layout will later be 114 /// used by Clang's during code generation. Not calling this function for 115 /// a RecordDecl will cause that Clang's codegen tries to layout the 116 /// record by itself. 117 /// 118 /// \param decl The RecordDecl to set the layout for. 119 /// \param layout The layout for the record. 120 void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout); 121 122 bool LayoutRecordType( 123 const clang::RecordDecl *record_decl, uint64_t &bit_size, 124 uint64_t &alignment, 125 llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, 126 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 127 &base_offsets, 128 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 129 &vbase_offsets); 130 131 /// If \ref record has a valid origin, this function copies that 132 /// origin's layout into this ClangASTImporter instance. 133 /// 134 /// \param[in] record The decl whose layout we're calculating. 135 /// \param[out] size Size of \ref record in bytes. 136 /// \param[out] alignment Alignment of \ref record in bytes. 137 /// \param[out] field_offsets Offsets of fields of \ref record. 138 /// \param[out] base_offsets Offsets of base classes of \ref record. 139 /// \param[out] vbase_offsets Offsets of virtual base classes of \ref record. 140 /// 141 /// \returns Returns 'false' if no valid origin was found for \ref record or 142 /// this function failed to import the layout from the origin. Otherwise, 143 /// returns 'true' and the offsets/size/alignment are valid for use. 144 bool importRecordLayoutFromOrigin( 145 const clang::RecordDecl *record, uint64_t &size, uint64_t &alignment, 146 llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, 147 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 148 &base_offsets, 149 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 150 &vbase_offsets); 151 152 /// Returns true iff the given type was copied from another TypeSystemClang 153 /// and the original type in this other TypeSystemClang might contain 154 /// additional information (e.g., the definition of a 'class' type) that could 155 /// be imported. 156 /// 157 /// \see ClangASTImporter::Import 158 bool CanImport(const CompilerType &type); 159 160 /// If the given type was copied from another TypeSystemClang then copy over 161 /// all missing information (e.g., the definition of a 'class' type). 162 /// 163 /// \return True iff an original type in another TypeSystemClang was found. 164 /// Note: Does *not* return false if an original type was found but 165 /// no information was imported over. 166 /// 167 /// \see ClangASTImporter::Import 168 bool Import(const CompilerType &type); 169 170 bool CompleteType(const CompilerType &compiler_type); 171 172 bool CompleteTagDecl(clang::TagDecl *decl); 173 174 bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin); 175 176 bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl); 177 178 bool CompleteAndFetchChildren(clang::QualType type); 179 180 bool RequireCompleteType(clang::QualType type); 181 182 /// Updates the internal origin-tracking information so that the given 183 /// 'original' decl is from now on used to import additional information 184 /// into the given decl. 185 /// 186 /// Usually the origin-tracking in the ClangASTImporter is automatically 187 /// updated when a declaration is imported, so the only valid reason to ever 188 /// call this is if there is a 'better' original decl and the target decl 189 /// is only a shallow clone that lacks any contents. 190 void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl); 191 192 std::optional<ClangASTMetadata> GetDeclMetadata(const clang::Decl *decl); 193 194 // 195 // Namespace maps 196 // 197 198 typedef std::pair<lldb::ModuleSP, CompilerDeclContext> NamespaceMapItem; 199 typedef std::vector<NamespaceMapItem> NamespaceMap; 200 typedef std::shared_ptr<NamespaceMap> NamespaceMapSP; 201 202 void RegisterNamespaceMap(const clang::NamespaceDecl *decl, 203 NamespaceMapSP &namespace_map); 204 205 NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl); 206 207 void BuildNamespaceMap(const clang::NamespaceDecl *decl); 208 209 // 210 // Completers for maps 211 // 212 213 class MapCompleter { 214 public: 215 virtual ~MapCompleter(); 216 217 virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map, 218 ConstString name, 219 NamespaceMapSP &parent_map) const = 0; 220 }; 221 222 void InstallMapCompleter(clang::ASTContext *dst_ctx, 223 MapCompleter &completer) { 224 ASTContextMetadataSP context_md; 225 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 226 227 if (context_md_iter == m_metadata_map.end()) { 228 context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); 229 m_metadata_map[dst_ctx] = context_md; 230 } else { 231 context_md = context_md_iter->second; 232 } 233 234 context_md->m_map_completer = &completer; 235 } 236 237 void ForgetDestination(clang::ASTContext *dst_ctx); 238 void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx); 239 240 struct DeclOrigin { 241 DeclOrigin() = default; 242 243 DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl) 244 : ctx(_ctx), decl(_decl) { 245 // The decl has to be in its associated ASTContext. 246 assert(_decl == nullptr || &_decl->getASTContext() == _ctx); 247 } 248 249 DeclOrigin(const DeclOrigin &rhs) { 250 ctx = rhs.ctx; 251 decl = rhs.decl; 252 } 253 254 void operator=(const DeclOrigin &rhs) { 255 ctx = rhs.ctx; 256 decl = rhs.decl; 257 } 258 259 bool Valid() const { return (ctx != nullptr || decl != nullptr); } 260 261 clang::ASTContext *ctx = nullptr; 262 clang::Decl *decl = nullptr; 263 }; 264 265 /// Listener interface used by the ASTImporterDelegate to inform other code 266 /// about decls that have been imported the first time. 267 struct NewDeclListener { 268 virtual ~NewDeclListener() = default; 269 /// A decl has been imported for the first time. 270 virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0; 271 }; 272 273 /// ASTImporter that intercepts and records the import process of the 274 /// underlying ASTImporter. 275 /// 276 /// This class updates the map from declarations to their original 277 /// declarations and can record declarations that have been imported in a 278 /// certain interval. 279 /// 280 /// When intercepting a declaration import, the ASTImporterDelegate uses the 281 /// CxxModuleHandler to replace any missing or malformed declarations with 282 /// their counterpart from a C++ module. 283 struct ASTImporterDelegate : public clang::ASTImporter { 284 ASTImporterDelegate(ClangASTImporter &main, clang::ASTContext *target_ctx, 285 clang::ASTContext *source_ctx) 286 : clang::ASTImporter(*target_ctx, main.m_file_manager, *source_ctx, 287 main.m_file_manager, true /*minimal*/), 288 m_main(main), m_source_ctx(source_ctx) { 289 // Target and source ASTContext shouldn't be identical. Importing AST 290 // nodes within the same AST doesn't make any sense as the whole idea 291 // is to import them to a different AST. 292 lldbassert(target_ctx != source_ctx && "Can't import into itself"); 293 // This is always doing a minimal import of any declarations. This means 294 // that there has to be an ExternalASTSource in the target ASTContext 295 // (that should implement the callbacks that complete any declarations 296 // on demand). Without an ExternalASTSource, this ASTImporter will just 297 // do a minimal import and the imported declarations won't be completed. 298 assert(target_ctx->getExternalSource() && "Missing ExternalSource"); 299 setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal); 300 } 301 302 /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate 303 /// and deattaches it at the end of the scope. Supports being used multiple 304 /// times on the same ASTImporterDelegate instance in nested scopes. 305 class CxxModuleScope { 306 /// The handler we attach to the ASTImporterDelegate. 307 CxxModuleHandler m_handler; 308 /// The ASTImporterDelegate we are supposed to attach the handler to. 309 ASTImporterDelegate &m_delegate; 310 /// True iff we attached the handler to the ASTImporterDelegate. 311 bool m_valid = false; 312 313 public: 314 CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx) 315 : m_delegate(delegate) { 316 // If the delegate doesn't have a CxxModuleHandler yet, create one 317 // and attach it. 318 if (!delegate.m_std_handler) { 319 m_handler = CxxModuleHandler(delegate, dst_ctx); 320 m_valid = true; 321 delegate.m_std_handler = &m_handler; 322 } 323 } 324 ~CxxModuleScope() { 325 if (m_valid) { 326 // Make sure no one messed with the handler we placed. 327 assert(m_delegate.m_std_handler == &m_handler); 328 m_delegate.m_std_handler = nullptr; 329 } 330 } 331 }; 332 333 void ImportDefinitionTo(clang::Decl *to, clang::Decl *from); 334 335 void Imported(clang::Decl *from, clang::Decl *to) override; 336 337 clang::Decl *GetOriginalDecl(clang::Decl *To) override; 338 339 void SetImportListener(NewDeclListener *listener) { 340 assert(m_new_decl_listener == nullptr && "Already attached a listener?"); 341 m_new_decl_listener = listener; 342 } 343 void RemoveImportListener() { m_new_decl_listener = nullptr; } 344 345 protected: 346 llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override; 347 348 private: 349 /// Decls we should ignore when mapping decls back to their original 350 /// ASTContext. Used by the CxxModuleHandler to mark declarations that 351 /// were created from the 'std' C++ module to prevent that the Importer 352 /// tries to sync them with the broken equivalent in the debug info AST. 353 llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore; 354 ClangASTImporter &m_main; 355 clang::ASTContext *m_source_ctx; 356 CxxModuleHandler *m_std_handler = nullptr; 357 /// The currently attached listener. 358 NewDeclListener *m_new_decl_listener = nullptr; 359 }; 360 361 typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP; 362 typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap; 363 typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP> 364 NamespaceMetaMap; 365 366 class ASTContextMetadata { 367 typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; 368 369 public: 370 ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {} 371 372 clang::ASTContext *m_dst_ctx; 373 DelegateMap m_delegates; 374 375 NamespaceMetaMap m_namespace_maps; 376 MapCompleter *m_map_completer = nullptr; 377 378 /// Sets the DeclOrigin for the given Decl and overwrites any existing 379 /// DeclOrigin. 380 void setOrigin(const clang::Decl *decl, DeclOrigin origin) { 381 // Setting the origin of any decl to itself (or to a different decl 382 // in the same ASTContext) doesn't make any sense. It will also cause 383 // ASTImporterDelegate::ImportImpl to infinite recurse when trying to find 384 // the 'original' Decl when importing code. 385 assert(&decl->getASTContext() != origin.ctx && 386 "Trying to set decl origin to its own ASTContext?"); 387 assert(decl != origin.decl && "Trying to set decl origin to itself?"); 388 m_origins[decl] = origin; 389 } 390 391 /// Removes any tracked DeclOrigin for the given decl. 392 void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); } 393 394 /// Remove all DeclOrigin entries that point to the given ASTContext. 395 /// Useful when an ASTContext is about to be deleted and all the dangling 396 /// pointers to it need to be removed. 397 void removeOriginsWithContext(clang::ASTContext *ctx) { 398 for (OriginMap::iterator iter = m_origins.begin(); 399 iter != m_origins.end();) { 400 if (iter->second.ctx == ctx) 401 m_origins.erase(iter++); 402 else 403 ++iter; 404 } 405 } 406 407 /// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin 408 /// instance if there no known DeclOrigin for the given Decl. 409 DeclOrigin getOrigin(const clang::Decl *decl) const { 410 auto iter = m_origins.find(decl); 411 if (iter == m_origins.end()) 412 return DeclOrigin(); 413 return iter->second; 414 } 415 416 /// Returns true there is a known DeclOrigin for the given Decl. 417 bool hasOrigin(const clang::Decl *decl) const { 418 return getOrigin(decl).Valid(); 419 } 420 421 private: 422 /// Maps declarations to the ASTContext/Decl from which they were imported 423 /// from. If a declaration is from an ASTContext which has been deleted 424 /// since the declaration was imported or the declaration wasn't created by 425 /// the ASTImporter, then it doesn't have a DeclOrigin and will not be 426 /// tracked here. 427 OriginMap m_origins; 428 }; 429 430 typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP; 431 typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP> 432 ContextMetadataMap; 433 434 ContextMetadataMap m_metadata_map; 435 436 ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) { 437 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 438 439 if (context_md_iter == m_metadata_map.end()) { 440 ASTContextMetadataSP context_md = 441 ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); 442 m_metadata_map[dst_ctx] = context_md; 443 return context_md; 444 } 445 return context_md_iter->second; 446 } 447 448 ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) { 449 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 450 451 if (context_md_iter != m_metadata_map.end()) 452 return context_md_iter->second; 453 return ASTContextMetadataSP(); 454 } 455 456 ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx, 457 clang::ASTContext *src_ctx) { 458 ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx); 459 460 DelegateMap &delegates = context_md->m_delegates; 461 DelegateMap::iterator delegate_iter = delegates.find(src_ctx); 462 463 if (delegate_iter == delegates.end()) { 464 ImporterDelegateSP delegate = 465 ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx)); 466 delegates[src_ctx] = delegate; 467 return delegate; 468 } 469 return delegate_iter->second; 470 } 471 472 DeclOrigin GetDeclOrigin(const clang::Decl *decl); 473 474 clang::FileManager m_file_manager; 475 typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> 476 RecordDeclToLayoutMap; 477 478 RecordDeclToLayoutMap m_record_decl_to_layout_map; 479 }; 480 481 template <class D> class TaggedASTDecl { 482 public: 483 TaggedASTDecl() : decl(nullptr) {} 484 TaggedASTDecl(D *_decl) : decl(_decl) {} 485 bool IsValid() const { return (decl != nullptr); } 486 bool IsInvalid() const { return !IsValid(); } 487 D *operator->() const { return decl; } 488 D *decl; 489 }; 490 491 template <class D2, template <class D> class TD, class D1> 492 TD<D2> DynCast(TD<D1> source) { 493 return TD<D2>(llvm::dyn_cast<D2>(source.decl)); 494 } 495 496 template <class D = clang::Decl> class DeclFromParser; 497 template <class D = clang::Decl> class DeclFromUser; 498 499 template <class D> class DeclFromParser : public TaggedASTDecl<D> { 500 public: 501 DeclFromParser() : TaggedASTDecl<D>() {} 502 DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {} 503 504 DeclFromUser<D> GetOrigin(ClangASTImporter &importer); 505 }; 506 507 template <class D> class DeclFromUser : public TaggedASTDecl<D> { 508 public: 509 DeclFromUser() : TaggedASTDecl<D>() {} 510 DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {} 511 512 DeclFromParser<D> Import(clang::ASTContext *dest_ctx, 513 ClangASTImporter &importer); 514 }; 515 516 template <class D> 517 DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTImporter &importer) { 518 ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(this->decl); 519 if (!origin.Valid()) 520 return DeclFromUser<D>(); 521 return DeclFromUser<D>(llvm::dyn_cast<D>(origin.decl)); 522 } 523 524 template <class D> 525 DeclFromParser<D> DeclFromUser<D>::Import(clang::ASTContext *dest_ctx, 526 ClangASTImporter &importer) { 527 DeclFromParser<> parser_generic_decl(importer.CopyDecl(dest_ctx, this->decl)); 528 if (parser_generic_decl.IsInvalid()) 529 return DeclFromParser<D>(); 530 return DeclFromParser<D>(llvm::dyn_cast<D>(parser_generic_decl.decl)); 531 } 532 533 } // namespace lldb_private 534 535 #endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H 536