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/lldb-types.h" 27 28 #include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" 29 30 #include "llvm/ADT/DenseMap.h" 31 32 namespace lldb_private { 33 34 class ClangASTMetadata; 35 class TypeSystemClang; 36 37 class ClangASTImporter { 38 public: 39 struct LayoutInfo { 40 LayoutInfo() = default; 41 typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 42 OffsetMap; 43 44 uint64_t bit_size = 0; 45 uint64_t alignment = 0; 46 llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets; 47 OffsetMap base_offsets; 48 OffsetMap vbase_offsets; 49 }; 50 ClangASTImporter()51 ClangASTImporter() 52 : m_file_manager(clang::FileSystemOptions(), 53 FileSystem::Instance().GetVirtualFileSystem()) {} 54 55 CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type); 56 57 clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); 58 59 CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type); 60 61 clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); 62 63 /// Sets the layout for the given RecordDecl. The layout will later be 64 /// used by Clang's during code generation. Not calling this function for 65 /// a RecordDecl will cause that Clang's codegen tries to layout the 66 /// record by itself. 67 /// 68 /// \param decl The RecordDecl to set the layout for. 69 /// \param layout The layout for the record. 70 void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout); 71 72 bool LayoutRecordType( 73 const clang::RecordDecl *record_decl, uint64_t &bit_size, 74 uint64_t &alignment, 75 llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, 76 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 77 &base_offsets, 78 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 79 &vbase_offsets); 80 81 bool CanImport(const CompilerType &type); 82 83 bool Import(const CompilerType &type); 84 85 bool CompleteType(const CompilerType &compiler_type); 86 87 bool CompleteTagDecl(clang::TagDecl *decl); 88 89 bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin); 90 91 bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl); 92 93 bool CompleteAndFetchChildren(clang::QualType type); 94 95 bool RequireCompleteType(clang::QualType type); 96 97 void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl); 98 99 ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl); 100 101 // 102 // Namespace maps 103 // 104 105 typedef std::pair<lldb::ModuleSP, CompilerDeclContext> NamespaceMapItem; 106 typedef std::vector<NamespaceMapItem> NamespaceMap; 107 typedef std::shared_ptr<NamespaceMap> NamespaceMapSP; 108 109 void RegisterNamespaceMap(const clang::NamespaceDecl *decl, 110 NamespaceMapSP &namespace_map); 111 112 NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl); 113 114 void BuildNamespaceMap(const clang::NamespaceDecl *decl); 115 116 // 117 // Completers for maps 118 // 119 120 class MapCompleter { 121 public: 122 virtual ~MapCompleter(); 123 124 virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map, 125 ConstString name, 126 NamespaceMapSP &parent_map) const = 0; 127 }; 128 InstallMapCompleter(clang::ASTContext * dst_ctx,MapCompleter & completer)129 void InstallMapCompleter(clang::ASTContext *dst_ctx, 130 MapCompleter &completer) { 131 ASTContextMetadataSP context_md; 132 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 133 134 if (context_md_iter == m_metadata_map.end()) { 135 context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); 136 m_metadata_map[dst_ctx] = context_md; 137 } else { 138 context_md = context_md_iter->second; 139 } 140 141 context_md->m_map_completer = &completer; 142 } 143 144 void ForgetDestination(clang::ASTContext *dst_ctx); 145 void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx); 146 147 struct DeclOrigin { DeclOriginDeclOrigin148 DeclOrigin() : ctx(nullptr), decl(nullptr) {} 149 DeclOriginDeclOrigin150 DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl) 151 : ctx(_ctx), decl(_decl) {} 152 DeclOriginDeclOrigin153 DeclOrigin(const DeclOrigin &rhs) { 154 ctx = rhs.ctx; 155 decl = rhs.decl; 156 } 157 158 void operator=(const DeclOrigin &rhs) { 159 ctx = rhs.ctx; 160 decl = rhs.decl; 161 } 162 ValidDeclOrigin163 bool Valid() const { return (ctx != nullptr || decl != nullptr); } 164 165 clang::ASTContext *ctx; 166 clang::Decl *decl; 167 }; 168 169 /// Listener interface used by the ASTImporterDelegate to inform other code 170 /// about decls that have been imported the first time. 171 struct NewDeclListener { 172 virtual ~NewDeclListener() = default; 173 /// A decl has been imported for the first time. 174 virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0; 175 }; 176 177 /// ASTImporter that intercepts and records the import process of the 178 /// underlying ASTImporter. 179 /// 180 /// This class updates the map from declarations to their original 181 /// declarations and can record declarations that have been imported in a 182 /// certain interval. 183 /// 184 /// When intercepting a declaration import, the ASTImporterDelegate uses the 185 /// CxxModuleHandler to replace any missing or malformed declarations with 186 /// their counterpart from a C++ module. 187 struct ASTImporterDelegate : public clang::ASTImporter { ASTImporterDelegateASTImporterDelegate188 ASTImporterDelegate(ClangASTImporter &master, clang::ASTContext *target_ctx, 189 clang::ASTContext *source_ctx) 190 : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx, 191 master.m_file_manager, true /*minimal*/), 192 m_master(master), m_source_ctx(source_ctx) { 193 setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal); 194 } 195 196 /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate 197 /// and deattaches it at the end of the scope. Supports being used multiple 198 /// times on the same ASTImporterDelegate instance in nested scopes. 199 class CxxModuleScope { 200 /// The handler we attach to the ASTImporterDelegate. 201 CxxModuleHandler m_handler; 202 /// The ASTImporterDelegate we are supposed to attach the handler to. 203 ASTImporterDelegate &m_delegate; 204 /// True iff we attached the handler to the ASTImporterDelegate. 205 bool m_valid = false; 206 207 public: CxxModuleScopeASTImporterDelegate208 CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx) 209 : m_delegate(delegate) { 210 // If the delegate doesn't have a CxxModuleHandler yet, create one 211 // and attach it. 212 if (!delegate.m_std_handler) { 213 m_handler = CxxModuleHandler(delegate, dst_ctx); 214 m_valid = true; 215 delegate.m_std_handler = &m_handler; 216 } 217 } ~CxxModuleScopeASTImporterDelegate218 ~CxxModuleScope() { 219 if (m_valid) { 220 // Make sure no one messed with the handler we placed. 221 assert(m_delegate.m_std_handler == &m_handler); 222 m_delegate.m_std_handler = nullptr; 223 } 224 } 225 }; 226 227 void ImportDefinitionTo(clang::Decl *to, clang::Decl *from); 228 229 void Imported(clang::Decl *from, clang::Decl *to) override; 230 231 clang::Decl *GetOriginalDecl(clang::Decl *To) override; 232 SetImportListenerASTImporterDelegate233 void SetImportListener(NewDeclListener *listener) { 234 assert(m_new_decl_listener == nullptr && "Already attached a listener?"); 235 m_new_decl_listener = listener; 236 } RemoveImportListenerASTImporterDelegate237 void RemoveImportListener() { m_new_decl_listener = nullptr; } 238 239 protected: 240 llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override; 241 242 private: 243 /// Decls we should ignore when mapping decls back to their original 244 /// ASTContext. Used by the CxxModuleHandler to mark declarations that 245 /// were created from the 'std' C++ module to prevent that the Importer 246 /// tries to sync them with the broken equivalent in the debug info AST. 247 llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore; 248 ClangASTImporter &m_master; 249 clang::ASTContext *m_source_ctx; 250 CxxModuleHandler *m_std_handler = nullptr; 251 /// The currently attached listener. 252 NewDeclListener *m_new_decl_listener = nullptr; 253 }; 254 255 typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP; 256 typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap; 257 typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP> 258 NamespaceMetaMap; 259 260 class ASTContextMetadata { 261 typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; 262 263 public: ASTContextMetadata(clang::ASTContext * dst_ctx)264 ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {} 265 266 clang::ASTContext *m_dst_ctx; 267 DelegateMap m_delegates; 268 269 NamespaceMetaMap m_namespace_maps; 270 MapCompleter *m_map_completer = nullptr; 271 272 /// Sets the DeclOrigin for the given Decl and overwrites any existing 273 /// DeclOrigin. setOrigin(const clang::Decl * decl,DeclOrigin origin)274 void setOrigin(const clang::Decl *decl, DeclOrigin origin) { 275 m_origins[decl] = origin; 276 } 277 278 /// Removes any tracked DeclOrigin for the given decl. removeOrigin(const clang::Decl * decl)279 void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); } 280 281 /// Remove all DeclOrigin entries that point to the given ASTContext. 282 /// Useful when an ASTContext is about to be deleted and all the dangling 283 /// pointers to it need to be removed. removeOriginsWithContext(clang::ASTContext * ctx)284 void removeOriginsWithContext(clang::ASTContext *ctx) { 285 for (OriginMap::iterator iter = m_origins.begin(); 286 iter != m_origins.end();) { 287 if (iter->second.ctx == ctx) 288 m_origins.erase(iter++); 289 else 290 ++iter; 291 } 292 } 293 294 /// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin 295 /// instance if there no known DeclOrigin for the given Decl. getOrigin(const clang::Decl * decl)296 DeclOrigin getOrigin(const clang::Decl *decl) const { 297 auto iter = m_origins.find(decl); 298 if (iter == m_origins.end()) 299 return DeclOrigin(); 300 return iter->second; 301 } 302 303 /// Returns true there is a known DeclOrigin for the given Decl. hasOrigin(const clang::Decl * decl)304 bool hasOrigin(const clang::Decl *decl) const { 305 return getOrigin(decl).Valid(); 306 } 307 308 private: 309 /// Maps declarations to the ASTContext/Decl from which they were imported 310 /// from. If a declaration is from an ASTContext which has been deleted 311 /// since the declaration was imported or the declaration wasn't created by 312 /// the ASTImporter, then it doesn't have a DeclOrigin and will not be 313 /// tracked here. 314 OriginMap m_origins; 315 }; 316 317 typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP; 318 typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP> 319 ContextMetadataMap; 320 321 ContextMetadataMap m_metadata_map; 322 GetContextMetadata(clang::ASTContext * dst_ctx)323 ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) { 324 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 325 326 if (context_md_iter == m_metadata_map.end()) { 327 ASTContextMetadataSP context_md = 328 ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); 329 m_metadata_map[dst_ctx] = context_md; 330 return context_md; 331 } 332 return context_md_iter->second; 333 } 334 MaybeGetContextMetadata(clang::ASTContext * dst_ctx)335 ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) { 336 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 337 338 if (context_md_iter != m_metadata_map.end()) 339 return context_md_iter->second; 340 return ASTContextMetadataSP(); 341 } 342 GetDelegate(clang::ASTContext * dst_ctx,clang::ASTContext * src_ctx)343 ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx, 344 clang::ASTContext *src_ctx) { 345 ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx); 346 347 DelegateMap &delegates = context_md->m_delegates; 348 DelegateMap::iterator delegate_iter = delegates.find(src_ctx); 349 350 if (delegate_iter == delegates.end()) { 351 ImporterDelegateSP delegate = 352 ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx)); 353 delegates[src_ctx] = delegate; 354 return delegate; 355 } 356 return delegate_iter->second; 357 } 358 359 DeclOrigin GetDeclOrigin(const clang::Decl *decl); 360 361 clang::FileManager m_file_manager; 362 typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> 363 RecordDeclToLayoutMap; 364 365 RecordDeclToLayoutMap m_record_decl_to_layout_map; 366 }; 367 368 } // namespace lldb_private 369 370 #endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H 371