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