The ASTImporter::Imported base method has been made a no-op in
26f72a9655. So all calls to it from
a base-class are now redundant. The API is now only used to notify
subclasses that an import occurred and not for any other
bookkeeping (which is done in MapImported which we call properly).
Differential Revision: https://reviews.llvm.org/D158172
1175 lines
41 KiB
C++
1175 lines
41 KiB
C++
//===-- 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/Decl.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "clang/AST/DeclObjC.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 <memory>
|
|
#include <optional>
|
|
|
|
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<TypeSystemClang>();
|
|
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<QualType> 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<clang::Decl *> 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<NamedDecl>(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<clang::Decl *, Backup> 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<clang::DeclContext>(decl);
|
|
|
|
if (!base) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (clang::DeclContext *context =
|
|
clang::dyn_cast<clang::DeclContext>(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<FunctionDecl>(redecl_context) &&
|
|
llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) {
|
|
for (clang::Decl *child_decl : decl_context->decls()) {
|
|
Override(child_decl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
~DeclContextOverride() {
|
|
for (const std::pair<clang::Decl *, Backup> &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<NamedDecl *> m_decls_to_complete;
|
|
/// Set of declarations that already were successfully completed (not just
|
|
/// added to m_decls_to_complete).
|
|
llvm::SmallPtrSet<NamedDecl *, 32> 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<TagDecl>(decl)) {
|
|
if (auto *original_tag_decl = dyn_cast<TagDecl>(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<ObjCContainerDecl>(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<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to))
|
|
return;
|
|
RecordDecl *from_record_decl = dyn_cast<RecordDecl>(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<NamedDecl>(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<TypeSystemClang>();
|
|
if (!src_ctxt)
|
|
return {};
|
|
|
|
LLDB_LOG(log,
|
|
" [ClangASTImporter] DeportType called on ({0}Type*){1} "
|
|
"from (ASTContext*){2} to (ASTContext*){3}",
|
|
src_type.GetTypeName(), src_type.GetOpaqueQualType(),
|
|
&src_ctxt->getASTContext(), &dst.getASTContext());
|
|
|
|
DeclContextOverride decl_context_override;
|
|
|
|
if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>())
|
|
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} from "
|
|
"(ASTContext*){2} to (ASTContext*){3}",
|
|
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} to "
|
|
"({2}Decl*){3}",
|
|
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<clang::EnumType>(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<clang::ObjCObjectType>(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<clang::TypedefType>(qual_type)
|
|
->getDecl()
|
|
->getUnderlyingType()
|
|
.getAsOpaquePtr()));
|
|
|
|
case clang::Type::Auto:
|
|
return CanImport(CompilerType(type.GetTypeSystem(),
|
|
llvm::cast<clang::AutoType>(qual_type)
|
|
->getDeducedType()
|
|
.getAsOpaquePtr()));
|
|
|
|
case clang::Type::Elaborated:
|
|
return CanImport(CompilerType(type.GetTypeSystem(),
|
|
llvm::cast<clang::ElaboratedType>(qual_type)
|
|
->getNamedType()
|
|
.getAsOpaquePtr()));
|
|
|
|
case clang::Type::Paren:
|
|
return CanImport(CompilerType(
|
|
type.GetTypeSystem(),
|
|
llvm::cast<clang::ParenType>(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<clang::EnumType>(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<clang::ObjCObjectType>(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<clang::TypedefType>(qual_type)
|
|
->getDecl()
|
|
->getUnderlyingType()
|
|
.getAsOpaquePtr()));
|
|
|
|
case clang::Type::Auto:
|
|
return Import(CompilerType(type.GetTypeSystem(),
|
|
llvm::cast<clang::AutoType>(qual_type)
|
|
->getDeducedType()
|
|
.getAsOpaquePtr()));
|
|
|
|
case clang::Type::Elaborated:
|
|
return Import(CompilerType(type.GetTypeSystem(),
|
|
llvm::cast<clang::ElaboratedType>(qual_type)
|
|
->getNamedType()
|
|
.getAsOpaquePtr()));
|
|
|
|
case clang::Type::Paren:
|
|
return Import(CompilerType(
|
|
type.GetTypeSystem(),
|
|
llvm::cast<clang::ParenType>(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;
|
|
}
|
|
|
|
bool ClangASTImporter::LayoutRecordType(
|
|
const clang::RecordDecl *record_decl, uint64_t &bit_size,
|
|
uint64_t &alignment,
|
|
llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
|
|
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
|
|
&base_offsets,
|
|
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
|
|
&vbase_offsets) {
|
|
RecordDeclToLayoutMap::iterator pos =
|
|
m_record_decl_to_layout_map.find(record_decl);
|
|
bool success = false;
|
|
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);
|
|
success = true;
|
|
} else {
|
|
bit_size = 0;
|
|
alignment = 0;
|
|
field_offsets.clear();
|
|
}
|
|
return success;
|
|
}
|
|
|
|
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<TagType>()) {
|
|
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<TagDecl>(decl_origin.decl);
|
|
|
|
for (Decl *origin_child_decl : origin_tag_decl->decls()) {
|
|
llvm::Expected<Decl *> 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<RecordDecl>(origin_tag_decl))
|
|
record_decl->setHasLoadedFieldsFromExternalStorage(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
|
|
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<ObjCInterfaceDecl>(decl_origin.decl);
|
|
|
|
for (Decl *origin_child_decl : origin_interface_decl->decls()) {
|
|
llvm::Expected<Decl *> 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<TagType>()) {
|
|
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<ObjCObjectType>()) {
|
|
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<AtomicType>())
|
|
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<NamespaceDecl>(parent_context);
|
|
NamespaceMapSP parent_map;
|
|
|
|
if (parent_namespace)
|
|
parent_map = GetNamespaceMap(parent_namespace);
|
|
|
|
NamespaceMapSP new_map;
|
|
|
|
new_map = std::make_shared<NamespaceMap>();
|
|
|
|
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}",
|
|
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}->(ASTContext*){1}",
|
|
src_ast, dst_ast);
|
|
|
|
if (!md)
|
|
return;
|
|
|
|
md->m_delegates.erase(src_ast);
|
|
md->removeOriginsWithContext(src_ast);
|
|
}
|
|
|
|
ClangASTImporter::MapCompleter::~MapCompleter() = default;
|
|
|
|
llvm::Expected<Decl *>
|
|
ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
|
|
if (m_std_handler) {
|
|
std::optional<Decl *> 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<TagDecl>(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<DeclContext *> dc_or_err = ImportContext(td->getDeclContext());
|
|
if (!dc_or_err)
|
|
return dc_or_err.takeError();
|
|
Expected<DeclarationName> 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<clang::TagDecl>(to)) {
|
|
if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(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<clang::NamedDecl>(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}] Imported "
|
|
"({1}Decl*){2}, named {3} (from "
|
|
"(Decl*){4})",
|
|
static_cast<void *>(to->getTranslationUnitDecl()),
|
|
from->getDeclKindName(), static_cast<void *>(to), name_string,
|
|
static_cast<void *>(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<ObjCInterfaceDecl>(to)) {
|
|
do {
|
|
ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass();
|
|
|
|
if (to_superclass)
|
|
break; // we're not going to override it if it's set
|
|
|
|
ObjCInterfaceDecl *from_objc_interface =
|
|
dyn_cast<ObjCInterfaceDecl>(from);
|
|
|
|
if (!from_objc_interface)
|
|
break;
|
|
|
|
ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass();
|
|
|
|
if (!from_superclass)
|
|
break;
|
|
|
|
llvm::Expected<Decl *> 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}");
|
|
break;
|
|
}
|
|
|
|
ObjCInterfaceDecl *imported_from_superclass =
|
|
dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl);
|
|
|
|
if (!imported_from_superclass)
|
|
break;
|
|
|
|
if (!to_objc_interface->hasDefinition())
|
|
to_objc_interface->startDefinition();
|
|
|
|
to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo(
|
|
m_source_ctx->getObjCInterfaceType(imported_from_superclass)));
|
|
} while (false);
|
|
}
|
|
}
|
|
|
|
/// 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<ClangExternalASTSourceCallbacks>(
|
|
getFromContext().getExternalSource());
|
|
// Can also be a ClangASTSourceProxy.
|
|
auto *to_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>(
|
|
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<clang::NamedDecl>(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}, named {2} (from "
|
|
"(Decl*){3}), metadata {4}",
|
|
from->getDeclKindName(), to, name_string, from, user_id);
|
|
} else {
|
|
LLDB_LOG(log,
|
|
" [ClangASTImporter] Imported ({0}Decl*){1} (from "
|
|
"(Decl*){2}), 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}/(ASTContext*){1} from (ASTContext*){2} to "
|
|
"(ASTContext*){3}",
|
|
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}",
|
|
&from->getASTContext());
|
|
}
|
|
|
|
if (auto *to_namespace = dyn_cast<clang::NamespaceDecl>(to)) {
|
|
auto *from_namespace = cast<clang::NamespaceDecl>(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}/(ASTContext*){1} into (ASTContext*){2}",
|
|
from, m_source_ctx, &to->getASTContext());
|
|
}
|
|
|
|
if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
|
|
to_tag_decl->setHasExternalLexicalStorage();
|
|
to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
|
|
auto from_tag_decl = cast<TagDecl>(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<NamespaceDecl>(to)) {
|
|
m_main.BuildNamespaceMap(to_namespace_decl);
|
|
to_namespace_decl->setHasExternalVisibleStorage();
|
|
}
|
|
|
|
if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
|
|
to_container_decl->setHasExternalLexicalStorage();
|
|
to_container_decl->setHasExternalVisibleStorage();
|
|
|
|
if (log) {
|
|
if (ObjCInterfaceDecl *to_interface_decl =
|
|
llvm::dyn_cast<ObjCInterfaceDecl>(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<CXXMethodDecl>(to))
|
|
MaybeCompleteReturnType(m_main, to_method);
|
|
}
|
|
|
|
clang::Decl *
|
|
ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) {
|
|
return m_main.GetDeclOrigin(To).decl;
|
|
}
|