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