Files
llvm/lldb/source/Symbol/ClangASTImporter.cpp
Sean Callanan 5b26f27f46 I have brought LLDB up-to-date with top of tree
LLVM/Clang.  This brings in several fixes, including:

- Improvements in the Just-In-Time compiler's
  allocation of memory: the JIT now allocates
  memory in chunks of sections, improving its
  ability to generate relocations.  I have
  revamped the RecordingMemoryManager to reflect
  these changes, as well as to get the memory
  allocation and data copying out fo the
  ClangExpressionParser code.  Jim Grosbach wrote
  the updates to the JIT on the LLVM side.

- A new ExternalASTSource interface to allow LLDB to
  report accurate structure layout information to
  Clang.  Previously we could only report the sizes
  of fields, not their offsets.  This meant that if
  data structures included field alignment
  directives, we could not communicate the necessary
  alignment to Clang and accesses to the data would
  fail.  Now we can (and I have update the relevant
  test case).  Thanks to Doug Gregor for implementing
  the Clang side of this fix.

- The way Objective-C interfaces are completed by
  Clang has been made consistent with RecordDecls;
  with help from Doug Gregor and Greg Clayton I have
  ensured that this still works.

- I have eliminated all local LLVM and Clang patches,
  committing the ones that are still relevant to LLVM
  and Clang as needed.

I have tested the changes extensively locally, but
please let me know if they cause any trouble for you.

llvm-svn: 149775
2012-02-04 08:49:35 +00:00

535 lines
17 KiB
C++

