//===-- ClangASTImporter.cpp ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Core/Module.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "llvm/Support/raw_ostream.h" #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" #include "Plugins/ExpressionParser/Clang/ClangASTSource.h" #include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include #include #include using namespace lldb_private; using namespace clang; CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast, const CompilerType &src_type) { clang::ASTContext &dst_clang_ast = dst_ast.getASTContext(); auto src_ast = src_type.GetTypeSystem().dyn_cast_or_null(); if (!src_ast) return CompilerType(); clang::ASTContext &src_clang_ast = src_ast->getASTContext(); clang::QualType src_qual_type = ClangUtil::GetQualType(src_type); ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast)); if (!delegate_sp) return CompilerType(); ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast); llvm::Expected ret_or_error = delegate_sp->Import(src_qual_type); if (!ret_or_error) { Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG_ERROR(log, ret_or_error.takeError(), "Couldn't import type: {0}"); return CompilerType(); } lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr(); if (dst_clang_type) return CompilerType(dst_ast.weak_from_this(), dst_clang_type); return CompilerType(); } clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast, clang::Decl *decl) { ImporterDelegateSP delegate_sp; clang::ASTContext *src_ast = &decl->getASTContext(); delegate_sp = GetDelegate(dst_ast, src_ast); ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast); if (!delegate_sp) return nullptr; llvm::Expected result = delegate_sp->Import(decl); if (!result) { Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}"); if (log) { lldb::user_id_t user_id = LLDB_INVALID_UID; ClangASTMetadata *metadata = GetDeclMetadata(decl); if (metadata) user_id = metadata->GetUserID(); if (NamedDecl *named_decl = dyn_cast(decl)) LLDB_LOG(log, " [ClangASTImporter] WARNING: Failed to import a {0} " "'{1}', metadata {2}", decl->getDeclKindName(), named_decl->getNameAsString(), user_id); else LLDB_LOG(log, " [ClangASTImporter] WARNING: Failed to import a {0}, " "metadata {1}", decl->getDeclKindName(), user_id); } return nullptr; } return *result; } class DeclContextOverride { private: struct Backup { clang::DeclContext *decl_context; clang::DeclContext *lexical_decl_context; }; llvm::DenseMap m_backups; void OverrideOne(clang::Decl *decl) { if (m_backups.contains(decl)) { return; } m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()}; decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl()); decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl()); } bool ChainPassesThrough( clang::Decl *decl, clang::DeclContext *base, clang::DeclContext *(clang::Decl::*contextFromDecl)(), clang::DeclContext *(clang::DeclContext::*contextFromContext)()) { for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx; decl_ctx = (decl_ctx->*contextFromContext)()) { if (decl_ctx == base) { return true; } } return false; } clang::Decl *GetEscapedChild(clang::Decl *decl, clang::DeclContext *base = nullptr) { if (base) { // decl's DeclContext chains must pass through base. if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext, &clang::DeclContext::getParent) || !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext, &clang::DeclContext::getLexicalParent)) { return decl; } } else { base = clang::dyn_cast(decl); if (!base) { return nullptr; } } if (clang::DeclContext *context = clang::dyn_cast(decl)) { for (clang::Decl *decl : context->decls()) { if (clang::Decl *escaped_child = GetEscapedChild(decl)) { return escaped_child; } } } return nullptr; } void Override(clang::Decl *decl) { if (clang::Decl *escaped_child = GetEscapedChild(decl)) { Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG(log, " [ClangASTImporter] DeclContextOverride couldn't " "override ({0}Decl*){1} - its child ({2}Decl*){3} escapes", decl->getDeclKindName(), decl, escaped_child->getDeclKindName(), escaped_child); lldbassert(0 && "Couldn't override!"); } OverrideOne(decl); } public: DeclContextOverride() = default; void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) { for (DeclContext *decl_context = decl->getLexicalDeclContext(); decl_context; decl_context = decl_context->getLexicalParent()) { DeclContext *redecl_context = decl_context->getRedeclContext(); if (llvm::isa(redecl_context) && llvm::isa(redecl_context->getLexicalParent())) { for (clang::Decl *child_decl : decl_context->decls()) { Override(child_decl); } } } } ~DeclContextOverride() { for (const std::pair &backup : m_backups) { backup.first->setDeclContext(backup.second.decl_context); backup.first->setLexicalDeclContext(backup.second.lexical_decl_context); } } }; namespace { /// Completes all imported TagDecls at the end of the scope. /// /// While in a CompleteTagDeclsScope, every decl that could be completed will /// be completed at the end of the scope (including all Decls that are /// imported while completing the original Decls). class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { ClangASTImporter::ImporterDelegateSP m_delegate; /// List of declarations in the target context that need to be completed. /// Every declaration should only be completed once and therefore should only /// be once in this list. llvm::SetVector m_decls_to_complete; /// Set of declarations that already were successfully completed (not just /// added to m_decls_to_complete). llvm::SmallPtrSet m_decls_already_completed; clang::ASTContext *m_dst_ctx; clang::ASTContext *m_src_ctx; ClangASTImporter &importer; public: /// Constructs a CompleteTagDeclsScope. /// \param importer The ClangASTImporter that we should observe. /// \param dst_ctx The ASTContext to which Decls are imported. /// \param src_ctx The ASTContext from which Decls are imported. explicit CompleteTagDeclsScope(ClangASTImporter &importer, clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx) : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx), m_src_ctx(src_ctx), importer(importer) { m_delegate->SetImportListener(this); } ~CompleteTagDeclsScope() override { ClangASTImporter::ASTContextMetadataSP to_context_md = importer.GetContextMetadata(m_dst_ctx); // Complete all decls we collected until now. while (!m_decls_to_complete.empty()) { NamedDecl *decl = m_decls_to_complete.pop_back_val(); m_decls_already_completed.insert(decl); // The decl that should be completed has to be imported into the target // context from some other context. assert(to_context_md->hasOrigin(decl)); // We should only complete decls coming from the source context. assert(to_context_md->getOrigin(decl).ctx == m_src_ctx); Decl *original_decl = to_context_md->getOrigin(decl).decl; // Complete the decl now. TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); if (auto *tag_decl = dyn_cast(decl)) { if (auto *original_tag_decl = dyn_cast(original_decl)) { if (original_tag_decl->isCompleteDefinition()) { m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl); tag_decl->setCompleteDefinition(true); } } tag_decl->setHasExternalLexicalStorage(false); tag_decl->setHasExternalVisibleStorage(false); } else if (auto *container_decl = dyn_cast(decl)) { container_decl->setHasExternalLexicalStorage(false); container_decl->setHasExternalVisibleStorage(false); } to_context_md->removeOrigin(decl); } // Stop listening to imported decls. We do this after clearing the // Decls we needed to import to catch all Decls they might have pulled in. m_delegate->RemoveImportListener(); } void NewDeclImported(clang::Decl *from, clang::Decl *to) override { // Filter out decls that we can't complete later. if (!isa(to) && !isa(to)) return; RecordDecl *from_record_decl = dyn_cast(from); // We don't need to complete injected class name decls. if (from_record_decl && from_record_decl->isInjectedClassName()) return; NamedDecl *to_named_decl = dyn_cast(to); // Check if we already completed this type. if (m_decls_already_completed.contains(to_named_decl)) return; // Queue this type to be completed. m_decls_to_complete.insert(to_named_decl); } }; } // namespace CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst, const CompilerType &src_type) { Log *log = GetLog(LLDBLog::Expressions); auto src_ctxt = src_type.GetTypeSystem().dyn_cast_or_null(); if (!src_ctxt) return {}; LLDB_LOG(log, " [ClangASTImporter] DeportType called on ({0}Type*){1:x} " "from (ASTContext*){2:x} to (ASTContext*){3:x}", src_type.GetTypeName(), src_type.GetOpaqueQualType(), &src_ctxt->getASTContext(), &dst.getASTContext()); DeclContextOverride decl_context_override; if (auto *t = ClangUtil::GetQualType(src_type)->getAs()) decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl()); CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(), &src_ctxt->getASTContext()); return CopyType(dst, src_type); } clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl) { Log *log = GetLog(LLDBLog::Expressions); clang::ASTContext *src_ctx = &decl->getASTContext(); LLDB_LOG(log, " [ClangASTImporter] DeportDecl called on ({0}Decl*){1:x} from " "(ASTContext*){2:x} to (ASTContext*){3:x}", decl->getDeclKindName(), decl, src_ctx, dst_ctx); DeclContextOverride decl_context_override; decl_context_override.OverrideAllDeclsFromContainingFunction(decl); clang::Decl *result; { CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx); result = CopyDecl(dst_ctx, decl); } if (!result) return nullptr; LLDB_LOG(log, " [ClangASTImporter] DeportDecl deported ({0}Decl*){1:x} to " "({2}Decl*){3:x}", decl->getDeclKindName(), decl, result->getDeclKindName(), result); return result; } bool ClangASTImporter::CanImport(const CompilerType &type) { if (!ClangUtil::IsClangType(type)) return false; clang::QualType qual_type( ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); const clang::Type::TypeClass type_class = qual_type->getTypeClass(); switch (type_class) { case clang::Type::Record: { const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); if (cxx_record_decl) { if (GetDeclOrigin(cxx_record_decl).Valid()) return true; } } break; case clang::Type::Enum: { clang::EnumDecl *enum_decl = llvm::cast(qual_type)->getDecl(); if (enum_decl) { if (GetDeclOrigin(enum_decl).Valid()) return true; } } break; case clang::Type::ObjCObject: case clang::Type::ObjCInterface: { const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast(qual_type); if (objc_class_type) { clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); // We currently can't complete objective C types through the newly added // ASTContext because it only supports TagDecl objects right now... if (class_interface_decl) { if (GetDeclOrigin(class_interface_decl).Valid()) return true; } } } break; case clang::Type::Typedef: return CanImport(CompilerType(type.GetTypeSystem(), llvm::cast(qual_type) ->getDecl() ->getUnderlyingType() .getAsOpaquePtr())); case clang::Type::Auto: return CanImport(CompilerType(type.GetTypeSystem(), llvm::cast(qual_type) ->getDeducedType() .getAsOpaquePtr())); case clang::Type::Elaborated: return CanImport(CompilerType(type.GetTypeSystem(), llvm::cast(qual_type) ->getNamedType() .getAsOpaquePtr())); case clang::Type::Paren: return CanImport(CompilerType( type.GetTypeSystem(), llvm::cast(qual_type)->desugar().getAsOpaquePtr())); default: break; } return false; } bool ClangASTImporter::Import(const CompilerType &type) { if (!ClangUtil::IsClangType(type)) return false; clang::QualType qual_type( ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); const clang::Type::TypeClass type_class = qual_type->getTypeClass(); switch (type_class) { case clang::Type::Record: { const clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); if (cxx_record_decl) { if (GetDeclOrigin(cxx_record_decl).Valid()) return CompleteAndFetchChildren(qual_type); } } break; case clang::Type::Enum: { clang::EnumDecl *enum_decl = llvm::cast(qual_type)->getDecl(); if (enum_decl) { if (GetDeclOrigin(enum_decl).Valid()) return CompleteAndFetchChildren(qual_type); } } break; case clang::Type::ObjCObject: case clang::Type::ObjCInterface: { const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast(qual_type); if (objc_class_type) { clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); // We currently can't complete objective C types through the newly added // ASTContext because it only supports TagDecl objects right now... if (class_interface_decl) { if (GetDeclOrigin(class_interface_decl).Valid()) return CompleteAndFetchChildren(qual_type); } } } break; case clang::Type::Typedef: return Import(CompilerType(type.GetTypeSystem(), llvm::cast(qual_type) ->getDecl() ->getUnderlyingType() .getAsOpaquePtr())); case clang::Type::Auto: return Import(CompilerType(type.GetTypeSystem(), llvm::cast(qual_type) ->getDeducedType() .getAsOpaquePtr())); case clang::Type::Elaborated: return Import(CompilerType(type.GetTypeSystem(), llvm::cast(qual_type) ->getNamedType() .getAsOpaquePtr())); case clang::Type::Paren: return Import(CompilerType( type.GetTypeSystem(), llvm::cast(qual_type)->desugar().getAsOpaquePtr())); default: break; } return false; } bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { if (!CanImport(compiler_type)) return false; if (Import(compiler_type)) { TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type); return true; } TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), false); return false; } /// Copy layout information from \ref source_map to the \ref destination_map. /// /// In the process of copying over layout info, we may need to import /// decls from the \ref source_map. This function will use the supplied /// \ref importer to import the necessary decls into \ref dest_ctx. /// /// \param[in,out] dest_ctx Destination ASTContext into which we import /// decls from the \ref source_map. /// \param[out] destination_map A map from decls in \ref dest_ctx to an /// integral offest, which will be copies /// of the decl/offest pairs in \ref source_map /// if successful. /// \param[in] source_map A map from decls to integral offests. These will /// be copied into \ref destination_map. /// \param[in,out] importer Used to import decls into \ref dest_ctx. /// /// \returns On success, will return 'true' and the offsets in \ref /// destination_map /// are usable copies of \ref source_map. template static bool ImportOffsetMap(clang::ASTContext *dest_ctx, llvm::DenseMap &destination_map, llvm::DenseMap &source_map, ClangASTImporter &importer) { // When importing fields into a new record, clang has a hard requirement that // fields be imported in field offset order. Since they are stored in a // DenseMap with a pointer as the key type, this means we cannot simply // iterate over the map, as the order will be non-deterministic. Instead we // have to sort by the offset and then insert in sorted order. typedef llvm::DenseMap MapType; typedef typename MapType::value_type PairType; std::vector sorted_items; sorted_items.reserve(source_map.size()); sorted_items.assign(source_map.begin(), source_map.end()); llvm::sort(sorted_items, llvm::less_second()); for (const auto &item : sorted_items) { DeclFromUser user_decl(const_cast(item.first)); DeclFromParser parser_decl(user_decl.Import(dest_ctx, importer)); if (parser_decl.IsInvalid()) return false; destination_map.insert( std::pair(parser_decl.decl, item.second)); } return true; } /// Given a CXXRecordDecl, will calculate and populate \ref base_offsets /// with the integral offsets of any of its (possibly virtual) base classes. /// /// \param[in] record_layout ASTRecordLayout of \ref record. /// \param[in] record The record that we're calculating the base layouts of. /// \param[out] base_offsets Map of base-class decl to integral offset which /// this function will fill in. /// /// \returns On success, will return 'true' and the offsets in \ref base_offsets /// are usable. template bool ExtractBaseOffsets(const ASTRecordLayout &record_layout, DeclFromUser &record, llvm::DenseMap &base_offsets) { for (CXXRecordDecl::base_class_const_iterator bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()), be = (IsVirtual ? record->vbases_end() : record->bases_end()); bi != be; ++bi) { if (!IsVirtual && bi->isVirtual()) continue; const clang::Type *origin_base_type = bi->getType().getTypePtr(); const clang::RecordType *origin_base_record_type = origin_base_type->getAs(); if (!origin_base_record_type) return false; DeclFromUser origin_base_record( origin_base_record_type->getDecl()); if (origin_base_record.IsInvalid()) return false; DeclFromUser origin_base_cxx_record( DynCast(origin_base_record)); if (origin_base_cxx_record.IsInvalid()) return false; CharUnits base_offset; if (IsVirtual) base_offset = record_layout.getVBaseClassOffset(origin_base_cxx_record.decl); else base_offset = record_layout.getBaseClassOffset(origin_base_cxx_record.decl); base_offsets.insert(std::pair( origin_base_cxx_record.decl, base_offset)); } return true; } bool ClangASTImporter::importRecordLayoutFromOrigin( const RecordDecl *record, uint64_t &size, uint64_t &alignment, llvm::DenseMap &field_offsets, llvm::DenseMap &base_offsets, llvm::DenseMap &vbase_offsets) { Log *log = GetLog(LLDBLog::Expressions); clang::ASTContext &dest_ctx = record->getASTContext(); LLDB_LOG(log, "LayoutRecordType on (ASTContext*){0:x} '{1}' for (RecordDecl*)" "{2:x} [name = '{3}']", &dest_ctx, TypeSystemClang::GetASTContext(&dest_ctx)->getDisplayName(), record, record->getName()); DeclFromParser parser_record(record); DeclFromUser origin_record(parser_record.GetOrigin(*this)); if (origin_record.IsInvalid()) return false; std::remove_reference_t origin_field_offsets; std::remove_reference_t origin_base_offsets; std::remove_reference_t origin_virtual_base_offsets; TypeSystemClang::GetCompleteDecl( &origin_record->getASTContext(), const_cast(origin_record.decl)); clang::RecordDecl *definition = origin_record.decl->getDefinition(); if (!definition || !definition->isCompleteDefinition()) return false; const ASTRecordLayout &record_layout( origin_record->getASTContext().getASTRecordLayout(origin_record.decl)); int field_idx = 0, field_count = record_layout.getFieldCount(); for (RecordDecl::field_iterator fi = origin_record->field_begin(), fe = origin_record->field_end(); fi != fe; ++fi) { if (field_idx >= field_count) return false; // Layout didn't go well. Bail out. uint64_t field_offset = record_layout.getFieldOffset(field_idx); origin_field_offsets.insert( std::pair(*fi, field_offset)); field_idx++; } DeclFromUser origin_cxx_record( DynCast(origin_record)); if (origin_cxx_record.IsValid()) { if (!ExtractBaseOffsets(record_layout, origin_cxx_record, origin_base_offsets) || !ExtractBaseOffsets(record_layout, origin_cxx_record, origin_virtual_base_offsets)) return false; } if (!ImportOffsetMap(&dest_ctx, field_offsets, origin_field_offsets, *this) || !ImportOffsetMap(&dest_ctx, base_offsets, origin_base_offsets, *this) || !ImportOffsetMap(&dest_ctx, vbase_offsets, origin_virtual_base_offsets, *this)) return false; size = record_layout.getSize().getQuantity() * dest_ctx.getCharWidth(); alignment = record_layout.getAlignment().getQuantity() * dest_ctx.getCharWidth(); if (log) { LLDB_LOG(log, "LRT returned:"); LLDB_LOG(log, "LRT Original = (RecordDecl*){0:x}", static_cast(origin_record.decl)); LLDB_LOG(log, "LRT Size = {0}", size); LLDB_LOG(log, "LRT Alignment = {0}", alignment); LLDB_LOG(log, "LRT Fields:"); for (RecordDecl::field_iterator fi = record->field_begin(), fe = record->field_end(); fi != fe; ++fi) { LLDB_LOG( log, "LRT (FieldDecl*){0:x}, Name = '{1}', Type = '{2}', Offset = " "{3} bits", *fi, fi->getName(), fi->getType().getAsString(), field_offsets[*fi]); } DeclFromParser parser_cxx_record = DynCast(parser_record); if (parser_cxx_record.IsValid()) { LLDB_LOG(log, "LRT Bases:"); for (CXXRecordDecl::base_class_const_iterator bi = parser_cxx_record->bases_begin(), be = parser_cxx_record->bases_end(); bi != be; ++bi) { bool is_virtual = bi->isVirtual(); QualType base_type = bi->getType(); const RecordType *base_record_type = base_type->getAs(); DeclFromParser base_record(base_record_type->getDecl()); DeclFromParser base_cxx_record = DynCast(base_record); LLDB_LOG(log, "LRT {0}(CXXRecordDecl*){1:x}, Name = '{2}', Offset = " "{3} chars", (is_virtual ? "Virtual " : ""), base_cxx_record.decl, base_cxx_record.decl->getName(), (is_virtual ? vbase_offsets[base_cxx_record.decl].getQuantity() : base_offsets[base_cxx_record.decl].getQuantity())); } } else { LLDB_LOG(log, "LRD Not a CXXRecord, so no bases"); } } return true; } bool ClangASTImporter::LayoutRecordType( const clang::RecordDecl *record_decl, uint64_t &bit_size, uint64_t &alignment, llvm::DenseMap &field_offsets, llvm::DenseMap &base_offsets, llvm::DenseMap &vbase_offsets) { RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find(record_decl); base_offsets.clear(); vbase_offsets.clear(); if (pos != m_record_decl_to_layout_map.end()) { bit_size = pos->second.bit_size; alignment = pos->second.alignment; field_offsets.swap(pos->second.field_offsets); base_offsets.swap(pos->second.base_offsets); vbase_offsets.swap(pos->second.vbase_offsets); m_record_decl_to_layout_map.erase(pos); return true; } // It's possible that we calculated the layout in a different // ClangASTImporter instance. Try to import such layout if // our decl has an origin. if (auto origin = GetDeclOrigin(record_decl); origin.Valid()) if (importRecordLayoutFromOrigin(record_decl, bit_size, alignment, field_offsets, base_offsets, vbase_offsets)) return true; bit_size = 0; alignment = 0; field_offsets.clear(); return false; } void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout) { m_record_decl_to_layout_map.insert(std::make_pair(decl, layout)); } bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) { DeclOrigin decl_origin = GetDeclOrigin(decl); if (!decl_origin.Valid()) return false; if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) return false; ImporterDelegateSP delegate_sp( GetDelegate(&decl->getASTContext(), decl_origin.ctx)); ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &decl->getASTContext()); if (delegate_sp) delegate_sp->ImportDefinitionTo(decl, decl_origin.decl); return true; } bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin_decl) { clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext(); if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl)) return false; ImporterDelegateSP delegate_sp( GetDelegate(&decl->getASTContext(), origin_ast_ctx)); if (delegate_sp) delegate_sp->ImportDefinitionTo(decl, origin_decl); ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); context_md->setOrigin(decl, DeclOrigin(origin_ast_ctx, origin_decl)); return true; } bool ClangASTImporter::CompleteObjCInterfaceDecl( clang::ObjCInterfaceDecl *interface_decl) { DeclOrigin decl_origin = GetDeclOrigin(interface_decl); if (!decl_origin.Valid()) return false; if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) return false; ImporterDelegateSP delegate_sp( GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx)); if (delegate_sp) delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl); if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass()) RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0)); return true; } bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) { if (!RequireCompleteType(type)) return false; Log *log = GetLog(LLDBLog::Expressions); if (const TagType *tag_type = type->getAs()) { TagDecl *tag_decl = tag_type->getDecl(); DeclOrigin decl_origin = GetDeclOrigin(tag_decl); if (!decl_origin.Valid()) return false; ImporterDelegateSP delegate_sp( GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx)); ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &tag_decl->getASTContext()); TagDecl *origin_tag_decl = llvm::dyn_cast(decl_origin.decl); for (Decl *origin_child_decl : origin_tag_decl->decls()) { llvm::Expected imported_or_err = delegate_sp->Import(origin_child_decl); if (!imported_or_err) { LLDB_LOG_ERROR(log, imported_or_err.takeError(), "Couldn't import decl: {0}"); return false; } } if (RecordDecl *record_decl = dyn_cast(origin_tag_decl)) record_decl->setHasLoadedFieldsFromExternalStorage(true); return true; } if (const ObjCObjectType *objc_object_type = type->getAs()) { if (ObjCInterfaceDecl *objc_interface_decl = objc_object_type->getInterface()) { DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl); if (!decl_origin.Valid()) return false; ImporterDelegateSP delegate_sp( GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx)); ObjCInterfaceDecl *origin_interface_decl = llvm::dyn_cast(decl_origin.decl); for (Decl *origin_child_decl : origin_interface_decl->decls()) { llvm::Expected imported_or_err = delegate_sp->Import(origin_child_decl); if (!imported_or_err) { LLDB_LOG_ERROR(log, imported_or_err.takeError(), "Couldn't import decl: {0}"); return false; } } return true; } return false; } return true; } bool ClangASTImporter::RequireCompleteType(clang::QualType type) { if (type.isNull()) return false; if (const TagType *tag_type = type->getAs()) { TagDecl *tag_decl = tag_type->getDecl(); if (tag_decl->getDefinition() || tag_decl->isBeingDefined()) return true; return CompleteTagDecl(tag_decl); } if (const ObjCObjectType *objc_object_type = type->getAs()) { if (ObjCInterfaceDecl *objc_interface_decl = objc_object_type->getInterface()) return CompleteObjCInterfaceDecl(objc_interface_decl); return false; } if (const ArrayType *array_type = type->getAsArrayTypeUnsafe()) return RequireCompleteType(array_type->getElementType()); if (const AtomicType *atomic_type = type->getAs()) return RequireCompleteType(atomic_type->getPointeeType()); return true; } ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) { DeclOrigin decl_origin = GetDeclOrigin(decl); if (decl_origin.Valid()) { TypeSystemClang *ast = TypeSystemClang::GetASTContext(decl_origin.ctx); return ast->GetMetadata(decl_origin.decl); } TypeSystemClang *ast = TypeSystemClang::GetASTContext(&decl->getASTContext()); return ast->GetMetadata(decl); } ClangASTImporter::DeclOrigin ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); return context_md->getOrigin(decl); } void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); context_md->setOrigin( decl, DeclOrigin(&original_decl->getASTContext(), original_decl)); } void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl, NamespaceMapSP &namespace_map) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); context_md->m_namespace_maps[decl] = namespace_map; } ClangASTImporter::NamespaceMapSP ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps; NamespaceMetaMap::iterator iter = namespace_maps.find(decl); if (iter != namespace_maps.end()) return iter->second; return NamespaceMapSP(); } void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) { assert(decl); ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); const DeclContext *parent_context = decl->getDeclContext(); const NamespaceDecl *parent_namespace = dyn_cast(parent_context); NamespaceMapSP parent_map; if (parent_namespace) parent_map = GetNamespaceMap(parent_namespace); NamespaceMapSP new_map; new_map = std::make_shared(); if (context_md->m_map_completer) { std::string namespace_string = decl->getDeclName().getAsString(); context_md->m_map_completer->CompleteNamespaceMap( new_map, ConstString(namespace_string.c_str()), parent_map); } context_md->m_namespace_maps[decl] = new_map; } void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) { Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG(log, " [ClangASTImporter] Forgetting destination (ASTContext*){0:x}", dst_ast); m_metadata_map.erase(dst_ast); } void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, clang::ASTContext *src_ast) { ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast); Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG(log, " [ClangASTImporter] Forgetting source->dest " "(ASTContext*){0:x}->(ASTContext*){1:x}", src_ast, dst_ast); if (!md) return; md->m_delegates.erase(src_ast); md->removeOriginsWithContext(src_ast); } ClangASTImporter::MapCompleter::~MapCompleter() = default; llvm::Expected ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { if (m_std_handler) { std::optional D = m_std_handler->Import(From); if (D) { // Make sure we don't use this decl later to map it back to it's original // decl. The decl the CxxModuleHandler created has nothing to do with // the one from debug info, and linking those two would just cause the // ASTImporter to try 'updating' the module decl with the minimal one from // the debug info. m_decls_to_ignore.insert(*D); return *D; } } // Check which ASTContext this declaration originally came from. DeclOrigin origin = m_main.GetDeclOrigin(From); // Prevent infinite recursion when the origin tracking contains a cycle. assert(origin.decl != From && "Origin points to itself?"); // If it originally came from the target ASTContext then we can just // pretend that the original is the one we imported. This can happen for // example when inspecting a persistent declaration from the scratch // ASTContext (which will provide the declaration when parsing the // expression and then we later try to copy the declaration back to the // scratch ASTContext to store the result). // Without this check we would ask the ASTImporter to import a declaration // into the same ASTContext where it came from (which doesn't make a lot of // sense). if (origin.Valid() && origin.ctx == &getToContext()) { RegisterImportedDecl(From, origin.decl); return origin.decl; } // This declaration came originally from another ASTContext. Instead of // copying our potentially incomplete 'From' Decl we instead go to the // original ASTContext and copy the original to the target. This is not // only faster than first completing our current decl and then copying it // to the target, but it also prevents that indirectly copying the same // declaration to the same target requires the ASTImporter to merge all // the different decls that appear to come from different ASTContexts (even // though all these different source ASTContexts just got a copy from // one source AST). if (origin.Valid()) { auto R = m_main.CopyDecl(&getToContext(), origin.decl); if (R) { RegisterImportedDecl(From, R); return R; } } // If we have a forcefully completed type, try to find an actual definition // for it in other modules. const ClangASTMetadata *md = m_main.GetDeclMetadata(From); auto *td = dyn_cast(From); if (td && md && md->IsForcefullyCompleted()) { Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG(log, "[ClangASTImporter] Searching for a complete definition of {0} in " "other modules", td->getName()); Expected dc_or_err = ImportContext(td->getDeclContext()); if (!dc_or_err) return dc_or_err.takeError(); Expected dn_or_err = Import(td->getDeclName()); if (!dn_or_err) return dn_or_err.takeError(); DeclContext *dc = *dc_or_err; DeclContext::lookup_result lr = dc->lookup(*dn_or_err); for (clang::Decl *candidate : lr) { if (candidate->getKind() == From->getKind()) { RegisterImportedDecl(From, candidate); m_decls_to_ignore.insert(candidate); return candidate; } } LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); } return ASTImporter::ImportImpl(From); } void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( clang::Decl *to, clang::Decl *from) { // We might have a forward declaration from a shared library that we // gave external lexical storage so that Clang asks us about the full // definition when it needs it. In this case the ASTImporter isn't aware // that the forward decl from the shared library is the actual import // target but would create a second declaration that would then be defined. // We want that 'to' is actually complete after this function so let's // tell the ASTImporter that 'to' was imported from 'from'. MapImported(from, to); Log *log = GetLog(LLDBLog::Expressions); if (llvm::Error err = ImportDefinition(from)) { LLDB_LOG_ERROR(log, std::move(err), "[ClangASTImporter] Error during importing definition: {0}"); return; } if (clang::TagDecl *to_tag = dyn_cast(to)) { if (clang::TagDecl *from_tag = dyn_cast(from)) { to_tag->setCompleteDefinition(from_tag->isCompleteDefinition()); if (Log *log_ast = GetLog(LLDBLog::AST)) { std::string name_string; if (NamedDecl *from_named_decl = dyn_cast(from)) { llvm::raw_string_ostream name_stream(name_string); from_named_decl->printName(name_stream); name_stream.flush(); } LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0:x}] Imported " "({1}Decl*){2:x}, named {3} (from " "(Decl*){4:x})", static_cast(to->getTranslationUnitDecl()), from->getDeclKindName(), static_cast(to), name_string, static_cast(from)); // Log the AST of the TU. std::string ast_string; llvm::raw_string_ostream ast_stream(ast_string); to->getTranslationUnitDecl()->dump(ast_stream); LLDB_LOG(log_ast, "{0}", ast_string); } } } // If we're dealing with an Objective-C class, ensure that the inheritance // has been set up correctly. The ASTImporter may not do this correctly if // the class was originally sourced from symbols. if (ObjCInterfaceDecl *to_objc_interface = dyn_cast(to)) { ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass(); if (to_superclass) return; // we're not going to override it if it's set ObjCInterfaceDecl *from_objc_interface = dyn_cast(from); if (!from_objc_interface) return; ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass(); if (!from_superclass) return; llvm::Expected imported_from_superclass_decl = Import(from_superclass); if (!imported_from_superclass_decl) { LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(), "Couldn't import decl: {0}"); return; } ObjCInterfaceDecl *imported_from_superclass = dyn_cast(*imported_from_superclass_decl); if (!imported_from_superclass) return; if (!to_objc_interface->hasDefinition()) to_objc_interface->startDefinition(); to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo( m_source_ctx->getObjCInterfaceType(imported_from_superclass))); } } /// Takes a CXXMethodDecl and completes the return type if necessary. This /// is currently only necessary for virtual functions with covariant return /// types where Clang's CodeGen expects that the underlying records are already /// completed. static void MaybeCompleteReturnType(ClangASTImporter &importer, CXXMethodDecl *to_method) { if (!to_method->isVirtual()) return; QualType return_type = to_method->getReturnType(); if (!return_type->isPointerType() && !return_type->isReferenceType()) return; clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl(); if (!rd) return; if (rd->getDefinition()) return; importer.CompleteTagDecl(rd); } /// Recreate a module with its parents in \p to_source and return its id. static OptionalClangModuleID RemapModule(OptionalClangModuleID from_id, ClangExternalASTSourceCallbacks &from_source, ClangExternalASTSourceCallbacks &to_source) { if (!from_id.HasValue()) return {}; clang::Module *module = from_source.getModule(from_id.GetValue()); OptionalClangModuleID parent = RemapModule( from_source.GetIDForModule(module->Parent), from_source, to_source); TypeSystemClang &to_ts = to_source.GetTypeSystem(); return to_ts.GetOrCreateClangModule(module->Name, parent, module->IsFramework, module->IsExplicit); } void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, clang::Decl *to) { Log *log = GetLog(LLDBLog::Expressions); // Some decls shouldn't be tracked here because they were not created by // copying 'from' to 'to'. Just exit early for those. if (m_decls_to_ignore.count(to)) return; // Transfer module ownership information. auto *from_source = llvm::dyn_cast_or_null( getFromContext().getExternalSource()); // Can also be a ClangASTSourceProxy. auto *to_source = llvm::dyn_cast_or_null( getToContext().getExternalSource()); if (from_source && to_source) { OptionalClangModuleID from_id(from->getOwningModuleID()); OptionalClangModuleID to_id = RemapModule(from_id, *from_source, *to_source); TypeSystemClang &to_ts = to_source->GetTypeSystem(); to_ts.SetOwningModule(to, to_id); } lldb::user_id_t user_id = LLDB_INVALID_UID; ClangASTMetadata *metadata = m_main.GetDeclMetadata(from); if (metadata) user_id = metadata->GetUserID(); if (log) { if (NamedDecl *from_named_decl = dyn_cast(from)) { std::string name_string; llvm::raw_string_ostream name_stream(name_string); from_named_decl->printName(name_stream); name_stream.flush(); LLDB_LOG( log, " [ClangASTImporter] Imported ({0}Decl*){1:x}, named {2} (from " "(Decl*){3:x}), metadata {4}", from->getDeclKindName(), to, name_string, from, user_id); } else { LLDB_LOG(log, " [ClangASTImporter] Imported ({0}Decl*){1:x} (from " "(Decl*){2:x}), metadata {3}", from->getDeclKindName(), to, from, user_id); } } ASTContextMetadataSP to_context_md = m_main.GetContextMetadata(&to->getASTContext()); ASTContextMetadataSP from_context_md = m_main.MaybeGetContextMetadata(m_source_ctx); if (from_context_md) { DeclOrigin origin = from_context_md->getOrigin(from); if (origin.Valid()) { if (origin.ctx != &to->getASTContext()) { if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) to_context_md->setOrigin(to, origin); LLDB_LOG(log, " [ClangASTImporter] Propagated origin " "(Decl*){0:x}/(ASTContext*){1:x} from (ASTContext*){2:x} to " "(ASTContext*){3:x}", origin.decl, origin.ctx, &from->getASTContext(), &to->getASTContext()); } } else { if (m_new_decl_listener) m_new_decl_listener->NewDeclImported(from, to); if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Decl has no origin information in " "(ASTContext*){0:x}", &from->getASTContext()); } if (auto *to_namespace = dyn_cast(to)) { auto *from_namespace = cast(from); NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps; NamespaceMetaMap::iterator namespace_map_iter = namespace_maps.find(from_namespace); if (namespace_map_iter != namespace_maps.end()) to_context_md->m_namespace_maps[to_namespace] = namespace_map_iter->second; } } else { to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Sourced origin " "(Decl*){0:x}/(ASTContext*){1:x} into (ASTContext*){2:x}", from, m_source_ctx, &to->getASTContext()); } if (auto *to_tag_decl = dyn_cast(to)) { to_tag_decl->setHasExternalLexicalStorage(); to_tag_decl->getPrimaryContext()->setMustBuildLookupTable(); auto from_tag_decl = cast(from); LLDB_LOG( log, " [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]", (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""), (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""), (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"), (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete")); } if (auto *to_namespace_decl = dyn_cast(to)) { m_main.BuildNamespaceMap(to_namespace_decl); to_namespace_decl->setHasExternalVisibleStorage(); } if (auto *to_container_decl = dyn_cast(to)) { to_container_decl->setHasExternalLexicalStorage(); to_container_decl->setHasExternalVisibleStorage(); if (log) { if (ObjCInterfaceDecl *to_interface_decl = llvm::dyn_cast(to_container_decl)) { LLDB_LOG( log, " [ClangASTImporter] To is an ObjCInterfaceDecl - attributes " "{0}{1}{2}", (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""), (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""), (to_interface_decl->hasDefinition() ? " HasDefinition" : "")); } else { LLDB_LOG( log, " [ClangASTImporter] To is an {0}Decl - attributes {1}{2}", ((Decl *)to_container_decl)->getDeclKindName(), (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""), (to_container_decl->hasExternalVisibleStorage() ? " Visible" : "")); } } } if (clang::CXXMethodDecl *to_method = dyn_cast(to)) MaybeCompleteReturnType(m_main, to_method); } clang::Decl * ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) { return m_main.GetDeclOrigin(To).decl; }