<rdar://problem/11113279>

Fixed type lookups to "do the right thing". Prior to this fix, looking up a type using "foo::bar" would result in a type list that contains all types that had "bar" as a basename unless the symbol file was able to match fully qualified names (which our DWARF parser does not). 

This fix will allow type matches to be made based on the basename and then have the types that don't match filtered out. Types by name can be fully qualified, or partially qualified with the new "bool exact_match" parameter to the Module::FindTypes() method.

This fixes some issue that we discovered with dynamic type resolution as well as improves the overall type lookups in LLDB.

llvm-svn: 153482
This commit is contained in:
Greg Clayton 2012-03-26 23:03:23 +00:00
parent 98e5d863ad
commit 84db9105d2
44 changed files with 584 additions and 262 deletions

View File

@ -519,11 +519,11 @@ protected:
return false;
}
bool Get(ValueObject& valobj,
clang::QualType type,
MapValueType& entry,
lldb::DynamicValueType use_dynamic,
uint32_t& reason)
bool Get (ValueObject& valobj,
clang::QualType type, // TODO: find out why "type" is passed in the type when it belongs to valobj? Can it ever differ?
MapValueType& entry,
lldb::DynamicValueType use_dynamic,
uint32_t& reason)
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
if (type.isNull())
@ -541,7 +541,7 @@ protected:
log->Printf("type is NULL, returning");
return false;
}
ConstString typeName(ClangASTType::GetTypeNameForQualType(type).c_str());
ConstString typeName(ClangASTType::GetTypeNameForQualType(valobj.GetClangAST(), type).c_str());
if (valobj.GetBitfieldBitSize() > 0)
{

View File

@ -620,32 +620,37 @@ public:
//------------------------------------------------------------------
/// Find types by name.
///
/// Type lookups in modules go through the SymbolVendor (which will
/// use one or more SymbolFile subclasses). The SymbolFile needs to
/// be able to lookup types by basename and not the fully qualified
/// typename. This allows the type accelerator tables to stay small,
/// even with heavily templatized C++. The type search will then
/// narrow down the search results. If "exact_match" is true, then
/// the type search will only match exact type name matches. If
/// "exact_match" is false, the type will match as long as the base
/// typename matches and as long as any immediate containing
/// namespaces/class scopes that are specified match. So to search
/// for a type "d" in "b::c", the name "b::c::d" can be specified
/// and it will match any class/namespace "b" which contains a
/// class/namespace "c" which contains type "d". We do this to
/// allow users to not always have to specify complete scoping on
/// all expressions, but it also allows for exact matching when
/// required.
///
/// @param[in] sc
/// A symbol context that scopes where to extract a type list
/// from.
///
/// @param[in] name
/// The name of the type we are looking for.
/// @param[in] type_name
/// The name of the type we are looking for that is a fully
/// or partially qualfieid type name.
///
/// @param[in] namespace_decl
/// If valid, a namespace to search in.
///
/// @param[in] append
/// If \b true, any matches will be appended to \a
/// variable_list, else matches replace the contents of
/// \a variable_list.
///
/// @param[in] max_matches
/// Allow the number of matches to be limited to \a
/// max_matches. Specify UINT32_MAX to get all possible matches.
///
/// @param[in] encoding
/// Limit the search to specific types, or get all types if
/// set to Type::invalid.
///
/// @param[in] udt_name
/// If the encoding is a user defined type, specify the name
/// of the user defined type ("struct", "union", "class", etc).
/// @param[in] exact_match
/// If \b true, \a type_name is fully qualifed and must match
/// exactly. If \b false, \a type_name is a partially qualfied
/// name where the leading namespaces or classes can be
/// omitted to make finding types that a user may type
/// easier.
///
/// @param[out] type_list
/// A type list gets populated with any matches.
@ -655,12 +660,40 @@ public:
//------------------------------------------------------------------
uint32_t
FindTypes (const SymbolContext& sc,
const ConstString &name,
const ClangNamespaceDecl *namespace_decl,
bool append,
uint32_t max_matches,
const ConstString &type_name,
bool exact_match,
uint32_t max_matches,
TypeList& types);
//------------------------------------------------------------------
/// Find types by name that are in a namespace. This function is
/// used by the expression parser when searches need to happen in
/// an exact namespace scope.
///
/// @param[in] sc
/// A symbol context that scopes where to extract a type list
/// from.
///
/// @param[in] type_name
/// The name of a type within a namespace that should not include
/// any qualifying namespaces (just a type basename).
///
/// @param[in] namespace_decl
/// The namespace declaration that this type must exist in.
///
/// @param[out] type_list
/// A type list gets populated with any matches.
///
/// @return
/// The number of matches added to \a type_list.
//------------------------------------------------------------------
uint32_t
FindTypesInNamespace (const SymbolContext& sc,
const ConstString &type_name,
const ClangNamespaceDecl *namespace_decl,
uint32_t max_matches,
TypeList& type_list);
//------------------------------------------------------------------
/// Get const accessor for the module architecture.
///

View File

@ -340,10 +340,10 @@ public:
/// The number of matches added to \a type_list.
//------------------------------------------------------------------
uint32_t
FindTypes (const SymbolContext& sc,
const ConstString &name,
bool append,
uint32_t max_matches,
FindTypes2 (const SymbolContext& sc,
const ConstString &name,
bool name_is_fully_qualified,
uint32_t max_matches,
TypeList& types);
bool

View File

@ -566,12 +566,15 @@ public:
virtual lldb::ValueType
GetValueType() const = 0;
virtual ConstString
GetTypeName() = 0;
//------------------------------------------------------------------
// Sublasses can implement the functions below.
//------------------------------------------------------------------
virtual ConstString
GetTypeName();
virtual ConstString
GetQualifiedTypeName();
virtual lldb::LanguageType
GetObjectRuntimeLanguage();

View File

@ -59,6 +59,9 @@ public:
virtual ConstString
GetTypeName();
virtual ConstString
GetQualifiedTypeName();
virtual bool
IsInScope ();

View File

@ -33,9 +33,6 @@ namespace lldb_private {
virtual size_t
GetByteSize();
virtual ConstString
GetTypeName();
virtual uint32_t
CalculateNumChildren();

View File

@ -37,6 +37,9 @@ public:
virtual ConstString
GetTypeName();
virtual ConstString
GetQualifiedTypeName();
virtual uint32_t
CalculateNumChildren();

View File

@ -78,15 +78,25 @@ public:
ConstString
GetConstTypeName ();
ConstString
GetConstQualifiedTypeName ();
static ConstString
GetConstTypeName (lldb::clang_type_t clang_type);
GetConstTypeName (clang::ASTContext *ast,
lldb::clang_type_t clang_type);
static std::string
GetTypeNameForQualType (clang::QualType qual_type);
static ConstString
GetConstQualifiedTypeName (clang::ASTContext *ast,
lldb::clang_type_t clang_type);
static std::string
GetTypeNameForOpaqueQualType (lldb::clang_type_t opaque_qual_type);
GetTypeNameForQualType (clang::ASTContext *ast,
clang::QualType qual_type);
static std::string
GetTypeNameForOpaqueQualType (clang::ASTContext *ast,
lldb::clang_type_t opaque_qual_type);
uint32_t
GetClangTypeBitWidth ();

View File

@ -147,6 +147,9 @@ public:
return m_name;
}
ConstString
GetQualifiedName ();
void
DumpValue(ExecutionContext *exe_ctx,
Stream *s,
@ -240,6 +243,12 @@ public:
static int
Compare(const Type &a, const Type &b);
// From a fully qualified typename, split the type into the type basename
// and the remaining type scope (namespaces/classes).
static bool
GetTypeScopeAndBasename (const char* name_cstr,
std::string &scope,
std::string &basename);
void
SetEncodingType (Type *encoding_type)
{
@ -491,7 +500,7 @@ public:
{
return m_name;
}
uint64_t
GetBitOffset () const
{

View File

@ -51,6 +51,17 @@ public:
lldb::TypeSP
GetTypeAtIndex(uint32_t idx);
bool
RemoveTypeWithUID (lldb::user_id_t uid);
void
RemoveMismatchedTypes (const char *qualified_typename,
bool exact_match);
void
RemoveMismatchedTypes (const std::string &type_scope,
const std::string &type_basename,
bool exact_match);
private:
typedef std::multimap<lldb::user_id_t, lldb::TypeSP> collection;
typedef collection::iterator iterator;

View File

@ -425,12 +425,12 @@ SBModule::FindFirstType (const char *name_cstr)
SymbolContext sc;
TypeList type_list;
uint32_t num_matches = 0;
const bool exact_match = false;
ConstString name(name_cstr);
num_matches = module_sp->FindTypes (sc,
name,
NULL,
false,
exact_match,
1,
type_list);
@ -451,13 +451,13 @@ SBModule::FindTypes (const char *type)
{
SymbolContext sc;
TypeList type_list;
const bool exact_match = false;
uint32_t num_matches = 0;
ConstString name(type);
num_matches = module_sp->FindTypes (sc,
name,
NULL,
false,
exact_match,
UINT32_MAX,
type_list);

View File

@ -1954,14 +1954,15 @@ SBTarget::FindTypes (const char* type)
{
ModuleList& images = target_sp->GetImages();
ConstString name_const(type);
bool exact_match = false;
SymbolContext sc;
TypeList type_list;
uint32_t num_matches = images.FindTypes(sc,
name_const,
true,
UINT32_MAX,
type_list);
uint32_t num_matches = images.FindTypes2 (sc,
name_const,
exact_match,
UINT32_MAX,
type_list);
for (size_t idx = 0; idx < num_matches; idx++)
{

View File

@ -441,7 +441,8 @@ SBType::GetName()
if (!IsValid())
return "";
return ClangASTType::GetConstTypeName(m_opaque_sp->GetOpaqueQualType()).GetCString();
return ClangASTType::GetConstTypeName(m_opaque_sp->GetASTContext(),
m_opaque_sp->GetOpaqueQualType()).GetCString();
}
lldb::TypeClass

View File

@ -138,7 +138,8 @@ SBValue::GetTypeName ()
const char *name = NULL;
lldb::ValueObjectSP value_sp(GetSP());
if (value_sp)
name = value_sp->GetTypeName().GetCString();
//name = value_sp->GetTypeName().GetCString();
name = value_sp->GetQualifiedTypeName().GetCString();
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
{

View File

@ -386,7 +386,7 @@ public:
{
// We are viewing memory as a type
SymbolContext sc;
const bool append = true;
const bool exact_match = false;
TypeList type_list;
uint32_t reference_count = 0;
uint32_t pointer_count = 0;
@ -458,17 +458,16 @@ public:
{
sc.module_sp->FindTypes (sc,
lookup_type_name,
NULL,
append,
exact_match,
1,
type_list);
}
}
if (type_list.GetSize() == 0)
{
target->GetImages().FindTypes (sc,
target->GetImages().FindTypes2 (sc,
lookup_type_name,
append,
exact_match,
1,
type_list);
}

View File

@ -1585,12 +1585,13 @@ LookupTypeInModule (CommandInterpreter &interpreter,
if (module && name_cstr && name_cstr[0])
{
TypeList type_list;
const uint32_t max_num_matches = 1;
const uint32_t max_num_matches = UINT32_MAX;
uint32_t num_matches = 0;
bool name_is_fully_qualified = false;
SymbolContext sc;
ConstString name(name_cstr);
num_matches = module->FindTypes(sc, name, NULL, true, max_num_matches, type_list);
num_matches = module->FindTypes(sc, name, name_is_fully_qualified, max_num_matches, type_list);
if (num_matches)
{

View File

@ -630,7 +630,7 @@ FormatManager::LoadSTLFormatters()
std_string_summary_sp);
gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"),
std_string_summary_sp);
gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char, class std::char_traits<char>, class std::allocator<char> >"),
gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
std_string_summary_sp);
@ -676,7 +676,7 @@ FormatManager::LoadLibcxxFormatters()
libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::string"),
std_string_summary_sp);
libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<char, class std::__1::char_traits<char>, class std::__1::allocator<char> >"),
libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"),
std_string_summary_sp);
SyntheticChildren::Flags stl_synth_flags;

View File

@ -632,7 +632,12 @@ Module::FindFunctions (const RegularExpression& regex,
}
uint32_t
Module::FindTypes_Impl (const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, TypeList& types)
Module::FindTypes_Impl (const SymbolContext& sc,
const ConstString &name,
const ClangNamespaceDecl *namespace_decl,
bool append,
uint32_t max_matches,
TypeList& types)
{
Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
if (sc.module_sp.get() == NULL || sc.module_sp.get() == this)
@ -644,46 +649,59 @@ Module::FindTypes_Impl (const SymbolContext& sc, const ConstString &name, const
return 0;
}
// depending on implementation details, type lookup might fail because of
// embedded spurious namespace:: prefixes. this call strips them, paying
// attention to the fact that a type might have namespace'd type names as
// arguments to templates, and those must not be stripped off
static const char*
StripTypeName(const char* name_cstr)
uint32_t
Module::FindTypesInNamespace (const SymbolContext& sc,
const ConstString &type_name,
const ClangNamespaceDecl *namespace_decl,
uint32_t max_matches,
TypeList& type_list)
{
// Protect against null c string.
if (!name_cstr)
return name_cstr;
const char* skip_namespace = strstr(name_cstr, "::");
const char* template_arg_char = strchr(name_cstr, '<');
while (skip_namespace != NULL)
{
if (template_arg_char != NULL &&
skip_namespace > template_arg_char) // but namespace'd template arguments are still good to go
break;
name_cstr = skip_namespace+2;
skip_namespace = strstr(name_cstr, "::");
}
return name_cstr;
const bool append = true;
return FindTypes_Impl(sc, type_name, namespace_decl, append, max_matches, type_list);
}
uint32_t
Module::FindTypes (const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, TypeList& types)
Module::FindTypes (const SymbolContext& sc,
const ConstString &name,
bool exact_match,
uint32_t max_matches,
TypeList& types)
{
uint32_t retval = FindTypes_Impl(sc, name, namespace_decl, append, max_matches, types);
if (retval == 0)
uint32_t num_matches = 0;
const char *type_name_cstr = name.GetCString();
std::string type_scope;
std::string type_basename;
const bool append = true;
if (Type::GetTypeScopeAndBasename (type_name_cstr, type_scope, type_basename))
{
const char *orig_name = name.GetCString();
const char *stripped = StripTypeName(orig_name);
// Only do this lookup if StripTypeName has stripped the name:
if (stripped != orig_name)
return FindTypes_Impl(sc, ConstString(stripped), namespace_decl, append, max_matches, types);
// Check if "name" starts with "::" which means the qualified type starts
// from the root namespace and implies and exact match. The typenames we
// get back from clang do not start with "::" so we need to strip this off
// in order to get the qualfied names to match
if (type_scope.size() >= 2 && type_scope[0] == ':' && type_scope[1] == ':')
{
type_scope.erase(0,2);
exact_match = true;
}
ConstString type_basename_const_str (type_basename.c_str());
if (FindTypes_Impl(sc, type_basename_const_str, NULL, append, max_matches, types))
{
types.RemoveMismatchedTypes (type_scope, type_basename, exact_match);
num_matches = types.GetSize();
}
else
return 0;
{
types.Clear();
}
}
else
return retval;
{
// The type is not in a namespace/class scope, just search for it by basename
num_matches = FindTypes_Impl(sc, name, NULL, append, max_matches, types);
}
return num_matches;
}

View File

@ -352,19 +352,16 @@ ModuleList::FindModule (const UUID &uuid)
uint32_t
ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, TypeList& types)
ModuleList::FindTypes2 (const SymbolContext& sc, const ConstString &name, bool name_is_fully_qualified, uint32_t max_matches, TypeList& types)
{
Mutex::Locker locker(m_modules_mutex);
if (!append)
types.Clear();
uint32_t total_matches = 0;
collection::const_iterator pos, end = m_modules.end();
for (pos = m_modules.begin(); pos != end; ++pos)
{
if (sc.module_sp.get() == NULL || sc.module_sp.get() == (*pos).get())
total_matches += (*pos)->FindTypes (sc, name, NULL, true, max_matches, types);
total_matches += (*pos)->FindTypes (sc, name, name_is_fully_qualified, max_matches, types);
if (total_matches >= max_matches)
break;

View File

@ -1676,6 +1676,19 @@ ValueObject::GetDeclaration (Declaration &decl)
return false;
}
ConstString
ValueObject::GetTypeName()
{
return ClangASTType::GetConstTypeName (GetClangAST(), GetClangType());
}
ConstString
ValueObject::GetQualifiedTypeName()
{
return ClangASTType::GetConstQualifiedTypeName (GetClangAST(), GetClangType());
}
LanguageType
ValueObject::GetObjectRuntimeLanguage ()
{
@ -2640,13 +2653,10 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
else
{
if (ClangASTType::GetMinimumLanguage(root->GetClangAST(),
root->GetClangType()) == eLanguageTypeObjC
&&
ClangASTContext::IsPointerType(ClangASTType::GetPointeeType(root->GetClangType())) == false
&&
root->HasSyntheticValue()
&&
options.m_no_synthetic_children == false)
root->GetClangType()) == eLanguageTypeObjC
&& ClangASTContext::IsPointerType(ClangASTType::GetPointeeType(root->GetClangType())) == false
&& root->HasSyntheticValue()
&& options.m_no_synthetic_children == false)
{
root = root->GetSyntheticValue()->GetChildAtIndex(index, true);
}
@ -3152,7 +3162,8 @@ DumpValueObject_Impl (Stream &s,
// Always show the type for the top level items.
if (options.m_show_types || (curr_depth == 0 && !options.m_flat_output))
{
const char* typeName = valobj->GetTypeName().AsCString("<invalid type>");
const char* typeName = valobj->GetQualifiedTypeName().AsCString("<invalid type>");
//const char* typeName = valobj->GetTypeName().AsCString("<invalid type>");
s.Printf("(%s", typeName);
// only show dynamic types if the user really wants to see types
if (options.m_show_types && options.m_use_dynamic != eNoDynamicValues &&

View File

@ -73,7 +73,7 @@ ValueObjectChild::GetTypeName()
{
if (m_type_name.IsEmpty())
{
m_type_name = ClangASTType::GetConstTypeName (GetClangType());
m_type_name = ClangASTType::GetConstTypeName (GetClangAST(), GetClangType());
if (m_type_name)
{
if (m_bitfield_bit_size > 0)
@ -91,6 +91,26 @@ ValueObjectChild::GetTypeName()
return m_type_name;
}
ConstString
ValueObjectChild::GetQualifiedTypeName()
{
ConstString qualified_name = ClangASTType::GetConstQualifiedTypeName (GetClangAST(), GetClangType());
if (qualified_name)
{
if (m_bitfield_bit_size > 0)
{
const char *clang_type_name = qualified_name.AsCString();
if (clang_type_name)
{
std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
qualified_name.SetCString(&bitfield_type_name.front());
}
}
}
return qualified_name;
}
bool
ValueObjectChild::UpdateValue ()
{

View File

@ -316,7 +316,7 @@ ConstString
ValueObjectConstResult::GetTypeName()
{
if (m_type_name.IsEmpty())
m_type_name = ClangASTType::GetConstTypeName (GetClangType());
m_type_name = ClangASTType::GetConstTypeName (GetClangAST(), GetClangType());
return m_type_name;
}

View File

@ -66,12 +66,6 @@ ValueObjectCast::GetClangTypeImpl ()
return m_cast_type.GetOpaqueQualType();
}
ConstString
ValueObjectCast::GetTypeName()
{
return ClangASTType::GetConstTypeName (GetClangType());
}
uint32_t
ValueObjectCast::CalculateNumChildren()
{
@ -172,7 +166,7 @@ ValueObjectDynamicValue::GetTypeName()
{
const bool success = UpdateValueIfNeeded(false);
if (success && m_type_sp)
return ClangASTType::GetConstTypeName (GetClangType());
return ClangASTType::GetConstTypeName (GetClangAST(), GetClangType());
else
return m_parent->GetTypeName();
}

View File

@ -143,7 +143,7 @@ ValueObjectMemory::GetTypeName()
{
if (m_type_sp)
return m_type_sp->GetName();
return ClangASTType::GetConstTypeName (m_clang_type.GetOpaqueQualType());
return ClangASTType::GetConstTypeName (GetClangAST(), m_clang_type.GetOpaqueQualType());
}
uint32_t

View File

@ -326,7 +326,7 @@ ConstString
ValueObjectRegister::GetTypeName()
{
if (m_type_name.IsEmpty())
m_type_name = ClangASTType::GetConstTypeName (GetClangType());
m_type_name = ClangASTType::GetConstTypeName (GetClangAST(), GetClangType());
return m_type_name;
}

View File

@ -67,8 +67,16 @@ ValueObjectVariable::GetTypeName()
Type * var_type = m_variable_sp->GetType();
if (var_type)
return var_type->GetName();
ConstString empty_type_name;
return empty_type_name;
return ConstString();
}
ConstString
ValueObjectVariable::GetQualifiedTypeName()
{
Type * var_type = m_variable_sp->GetType();
if (var_type)
return var_type->GetQualifiedName();
return ConstString();
}
uint32_t

View File

@ -206,7 +206,7 @@ ClangASTSource::CompleteType (TagDecl *tag_decl)
SymbolContext null_sc;
ConstString name(tag_decl->getName().str().c_str());
i->first->FindTypes(null_sc, name, &i->second, true, UINT32_MAX, types);
i->first->FindTypesInNamespace(null_sc, name, &i->second, UINT32_MAX, types);
for (uint32_t ti = 0, te = types.GetSize();
ti != te && !found;
@ -244,7 +244,8 @@ ClangASTSource::CompleteType (TagDecl *tag_decl)
ModuleList &module_list = m_target->GetImages();
module_list.FindTypes(null_sc, name, true, UINT32_MAX, types);
bool exact_match = false;
module_list.FindTypes2 (null_sc, name, exact_match, UINT32_MAX, types);
for (uint32_t ti = 0, te = types.GetSize();
ti != te && !found;
@ -592,11 +593,12 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
{
TypeList types;
SymbolContext null_sc;
const bool exact_match = false;
if (module_sp && namespace_decl)
module_sp->FindTypes(null_sc, name, &namespace_decl, true, 1, types);
module_sp->FindTypesInNamespace(null_sc, name, &namespace_decl, 1, types);
else
m_target->GetImages().FindTypes(null_sc, name, true, 1, types);
m_target->GetImages().FindTypes2(null_sc, name, exact_match, 1, types);
if (types.GetSize())
{

View File

@ -113,7 +113,8 @@ ClangFunction::CompileFunction (Stream &errors)
// FIXME: How does clang tell us there's no return value? We need to handle that case.
unsigned num_errors = 0;
std::string return_type_str (ClangASTType::GetTypeNameForOpaqueQualType (m_function_return_qual_type));
std::string return_type_str (ClangASTType::GetTypeNameForOpaqueQualType (m_clang_ast_context->getASTContext(),
m_function_return_qual_type));
// Cons up the function we're going to wrap our call in, then compile it...
// We declare the function "extern "C"" because the compiler might be in C++
@ -159,7 +160,8 @@ ClangFunction::CompileFunction (Stream &errors)
if (trust_function)
{
lldb::clang_type_t arg_clang_type = m_function_ptr->GetArgumentTypeAtIndex(i);
type_name = ClangASTType::GetTypeNameForOpaqueQualType (arg_clang_type);
type_name = ClangASTType::GetTypeNameForOpaqueQualType (m_clang_ast_context->getASTContext(),
arg_clang_type);
}
else
{
@ -167,7 +169,8 @@ ClangFunction::CompileFunction (Stream &errors)
lldb::clang_type_t clang_qual_type = arg_value->GetClangType ();
if (clang_qual_type != NULL)
{
type_name = ClangASTType::GetTypeNameForOpaqueQualType (clang_qual_type);
type_name = ClangASTType::GetTypeNameForOpaqueQualType (m_clang_ast_context->getASTContext(),
clang_qual_type);
}
else
{

View File

@ -57,9 +57,6 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
// Only a pointer or reference type can have a different dynamic and static type:
if (CouldHaveDynamicValue (in_value))
{
// FIXME: Can we get the Clang Type and ask it if the thing is really virtual? That would avoid false positives,
// at the cost of not looking for the dynamic type of objects if DWARF->Clang gets it wrong.
// First job, pull out the address at 0 offset from the object.
AddressType address_type;
lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
@ -107,52 +104,76 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
const char *name = symbol->GetMangled().GetDemangledName().AsCString();
if (strstr(name, vtable_demangled_prefix) == name)
{
printf ("0x%16.16llx: static-type = '%s' has vtable symbol '%s'\n",
original_ptr,
in_value.GetTypeName().GetCString(),
name);
// We are a C++ class, that's good. Get the class name and look it up:
const char *class_name = name + strlen(vtable_demangled_prefix);
class_type_or_name.SetName (class_name);
const bool exact_match = true;
TypeList class_types;
uint32_t num_matches = target->GetImages().FindTypes (sc,
ConstString(class_name),
true,
UINT32_MAX,
class_types);
uint32_t num_matches = target->GetImages().FindTypes2 (sc,
ConstString(class_name),
exact_match,
UINT32_MAX,
class_types);
if (num_matches == 0)
{
printf ("0x%16.16llx: is not dynamic\n", original_ptr);
return false;
}
if (num_matches == 1)
{
lldb::TypeSP type_sp(class_types.GetTypeAtIndex(0));
printf ("0x%16.16llx: static-type = '%s' has single matching dynamic type: uid={0x%llx}, type-name='%s'\n",
original_ptr,
in_value.GetTypeName().AsCString(),
type_sp->GetID(),
type_sp->GetName().GetCString());
class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0));
}
else if (num_matches > 1)
{
for (size_t i = 0; i < num_matches; i++)
{
lldb::TypeSP this_type(class_types.GetTypeAtIndex(i));
if (this_type)
lldb::TypeSP type_sp(class_types.GetTypeAtIndex(i));
if (type_sp)
{
if (ClangASTContext::IsCXXClassType(this_type->GetClangFullType()))
{
// There can only be one type with a given name,
// so we've just found duplicate definitions, and this
// one will do as well as any other.
// We don't consider something to have a dynamic type if
// it is the same as the static type. So compare against
// the value we were handed:
clang::ASTContext *in_ast_ctx = in_value.GetClangAST ();
clang::ASTContext *this_ast_ctx = this_type->GetClangAST ();
if (in_ast_ctx != this_ast_ctx
|| !ClangASTContext::AreTypesSame (in_ast_ctx,
in_value.GetClangType(),
this_type->GetClangFullType()))
{
class_type_or_name.SetTypeSP (this_type);
return true;
}
return false;
}
printf ("0x%16.16llx: static-type = '%s' has multiple matching dynamic types: uid={0x%llx}, type-name='%s'\n",
original_ptr,
in_value.GetTypeName().AsCString(),
type_sp->GetID(),
type_sp->GetName().GetCString());
// if (ClangASTContext::IsCXXClassType(type_sp->GetClangFullType()))
// {
// // There can only be one type with a given name,
// // so we've just found duplicate definitions, and this
// // one will do as well as any other.
// // We don't consider something to have a dynamic type if
// // it is the same as the static type. So compare against
// // the value we were handed:
//
// clang::ASTContext *in_ast_ctx = in_value.GetClangAST ();
// clang::ASTContext *this_ast_ctx = type_sp->GetClangAST ();
// if (in_ast_ctx != this_ast_ctx
// || !ClangASTContext::AreTypesSame (in_ast_ctx,
// in_value.GetClangType(),
// type_sp->GetClangFullType()))
// {
// class_type_or_name.SetTypeSP (this_type);
// return true;
// }
// return false;
// }
}
}
}
else
return false;
}
// The offset_to_top is two pointers above the address.
Address offset_to_top_address = address_point_address;
@ -187,7 +208,6 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
}
}
}
}
return false;

View File

@ -349,9 +349,10 @@ AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value,
TypeList class_types;
SymbolContext sc;
uint32_t num_matches = target.GetImages().FindTypes (sc,
const bool exact_match = true;
uint32_t num_matches = target.GetImages().FindTypes2 (sc,
class_type_or_name.GetName(),
true,
exact_match,
UINT32_MAX,
class_types);
if (num_matches == 1)

View File

@ -476,12 +476,6 @@ PlatformDarwin::LaunchProcess (ProcessLaunchInfo &launch_info)
if (IsHost())
{
if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell))
{
const bool is_localhost = true;
if (!launch_info.ConvertArgumentsForLaunchingInShell (error, is_localhost))
return error;
}
error = Platform::LaunchProcess (launch_info);
}
else

View File

@ -1991,7 +1991,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (lldb::clang_type_t clang_type
if (class_language == eLanguageTypeObjC)
{
std::string class_str (ClangASTType::GetTypeNameForOpaqueQualType(clang_type));
std::string class_str (ClangASTType::GetTypeNameForOpaqueQualType(ast.getASTContext(), clang_type));
if (!class_str.empty())
{

View File

@ -1038,10 +1038,10 @@ ClangASTContext::CopyDecl (ASTContext *dst_ast,
}
bool
ClangASTContext::AreTypesSame(ASTContext *ast,
clang_type_t type1,
clang_type_t type2,
bool ignore_qualifiers)
ClangASTContext::AreTypesSame (ASTContext *ast,
clang_type_t type1,
clang_type_t type2,
bool ignore_qualifiers)
{
QualType type1_qual = QualType::getFromOpaquePtr(type1);
QualType type2_qual = QualType::getFromOpaquePtr(type2);
@ -3797,7 +3797,7 @@ ClangASTContext::GetChildClangTypeAtIndex
// Base classes should be a multiple of 8 bits in size
child_byte_offset = bit_offset/8;
child_name = ClangASTType::GetTypeNameForQualType(base_class->getType());
child_name = ClangASTType::GetTypeNameForQualType(ast, base_class->getType());
uint64_t clang_type_info_bit_size = ast->getTypeSize(base_class->getType());
@ -4662,7 +4662,7 @@ ClangASTContext::GetIndexOfChildWithName
if (omit_empty_base_classes && RecordHasFields(base_class_decl) == false)
continue;
std::string base_class_type_name (ClangASTType::GetTypeNameForQualType(base_class->getType()));
std::string base_class_type_name (ClangASTType::GetTypeNameForQualType(ast, base_class->getType()));
if (base_class_type_name.compare (name) == 0)
return child_idx;
++child_idx;

View File

@ -47,87 +47,64 @@ ClangASTType::~ClangASTType()
}
std::string
ClangASTType::GetTypeNameForQualType (clang::QualType qual_type)
ClangASTType::GetTypeNameForQualType (clang::ASTContext *ast, clang::QualType qual_type)
{
std::string type_name;
clang::PrintingPolicy printing_policy (ast->getPrintingPolicy());
printing_policy.SuppressTagKeyword = true;
const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
if (typedef_type)
{
const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
type_name = typedef_decl->getQualifiedNameAsString();
type_name = typedef_decl->getQualifiedNameAsString(printing_policy);
}
else
{
type_name = qual_type.getAsString();
type_name = qual_type.getAsString(printing_policy);
}
// There is no call to a clang type to get the type name without the
// class/struct/union/enum on the front, so lets strip it here
const char *type_name_cstr = type_name.c_str();
if (type_name_cstr[0] == 'c' &&
type_name_cstr[1] == 'l' &&
type_name_cstr[2] == 'a' &&
type_name_cstr[3] == 's' &&
type_name_cstr[4] == 's' &&
type_name_cstr[5] == ' ')
{
type_name.erase (0, 6);
}
else if (type_name_cstr[0] == 's' &&
type_name_cstr[1] == 't' &&
type_name_cstr[2] == 'r' &&
type_name_cstr[3] == 'u' &&
type_name_cstr[4] == 'c' &&
type_name_cstr[5] == 't' &&
type_name_cstr[6] == ' ')
{
type_name.erase (0, 7);
}
else if (type_name_cstr[0] == 'u' &&
type_name_cstr[1] == 'n' &&
type_name_cstr[2] == 'i' &&
type_name_cstr[3] == 'o' &&
type_name_cstr[4] == 'n' &&
type_name_cstr[5] == ' ')
{
type_name.erase (0, 6);
}
else if (type_name_cstr[0] == 'e' &&
type_name_cstr[1] == 'n' &&
type_name_cstr[2] == 'u' &&
type_name_cstr[3] == 'm' &&
type_name_cstr[4] == ' ')
{
type_name.erase (0, 5);
}
return type_name;
}
std::string
ClangASTType::GetTypeNameForOpaqueQualType (clang_type_t opaque_qual_type)
ClangASTType::GetTypeNameForOpaqueQualType (clang::ASTContext *ast, clang_type_t opaque_qual_type)
{
return GetTypeNameForQualType (clang::QualType::getFromOpaquePtr(opaque_qual_type));
return GetTypeNameForQualType (ast, clang::QualType::getFromOpaquePtr(opaque_qual_type));
}
ConstString
ClangASTType::GetConstTypeName ()
{
// TODO: verify if we actually need to complete a type just to get its type name????
if (!ClangASTContext::GetCompleteType (this->m_ast, this->m_type))
return ConstString("<invalid>");
return GetConstTypeName (m_type);
return GetConstTypeName (m_ast, m_type);
}
ConstString
ClangASTType::GetConstTypeName (clang_type_t clang_type)
ClangASTType::GetConstQualifiedTypeName ()
{
// TODO: verify if we actually need to complete a type just to get its fully qualified type name????
if (!ClangASTContext::GetCompleteType (this->m_ast, this->m_type))
return ConstString("<invalid>");
return GetConstQualifiedTypeName (m_ast, m_type);
}
ConstString
ClangASTType::GetConstQualifiedTypeName (clang::ASTContext *ast, clang_type_t opaque_qual_type)
{
return ConstString (GetTypeNameForQualType (ast, clang::QualType::getFromOpaquePtr(opaque_qual_type)).c_str());
}
ConstString
ClangASTType::GetConstTypeName (clang::ASTContext *ast, clang_type_t clang_type)
{
if (!clang_type)
return ConstString("<invalid>");
clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
std::string type_name (GetTypeNameForQualType (qual_type));
std::string type_name (GetTypeNameForOpaqueQualType(ast, clang_type));
ConstString const_type_name;
if (type_name.empty())
const_type_name.SetCString ("<invalid>");

View File

@ -120,8 +120,19 @@ Type::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_name)
*s << "id = " << (const UserID&)*this;
// Call the name accessor to make sure we resolve the type name
if (show_name && GetName())
*s << ", name = \"" << m_name << '"';
if (show_name)
{
const ConstString &type_name = GetName();
if (type_name)
{
*s << ", name = \"" << type_name << '"';
ConstString qualified_type_name (GetQualifiedName());
if (qualified_type_name != type_name)
{
*s << ", qualified = \"" << qualified_type_name << '"';
}
}
}
// Call the get byte size accesor so we resolve our byte size
if (GetByteSize())
@ -213,7 +224,7 @@ Type::GetName()
if (!m_name)
{
if (ResolveClangType(eResolveStateForward))
m_name = ClangASTType::GetConstTypeName (m_clang_type);
m_name = ClangASTType::GetConstTypeName (GetClangASTContext ().getASTContext(), m_clang_type);
}
return m_name;
}
@ -693,6 +704,49 @@ Type::IsRealObjCClass()
return false;
}
ConstString
Type::GetQualifiedName ()
{
ConstString qualified_name (ClangASTType::GetTypeNameForOpaqueQualType (GetClangASTContext ().getASTContext(), GetClangForwardType()).c_str());
return qualified_name;
}
bool
Type::GetTypeScopeAndBasename (const char* name_cstr,
std::string &scope,
std::string &basename)
{
// Protect against null c string.
if (name_cstr && name_cstr[0])
{
const char *basename_cstr = name_cstr;
const char* namespace_separator = ::strstr (basename_cstr, "::");
if (namespace_separator)
{
const char* template_arg_char = ::strchr (basename_cstr, '<');
while (namespace_separator != NULL)
{
if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go
break;
basename_cstr = namespace_separator + 2;
namespace_separator = strstr(basename_cstr, "::");
}
if (basename_cstr > name_cstr)
{
scope.assign (name_cstr, basename_cstr - name_cstr);
basename.assign (basename_cstr);
return true;
}
}
}
return false;
}
TypeAndOrName::TypeAndOrName () : m_type_sp(), m_type_name()
{

View File

@ -135,6 +135,20 @@ TypeList::GetTypeAtIndex(uint32_t idx)
return TypeSP();
}
bool
TypeList::RemoveTypeWithUID (user_id_t uid)
{
iterator pos = m_types.find(uid);
if (pos != m_types.end())
{
m_types.erase(pos);
return true;
}
return false;
}
void
TypeList::Dump(Stream *s, bool show_context)
{
@ -144,6 +158,147 @@ TypeList::Dump(Stream *s, bool show_context)
}
}
// depending on implementation details, type lookup might fail because of
// embedded spurious namespace:: prefixes. this call strips them, paying
// attention to the fact that a type might have namespace'd type names as
// arguments to templates, and those must not be stripped off
static bool
GetTypeScopeAndBasename(const char* name_cstr, std::string &scope, std::string &basename, bool *exact_ptr)
{
// Protect against null c string.
if (name_cstr && name_cstr[0])
{
const char *basename_cstr = name_cstr;
const char* namespace_separator = ::strstr (basename_cstr, "::");
if (namespace_separator)
{
const char* template_arg_char = ::strchr (basename_cstr, '<');
while (namespace_separator != NULL)
{
if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go
break;
basename_cstr = namespace_separator + 2;
namespace_separator = strstr(basename_cstr, "::");
}
if (basename_cstr > name_cstr)
{
scope.assign (name_cstr, basename_cstr - name_cstr);
if (scope.size() >= 2 && scope[0] == ':' && scope[1] == ':')
{
// The typename passed in started with "::" so make sure we only do exact matches
if (exact_ptr)
*exact_ptr = true;
// Strip the leading "::" as this won't ever show in qualified typenames we get
// from clang.
scope.erase(0,2);
}
basename.assign (basename_cstr);
return true;
}
}
}
return false;
}
void
TypeList::RemoveMismatchedTypes (const char *qualified_typename,
bool exact_match)
{
std::string type_scope;
std::string type_basename;
if (!Type::GetTypeScopeAndBasename (qualified_typename, type_scope, type_basename))
{
type_basename = qualified_typename;
type_scope.clear();
}
return RemoveMismatchedTypes (type_scope, type_basename, exact_match);
}
void
TypeList::RemoveMismatchedTypes (const std::string &type_scope,
const std::string &type_basename,
bool exact_match)
{
// Our "collection" type currently is a std::map which doesn't
// have any good way to iterate and remove items from the map
// so we currently just make a new list and add all of the matching
// types to it, and then swap it into m_types at the end
collection matching_types;
iterator pos, end = m_types.end();
for (pos = m_types.begin(); pos != end; ++pos)
{
Type* the_type = pos->second.get();
bool keep_match = false;
ConstString match_type_name_const_str (the_type->GetQualifiedName());
if (match_type_name_const_str)
{
const char *match_type_name = match_type_name_const_str.GetCString();
std::string match_type_scope;
std::string match_type_basename;
if (Type::GetTypeScopeAndBasename (match_type_name,
match_type_scope,
match_type_basename))
{
if (match_type_basename == type_basename)
{
const size_t type_scope_size = type_scope.size();
const size_t match_type_scope_size = match_type_scope.size();
if (exact_match || (type_scope_size == match_type_scope_size))
{
keep_match = match_type_scope == type_scope;
}
else
{
if (match_type_scope_size > type_scope_size)
{
const size_t type_scope_pos = match_type_scope.rfind(type_scope);
if (type_scope_pos == match_type_scope_size - type_scope_size)
{
if (type_scope_pos >= 2)
{
// Our match scope ends with the type scope we were lookikng for,
// but we need to make sure what comes before the matching
// type scope is a namepace boundary in case we are trying to match:
// type_basename = "d"
// type_scope = "b::c::"
// We want to match:
// match_type_scope "a::b::c::"
// But not:
// match_type_scope "a::bb::c::"
// So below we make sure what comes before "b::c::" in match_type_scope
// is "::", or the namespace boundary
if (match_type_scope[type_scope_pos - 1] == ':' &&
match_type_scope[type_scope_pos - 2] == ':')
{
keep_match = true;
}
}
}
}
}
}
}
else
{
// The type we are currently looking at doesn't exists
// in a namespace or class, so it only matches if there
// is no type scope...
keep_match = type_scope.empty() && type_basename.compare(match_type_name) == 0;
}
}
if (keep_match)
{
matching_types.insert (*pos);
}
}
m_types.swap(matching_types);
}
//void *
//TypeList::CreateClangPointerType (Type *type)
//{

View File

@ -23,11 +23,9 @@ public:
{
m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("basic_string<char>"));
m_impl.Append(ConstString("class std::basic_string<char, class std::char_traits<char>, class std::allocator<char> >").AsCString(), ConstString("basic_string<char>"));
// these two (with a prefixed std::) occur when c++stdlib string class occurs as a template argument in some STL container
m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("std::basic_string<char>"));
m_impl.Append(ConstString("class std::basic_string<char, class std::char_traits<char>, class std::allocator<char> >").AsCString(), ConstString("std::asic_string<char>"));
m_impl.Sort();
}

View File

@ -130,17 +130,15 @@ ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
return TypeSP();
const SymbolContext null_sc;
const ClangNamespaceDecl *null_namespace_decl = NULL;
const bool append = false;
const bool exact_match = true;
const uint32_t max_matches = UINT32_MAX;
TypeList types;
module_sp->FindTypes(null_sc,
name,
null_namespace_decl,
append,
max_matches,
types);
module_sp->FindTypes (null_sc,
name,
exact_match,
max_matches,
types);
if (types.GetSize() == 1)
{

View File

@ -567,7 +567,19 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
// Take care of the host case so that each subclass can just
// call this function to get the host functionality.
if (IsHost())
{
if (::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY"))
launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY);
if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell))
{
const bool is_localhost = true;
if (!launch_info.ConvertArgumentsForLaunchingInShell (error, is_localhost))
return error;
}
error = Host::LaunchProcess (launch_info);
}
else
error.SetErrorString ("base lldb_private::Platform class can't launch remote processes");
return error;

View File

@ -58,7 +58,7 @@ class LibcxxMapDataFormatterTestCase(TestBase):
self.runCmd("frame variable ii -T")
self.runCmd("type summary add -x \"std::map<\" --summary-string \"map has ${svar%#} items\" -e")
self.runCmd("type summary add -x \"std::__1::map<\" --summary-string \"map has ${svar%#} items\" -e")
self.expect('frame variable ii',
substrs = ['map has 0 items',
@ -135,9 +135,6 @@ class LibcxxMapDataFormatterTestCase(TestBase):
self.runCmd("n")
self.runCmd("frame variable si -T")
#self.runCmd("type summary add std::strint_map strint_map --summary-string \"map has ${svar%#} items\" -e")
#self.runCmd("type synth add std::strint_map strint_map -l StdMapSynthProvider")
self.expect('frame variable si',
substrs = ['map has 0 items',
'{}'])
@ -210,9 +207,6 @@ class LibcxxMapDataFormatterTestCase(TestBase):
self.runCmd("n")
self.runCmd("frame variable is -T")
#self.runCmd("type summary add std::intstr_map intstr_map --summary-string \"map has ${svar%#} items\" -e")
#self.runCmd("type synth add std::intstr_map intstr_map -l StdMapSynthProvider")
self.expect('frame variable is',
substrs = ['map has 0 items',
'{}'])

View File

@ -135,9 +135,6 @@ class StdMapDataFormatterTestCase(TestBase):
self.runCmd("n")
self.runCmd("frame variable si -T")
#self.runCmd("type summary add std::strint_map strint_map --summary-string \"map has ${svar%#} items\" -e")
#self.runCmd("type synth add std::strint_map strint_map -l StdMapSynthProvider")
self.expect('frame variable si',
substrs = ['map has 0 items',
'{}'])
@ -210,9 +207,6 @@ class StdMapDataFormatterTestCase(TestBase):
self.runCmd("n")
self.runCmd("frame variable is -T")
#self.runCmd("type summary add std::intstr_map intstr_map --summary-string \"map has ${svar%#} items\" -e")
#self.runCmd("type synth add std::intstr_map intstr_map -l StdMapSynthProvider")
self.expect('frame variable is',
substrs = ['map has 0 items',
'{}'])

View File

@ -99,12 +99,12 @@ class SetValuesTestCase(TestBase):
# main.c:57
# Check that 'frame variable -T' displays the correct data type and value.
self.expect("frame variable -T", VARIABLES_DISPLAYED_CORRECTLY,
startstr = "(long int) i = 33")
startstr = "(long) i = 33")
# Now set variable 'i' and check that it is correctly displayed.
self.runCmd("expression i = 33333")
self.expect("frame variable -T", VARIABLES_DISPLAYED_CORRECTLY,
startstr = "(long int) i = 33333")
startstr = "(long) i = 33333")
self.runCmd("continue")

View File

@ -58,8 +58,8 @@ class UnsignedTypesTestCase(TestBase):
patterns = ["\((short int|short)\) the_signed_short = 99"],
substrs = ["(signed char) the_signed_char = 'c'",
"(int) the_signed_int = 99",
"(long int) the_signed_long = 99",
"(long long int) the_signed_long_long = 99"])
"(long) the_signed_long = 99",
"(long long) the_signed_long_long = 99"])
if __name__ == '__main__':

View File

@ -55,8 +55,8 @@ class UnsignedTypesTestCase(TestBase):
startstr = "(unsigned char) the_unsigned_char = 'c'",
patterns = ["\((short unsigned int|unsigned short)\) the_unsigned_short = 99"],
substrs = ["(unsigned int) the_unsigned_int = 99",
"(long unsigned int) the_unsigned_long = 99",
"(long long unsigned int) the_unsigned_long_long = 99",
"(unsigned long) the_unsigned_long = 99",
"(unsigned long long) the_unsigned_long_long = 99",
"(uint32_t) the_uint32 = 99"])