//===-- ClangASTImporter.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangASTImporter.h"
#include "lldb/Symbol/ClangNamespaceDecl.h"
using namespace lldb_private;
using namespace clang;
clang::QualType
ClangASTImporter::CopyType (clang::ASTContext *dst_ast,
clang::ASTContext *src_ast,
clang::QualType type)
{
MinionSP minion_sp (GetMinion(dst_ast, src_ast));
if (minion_sp)
return minion_sp->Import(type);
return QualType();
}
lldb::clang_type_t
ClangASTImporter::CopyType (clang::ASTContext *dst_ast,
clang::ASTContext *src_ast,
lldb::clang_type_t type)
{
return CopyType (dst_ast, src_ast, QualType::getFromOpaquePtr(type)).getAsOpaquePtr();
}
clang::Decl *
ClangASTImporter::CopyDecl (clang::ASTContext *dst_ast,
clang::ASTContext *src_ast,
clang::Decl *decl)
{
MinionSP minion_sp;
minion_sp = GetMinion(dst_ast, src_ast);
if (minion_sp)
{
clang::Decl *result = minion_sp->Import(decl);
if (!result)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
{
if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl))
log->Printf(" [ClangASTImporter] WARNING: Failed to import a %s '%s'", decl->getDeclKindName(), named_decl->getNameAsString().c_str());
else
log->Printf(" [ClangASTImporter] WARNING: Failed to import a %s", decl->getDeclKindName());
}
}
return result;
}
return NULL;
}
lldb::clang_type_t
ClangASTImporter::DeportType (clang::ASTContext *dst_ctx,
clang::ASTContext *src_ctx,
lldb::clang_type_t type)
{
lldb::clang_type_t result = CopyType(dst_ctx, src_ctx, type);
if (!result)
return NULL;
QualType qual_type = QualType::getFromOpaquePtr(type);
if (const TagType *tag_type = qual_type->getAs<TagType>())
{
TagDecl *tag_decl = tag_type->getDecl();
const TagType *result_tag_type = QualType::getFromOpaquePtr(result)->getAs<TagType>();
TagDecl *result_tag_decl = result_tag_type->getDecl();
if (tag_decl)
{
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
minion_sp->ImportDefinitionTo(result_tag_decl, tag_decl);
ASTContextMetadataSP to_context_md = GetContextMetadata(dst_ctx);
OriginMap::iterator oi = to_context_md->m_origins.find(result_tag_decl);
if (oi != to_context_md->m_origins.end() &&
oi->second.ctx == src_ctx)
to_context_md->m_origins.erase(oi);
}
}
return result;
}
clang::Decl *
ClangASTImporter::DeportDecl (clang::ASTContext *dst_ctx,
clang::ASTContext *src_ctx,
clang::Decl *decl)
{
clang::Decl *result = CopyDecl(dst_ctx, src_ctx, decl);
if (!result)
return NULL;
ClangASTContext::GetCompleteDecl (src_ctx, decl);
MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
if (minion_sp && isa<TagDecl>(decl))
minion_sp->ImportDefinitionTo(result, decl);
ASTContextMetadataSP to_context_md = GetContextMetadata(dst_ctx);
OriginMap::iterator oi = to_context_md->m_origins.find(decl);
if (oi != to_context_md->m_origins.end() &&
oi->second.ctx == src_ctx)
to_context_md->m_origins.erase(oi);
return result;
}
void
ClangASTImporter::CompleteDecl (clang::Decl *decl)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
log->Printf(" [ClangASTImporter] CompleteDecl called on (%sDecl*)%p",
decl->getDeclKindName(),
decl);
if (ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl))
{
if (!interface_decl->getDefinition())
{
interface_decl->startDefinition();
CompleteObjCInterfaceDecl(interface_decl);
}
}
else if (ObjCProtocolDecl *protocol_decl = dyn_cast<ObjCProtocolDecl>(protocol_decl))
{
if (!protocol_decl->getDefinition())
protocol_decl->startDefinition();
}
else if (TagDecl *tag_decl = dyn_cast<TagDecl>(decl))
{
if (!tag_decl->getDefinition() && !tag_decl->isBeingDefined())
{
tag_decl->startDefinition();
CompleteTagDecl(tag_decl);
tag_decl->setCompleteDefinition(true);
}
}
else {
assert (0 && "CompleteDecl called on a Decl that can't be completed");
}
}
bool
ClangASTImporter::CompleteTagDecl (clang::TagDecl *decl)
{
DeclOrigin decl_origin = GetDeclOrigin(decl);
if (!decl_origin.Valid())
return false;
if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
return false;
MinionSP minion_sp (GetMinion(&decl->getASTContext(), decl_origin.ctx));
if (minion_sp)
minion_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 (!ClangASTContext::GetCompleteDecl(origin_ast_ctx, origin_decl))
return false;
MinionSP minion_sp (GetMinion(&decl->getASTContext(), origin_ast_ctx));
if (minion_sp)
minion_sp->ImportDefinitionTo(decl, origin_decl);
ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
OriginMap &origins = context_md->m_origins;
origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl);
return true;
}
bool
ClangASTImporter::CompleteObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface_decl)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
DeclOrigin decl_origin = GetDeclOrigin(interface_decl);
if (!decl_origin.Valid())
return false;
if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
return false;
MinionSP minion_sp (GetMinion(&interface_decl->getASTContext(), decl_origin.ctx));
if (minion_sp)
minion_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
return true;
}
ClangASTImporter::DeclOrigin
ClangASTImporter::GetDeclOrigin(const clang::Decl *decl)
{
ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
OriginMap &origins = context_md->m_origins;
OriginMap::iterator iter = origins.find(decl);
if (iter != origins.end())
return iter->second;
else
return DeclOrigin();
}
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;
else
return NamespaceMapSP();
}
void
ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *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.reset(new 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)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
log->Printf(" [ClangASTImporter] Forgetting destination (ASTContext*)%p", dst_ast);
m_metadata_map.erase(dst_ast);
}
void
ClangASTImporter::ForgetSource (clang::ASTContext *dst_ast, clang::ASTContext *src_ast)
{
ASTContextMetadataSP md = MaybeGetContextMetadata (dst_ast);
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
log->Printf(" [ClangASTImporter] Forgetting source->dest (ASTContext*)%p->(ASTContext*)%p", src_ast, dst_ast);
if (!md)
return;
md->m_minions.erase(src_ast);
for (OriginMap::iterator iter = md->m_origins.begin();
iter != md->m_origins.end();
)
{
if (iter->second.ctx == src_ast)
md->m_origins.erase(iter++);
else
++iter;
}
}
ClangASTImporter::MapCompleter::~MapCompleter ()
{
return;
}
void
ClangASTImporter::Minion::ImportDefinitionTo (clang::Decl *to, clang::Decl *from)
{
ASTImporter::Imported(from, to);
ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to);
/*
if (to_objc_interface)
to_objc_interface->startDefinition();
CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to);
if (to_cxx_record)
to_cxx_record->startDefinition();
*/
ImportDefinition(from);
// 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 (to_objc_interface)
{
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;
Decl *imported_from_superclass_decl = Import(from_superclass);
if (!imported_from_superclass_decl)
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(imported_from_superclass);
}
while (0);
}
}
clang::Decl
*ClangASTImporter::Minion::Imported (clang::Decl *from, clang::Decl *to)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (log)
{
if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from))
{
log->Printf(" [ClangASTImporter] Imported (%sDecl*)%p, named %s (from (Decl*)%p)",
from->getDeclKindName(),
to,
from_named_decl->getName().str().c_str(),
from);
if (!strcmp(from->getDeclKindName(), "ClassTemplateSpecialization") &&
!from_named_decl->getName().str().compare("rebind"))
fprintf(stderr, "This is the one!");
}
else
{
log->Printf(" [ClangASTImporter] Imported (%sDecl*)%p (from (Decl*)%p)",
from->getDeclKindName(),
to,
from);
}
}
ASTContextMetadataSP to_context_md = m_master.GetContextMetadata(&to->getASTContext());
ASTContextMetadataSP from_context_md = m_master.MaybeGetContextMetadata(m_source_ctx);
if (from_context_md)
{
OriginMap &origins = from_context_md->m_origins;
OriginMap::iterator origin_iter = origins.find(from);
if (origin_iter != origins.end())
{
to_context_md->m_origins[to] = origin_iter->second;
MinionSP direct_completer = m_master.GetMinion(&to->getASTContext(), origin_iter->second.ctx);
if (direct_completer.get() != this)
direct_completer->ASTImporter::Imported(origin_iter->second.decl, to);
if (log)
log->Printf(" [ClangASTImporter] Propagated origin (Decl*)%p/(ASTContext*)%p from (ASTContext*)%p to (ASTContext*)%p",
origin_iter->second.decl,
origin_iter->second.ctx,
&from->getASTContext(),
&to->getASTContext());
}
else
{
to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
if (log)
log->Printf(" [ClangASTImporter] Decl has no origin information in (ASTContext*)%p",
&from->getASTContext());
}
if (clang::NamespaceDecl *to_namespace = dyn_cast<clang::NamespaceDecl>(to))
{
clang::NamespaceDecl *from_namespace = dyn_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->m_origins[to] = DeclOrigin (m_source_ctx, from);
if (log)
log->Printf(" [ClangASTImporter] Sourced origin (Decl*)%p/(ASTContext*)%p into (ASTContext*)%p",
from,
m_source_ctx,
&to->getASTContext());
}
if (TagDecl *from_tag_decl = dyn_cast<TagDecl>(from))
{
TagDecl *to_tag_decl = dyn_cast<TagDecl>(to);
to_tag_decl->setHasExternalLexicalStorage();
if (log)
log->Printf(" [ClangASTImporter] To is a TagDecl - attributes %s%s [%s->%s]",
(to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
(to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
(from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
(to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
to_tag_decl = NULL;
}
if (isa<NamespaceDecl>(from))
{
NamespaceDecl *to_namespace_decl = dyn_cast<NamespaceDecl>(to);
m_master.BuildNamespaceMap(to_namespace_decl);
to_namespace_decl->setHasExternalVisibleStorage();
}
if (isa<ObjCInterfaceDecl>(from))
{
ObjCInterfaceDecl *to_interface_decl = dyn_cast<ObjCInterfaceDecl>(to);
to_interface_decl->setHasExternalLexicalStorage();
to_interface_decl->setHasExternalVisibleStorage();
/*to_interface_decl->setExternallyCompleted();*/
if (log)
log->Printf(" [ClangASTImporter] To is an ObjCInterfaceDecl - attributes %s%s%s",
(to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
(to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
(to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
}
return clang::ASTImporter::Imported(from, to);
}