ClangASTImporter.h revision 353358
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 ClangASTMetrics { 34public: 35 static void DumpCounters(Log *log); 36 static void ClearLocalCounters() { local_counters = {0, 0, 0, 0, 0, 0}; } 37 38 static void RegisterVisibleQuery() { 39 ++global_counters.m_visible_query_count; 40 ++local_counters.m_visible_query_count; 41 } 42 43 static void RegisterLexicalQuery() { 44 ++global_counters.m_lexical_query_count; 45 ++local_counters.m_lexical_query_count; 46 } 47 48 static void RegisterLLDBImport() { 49 ++global_counters.m_lldb_import_count; 50 ++local_counters.m_lldb_import_count; 51 } 52 53 static void RegisterClangImport() { 54 ++global_counters.m_clang_import_count; 55 ++local_counters.m_clang_import_count; 56 } 57 58 static void RegisterDeclCompletion() { 59 ++global_counters.m_decls_completed_count; 60 ++local_counters.m_decls_completed_count; 61 } 62 63 static void RegisterRecordLayout() { 64 ++global_counters.m_record_layout_count; 65 ++local_counters.m_record_layout_count; 66 } 67 68private: 69 struct Counters { 70 uint64_t m_visible_query_count; 71 uint64_t m_lexical_query_count; 72 uint64_t m_lldb_import_count; 73 uint64_t m_clang_import_count; 74 uint64_t m_decls_completed_count; 75 uint64_t m_record_layout_count; 76 }; 77 78 static Counters global_counters; 79 static Counters local_counters; 80 81 static void DumpCounters(Log *log, Counters &counters); 82}; 83 84class ClangASTImporter { 85public: 86 struct LayoutInfo { 87 LayoutInfo() 88 : bit_size(0), alignment(0), field_offsets(), base_offsets(), 89 vbase_offsets() {} 90 uint64_t bit_size; 91 uint64_t alignment; 92 llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets; 93 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> base_offsets; 94 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 95 vbase_offsets; 96 }; 97 98 ClangASTImporter() 99 : m_file_manager(clang::FileSystemOptions(), 100 FileSystem::Instance().GetVirtualFileSystem()) {} 101 102 clang::QualType CopyType(clang::ASTContext *dst_ctx, 103 clang::ASTContext *src_ctx, clang::QualType type); 104 105 lldb::opaque_compiler_type_t CopyType(clang::ASTContext *dst_ctx, 106 clang::ASTContext *src_ctx, 107 lldb::opaque_compiler_type_t type); 108 109 CompilerType CopyType(ClangASTContext &dst, const CompilerType &src_type); 110 111 clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx, 112 clang::Decl *decl); 113 114 lldb::opaque_compiler_type_t DeportType(clang::ASTContext *dst_ctx, 115 clang::ASTContext *src_ctx, 116 lldb::opaque_compiler_type_t type); 117 118 clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, 119 clang::ASTContext *src_ctx, clang::Decl *decl); 120 121 void InsertRecordDecl(clang::RecordDecl *decl, const LayoutInfo &layout); 122 123 bool LayoutRecordType( 124 const clang::RecordDecl *record_decl, uint64_t &bit_size, 125 uint64_t &alignment, 126 llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, 127 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 128 &base_offsets, 129 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> 130 &vbase_offsets); 131 132 bool CanImport(const CompilerType &type); 133 134 bool Import(const CompilerType &type); 135 136 bool CompleteType(const CompilerType &compiler_type); 137 138 void CompleteDecl(clang::Decl *decl); 139 140 bool CompleteTagDecl(clang::TagDecl *decl); 141 142 bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin); 143 144 bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl); 145 146 bool CompleteAndFetchChildren(clang::QualType type); 147 148 bool RequireCompleteType(clang::QualType type); 149 150 bool ResolveDeclOrigin(const clang::Decl *decl, clang::Decl **original_decl, 151 clang::ASTContext **original_ctx) { 152 DeclOrigin origin = GetDeclOrigin(decl); 153 154 if (original_decl) 155 *original_decl = origin.decl; 156 157 if (original_ctx) 158 *original_ctx = origin.ctx; 159 160 return origin.Valid(); 161 } 162 163 void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl); 164 165 ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl); 166 167 // 168 // Namespace maps 169 // 170 171 typedef std::vector<std::pair<lldb::ModuleSP, CompilerDeclContext>> 172 NamespaceMap; 173 typedef std::shared_ptr<NamespaceMap> NamespaceMapSP; 174 175 void RegisterNamespaceMap(const clang::NamespaceDecl *decl, 176 NamespaceMapSP &namespace_map); 177 178 NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl); 179 180 void BuildNamespaceMap(const clang::NamespaceDecl *decl); 181 182 // 183 // Completers for maps 184 // 185 186 class MapCompleter { 187 public: 188 virtual ~MapCompleter(); 189 190 virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map, 191 ConstString name, 192 NamespaceMapSP &parent_map) const = 0; 193 }; 194 195 void InstallMapCompleter(clang::ASTContext *dst_ctx, 196 MapCompleter &completer) { 197 ASTContextMetadataSP context_md; 198 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 199 200 if (context_md_iter == m_metadata_map.end()) { 201 context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); 202 m_metadata_map[dst_ctx] = context_md; 203 } else { 204 context_md = context_md_iter->second; 205 } 206 207 context_md->m_map_completer = &completer; 208 } 209 210 void ForgetDestination(clang::ASTContext *dst_ctx); 211 void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx); 212 213private: 214 struct DeclOrigin { 215 DeclOrigin() : ctx(nullptr), decl(nullptr) {} 216 217 DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl) 218 : ctx(_ctx), decl(_decl) {} 219 220 DeclOrigin(const DeclOrigin &rhs) { 221 ctx = rhs.ctx; 222 decl = rhs.decl; 223 } 224 225 void operator=(const DeclOrigin &rhs) { 226 ctx = rhs.ctx; 227 decl = rhs.decl; 228 } 229 230 bool Valid() { return (ctx != nullptr || decl != nullptr); } 231 232 clang::ASTContext *ctx; 233 clang::Decl *decl; 234 }; 235 236 typedef std::map<const clang::Decl *, DeclOrigin> OriginMap; 237 238 /// ASTImporter that intercepts and records the import process of the 239 /// underlying ASTImporter. 240 /// 241 /// This class updates the map from declarations to their original 242 /// declarations and can record and complete declarations that have been 243 /// imported in a certain interval. 244 /// 245 /// When intercepting a declaration import, the ASTImporterDelegate uses the 246 /// CxxModuleHandler to replace any missing or malformed declarations with 247 /// their counterpart from a C++ module. 248 class ASTImporterDelegate : public clang::ASTImporter { 249 public: 250 ASTImporterDelegate(ClangASTImporter &master, clang::ASTContext *target_ctx, 251 clang::ASTContext *source_ctx) 252 : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx, 253 master.m_file_manager, true /*minimal*/), 254 m_decls_to_deport(nullptr), m_decls_already_deported(nullptr), 255 m_master(master), m_source_ctx(source_ctx) {} 256 257 /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate 258 /// and deattaches it at the end of the scope. Supports being used multiple 259 /// times on the same ASTImporterDelegate instance in nested scopes. 260 class CxxModuleScope { 261 /// The handler we attach to the ASTImporterDelegate. 262 CxxModuleHandler m_handler; 263 /// The ASTImporterDelegate we are supposed to attach the handler to. 264 ASTImporterDelegate &m_delegate; 265 /// True iff we attached the handler to the ASTImporterDelegate. 266 bool m_valid = false; 267 268 public: 269 CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx) 270 : m_delegate(delegate) { 271 // If the delegate doesn't have a CxxModuleHandler yet, create one 272 // and attach it. 273 if (!delegate.m_std_handler) { 274 m_handler = CxxModuleHandler(delegate, dst_ctx); 275 m_valid = true; 276 delegate.m_std_handler = &m_handler; 277 } 278 } 279 ~CxxModuleScope() { 280 if (m_valid) { 281 // Make sure no one messed with the handler we placed. 282 assert(m_delegate.m_std_handler == &m_handler); 283 m_delegate.m_std_handler = nullptr; 284 } 285 } 286 }; 287 288 protected: 289 llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override; 290 291 public: 292 // A call to "InitDeportWorkQueues" puts the delegate into deport mode. 293 // In deport mode, every copied Decl that could require completion is 294 // recorded and placed into the decls_to_deport set. 295 // 296 // A call to "ExecuteDeportWorkQueues" completes all the Decls that 297 // are in decls_to_deport, adding any Decls it sees along the way that it 298 // hasn't already deported. It proceeds until decls_to_deport is empty. 299 // 300 // These calls must be paired. Leaving a delegate in deport mode or trying 301 // to start deport delegate with a new pair of queues will result in an 302 // assertion failure. 303 304 void 305 InitDeportWorkQueues(std::set<clang::NamedDecl *> *decls_to_deport, 306 std::set<clang::NamedDecl *> *decls_already_deported); 307 void ExecuteDeportWorkQueues(); 308 309 void ImportDefinitionTo(clang::Decl *to, clang::Decl *from); 310 311 void Imported(clang::Decl *from, clang::Decl *to) override; 312 313 clang::Decl *GetOriginalDecl(clang::Decl *To) override; 314 315 /// Decls we should ignore when mapping decls back to their original 316 /// ASTContext. Used by the CxxModuleHandler to mark declarations that 317 /// were created from the 'std' C++ module to prevent that the Importer 318 /// tries to sync them with the broken equivalent in the debug info AST. 319 std::set<clang::Decl *> m_decls_to_ignore; 320 std::set<clang::NamedDecl *> *m_decls_to_deport; 321 std::set<clang::NamedDecl *> *m_decls_already_deported; 322 ClangASTImporter &m_master; 323 clang::ASTContext *m_source_ctx; 324 CxxModuleHandler *m_std_handler = nullptr; 325 }; 326 327 typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP; 328 typedef std::map<clang::ASTContext *, ImporterDelegateSP> DelegateMap; 329 typedef std::map<const clang::NamespaceDecl *, NamespaceMapSP> 330 NamespaceMetaMap; 331 332 struct ASTContextMetadata { 333 ASTContextMetadata(clang::ASTContext *dst_ctx) 334 : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(), 335 m_map_completer(nullptr) {} 336 337 clang::ASTContext *m_dst_ctx; 338 DelegateMap m_delegates; 339 OriginMap m_origins; 340 341 NamespaceMetaMap m_namespace_maps; 342 MapCompleter *m_map_completer; 343 }; 344 345 typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP; 346 typedef std::map<const clang::ASTContext *, ASTContextMetadataSP> 347 ContextMetadataMap; 348 349 ContextMetadataMap m_metadata_map; 350 351 ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) { 352 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 353 354 if (context_md_iter == m_metadata_map.end()) { 355 ASTContextMetadataSP context_md = 356 ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); 357 m_metadata_map[dst_ctx] = context_md; 358 return context_md; 359 } else { 360 return context_md_iter->second; 361 } 362 } 363 364 ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) { 365 ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); 366 367 if (context_md_iter != m_metadata_map.end()) 368 return context_md_iter->second; 369 else 370 return ASTContextMetadataSP(); 371 } 372 373 ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx, 374 clang::ASTContext *src_ctx) { 375 ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx); 376 377 DelegateMap &delegates = context_md->m_delegates; 378 DelegateMap::iterator delegate_iter = delegates.find(src_ctx); 379 380 if (delegate_iter == delegates.end()) { 381 ImporterDelegateSP delegate = 382 ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx)); 383 delegates[src_ctx] = delegate; 384 return delegate; 385 } else { 386 return delegate_iter->second; 387 } 388 } 389 390 DeclOrigin GetDeclOrigin(const clang::Decl *decl); 391 392 clang::FileManager m_file_manager; 393 typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> 394 RecordDeclToLayoutMap; 395 396 RecordDeclToLayoutMap m_record_decl_to_layout_map; 397}; 398 399} // namespace lldb_private 400 401#endif // liblldb_ClangASTImporter_h_ 402