<rdar://problem/13506727>

Symbol table function names should support lookups like symbols with debug info. 

To fix this I:
- Gutted the way FindFunctions is used, there used to be way too much smarts only in the DWARF plug-in
- Made it more efficient by chopping the name up once and using simpler queries so that SymbolFile and Symtab plug-ins don't need to do as much
- Filter the results at a higher level
- Make the lldb_private::Symtab able to chop up C++ mangled names and make as much sense out of them as possible and also be able to search by basename, fullname, method name, and selector name.

llvm-svn: 178608
This commit is contained in:
Greg Clayton 2013-04-03 02:00:15 +00:00
parent 1786cb2f01
commit 43fe217b11
14 changed files with 956 additions and 273 deletions

View File

@ -86,13 +86,33 @@ public:
}
protected:
std::vector<ConstString> m_func_names;
uint32_t m_func_name_type_mask; // See FunctionNameType
ConstString m_class_name; // FIXME: Not used yet. The idea would be to stop on methods of this class.
struct LookupInfo
{
ConstString name;
ConstString lookup_name;
uint32_t name_type_mask; // See FunctionNameType
bool match_name_after_lookup;
LookupInfo () :
name(),
lookup_name(),
name_type_mask (0),
match_name_after_lookup (false)
{
}
void
Prune (SymbolContextList &sc_list,
size_t start_idx) const;
};
std::vector<LookupInfo> m_lookups;
ConstString m_class_name;
RegularExpression m_regex;
Breakpoint::MatchType m_match_type;
bool m_skip_prologue;
void
AddNameLookup (const ConstString &name, uint32_t name_type_mask);
private:
DISALLOW_COPY_AND_ASSIGN(BreakpointResolverName);
};

View File

@ -882,6 +882,56 @@ public:
bool
RemapSourceFile (const char *path, std::string &new_path) const;
//------------------------------------------------------------------
/// Prepare to do a function name lookup.
///
/// Looking up functions by name can be a tricky thing. LLDB requires
/// that accelerator tables contain full names for functions as well
/// as function basenames which include functions, class methods and
/// class functions. When the user requests that an action use a
/// function by name, we are sometimes asked to automatically figure
/// out what a name could possibly map to. A user might request a
/// breakpoint be set on "count". If no options are supplied to limit
/// the scope of where to search for count, we will by default match
/// any function names named "count", all class and instance methods
/// named "count" (no matter what the namespace or contained context)
/// and any selectors named "count". If a user specifies "a::b" we
/// will search for the basename "b", and then prune the results that
/// don't match "a::b" (note that "c::a::b" and "d::e::a::b" will
/// match a query of "a::b".
///
/// @param[in] name
/// The user supplied name to use in the lookup
///
/// @param[in] name_type_mask
/// The mask of bits from lldb::FunctionNameType enumerations
/// that tell us what kind of name we are looking for.
///
/// @param[out] lookup_name
/// The actual name that will be used when calling
/// SymbolVendor::FindFunctions() or Symtab::FindFunctionSymbols()
///
/// @param[out] lookup_name_type_mask
/// The actual name mask that should be used in the calls to
/// SymbolVendor::FindFunctions() or Symtab::FindFunctionSymbols()
///
/// @param[out] match_name_after_lookup
/// A boolean that indicates if we need to iterate through any
/// match results obtained from SymbolVendor::FindFunctions() or
/// Symtab::FindFunctionSymbols() to see if the name contains
/// \a name. For example if \a name is "a::b", this function will
/// return a \a lookup_name of "b", with \a match_name_after_lookup
/// set to true to indicate any matches will need to be checked
/// to make sure they contain \a name.
//------------------------------------------------------------------
static void
PrepareForFunctionNameLookup (const ConstString &name,
uint32_t name_type_mask,
ConstString &lookup_name,
uint32_t &lookup_name_type_mask,
bool &match_name_after_lookup);
protected:
//------------------------------------------------------------------
// Member Variables

View File

@ -461,6 +461,19 @@ public:
bool
GetContextAtIndex(size_t idx, SymbolContext& sc) const;
//------------------------------------------------------------------
/// Get accessor for the last symbol context in the list.
///
/// @param[out] sc
/// A reference to the symbol context to fill in.
///
/// @return
/// Returns \b true if \a sc was filled in, \b false if the
/// list is empty.
//------------------------------------------------------------------
bool
GetLastContext(SymbolContext& sc) const;
bool
RemoveContextAtIndex (size_t idx);
//------------------------------------------------------------------

View File

@ -107,6 +107,8 @@ protected:
collection m_symbols;
std::vector<uint32_t> m_addr_indexes;
UniqueCStringMap<uint32_t> m_name_to_index;
UniqueCStringMap<uint32_t> m_basename_to_index;
UniqueCStringMap<uint32_t> m_method_to_index;
UniqueCStringMap<uint32_t> m_selector_to_index;
mutable Mutex m_mutex; // Provide thread safety for this symbol table
bool m_addr_indexes_computed:1,

View File

@ -25,6 +25,93 @@ class CPPLanguageRuntime :
public LanguageRuntime
{
public:
class MethodName
{
public:
enum Type
{
eTypeInvalid,
eTypeUnknownMethod,
eTypeClassMethod,
eTypeInstanceMethod
};
MethodName () :
m_full(),
m_basename(),
m_context(),
m_arguments(),
m_qualifiers(),
m_type (eTypeInvalid),
m_parsed (false),
m_parse_error (false)
{
}
MethodName (const ConstString &s) :
m_full(s),
m_basename(),
m_context(),
m_arguments(),
m_qualifiers(),
m_type (eTypeInvalid),
m_parsed (false),
m_parse_error (false)
{
}
void
Clear();
bool
IsValid () const
{
if (m_parse_error)
return false;
if (m_type == eTypeInvalid)
return false;
return (bool)m_full;
}
Type
GetType () const
{
return m_type;
}
const ConstString &
GetFullName () const
{
return m_full;
}
const ConstString &
GetBasename ();
llvm::StringRef
GetContext ();
llvm::StringRef
GetArguments ();
llvm::StringRef
GetQualifiers ();
protected:
void
Parse();
ConstString m_full; // Full name: "lldb::SBTarget::GetBreakpointAtIndex(unsigned int) const"
ConstString m_basename; // Basename: "GetBreakpointAtIndex"
llvm::StringRef m_context; // Decl context: "lldb::SBTarget"
llvm::StringRef m_arguments; // Arguments: "(unsigned int)"
llvm::StringRef m_qualifiers; // Qualifiers: "const"
Type m_type;
bool m_parsed;
bool m_parse_error;
};
virtual
~CPPLanguageRuntime();

View File

@ -27,16 +27,12 @@
using namespace lldb;
using namespace lldb_private;
BreakpointResolverName::BreakpointResolverName
(
Breakpoint *bkpt,
const char *func_name,
uint32_t func_name_type_mask,
Breakpoint::MatchType type,
bool skip_prologue
) :
BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
const char *name_cstr,
uint32_t name_type_mask,
Breakpoint::MatchType type,
bool skip_prologue) :
BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
m_func_name_type_mask (func_name_type_mask),
m_class_name (),
m_regex (),
m_match_type (type),
@ -45,22 +41,17 @@ BreakpointResolverName::BreakpointResolverName
if (m_match_type == Breakpoint::Regexp)
{
if (!m_regex.Compile (func_name))
if (!m_regex.Compile (name_cstr))
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Warning ("function name regexp: \"%s\" did not compile.", func_name);
log->Warning ("function name regexp: \"%s\" did not compile.", name_cstr);
}
}
else
{
const bool append = true;
ObjCLanguageRuntime::MethodName objc_name(func_name, false);
if (objc_name.IsValid(false))
objc_name.GetFullNames(m_func_names, append);
else
m_func_names.push_back(ConstString(func_name));
AddNameLookup (ConstString(name_cstr), name_type_mask);
}
}
@ -70,18 +61,12 @@ BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
uint32_t name_type_mask,
bool skip_prologue) :
BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
m_func_name_type_mask (name_type_mask),
m_match_type (Breakpoint::Exact),
m_skip_prologue (skip_prologue)
{
const bool append = true;
for (size_t i = 0; i < num_names; i++)
{
ObjCLanguageRuntime::MethodName objc_name(names[i], false);
if (objc_name.IsValid(false))
objc_name.GetFullNames(m_func_names, append);
else
m_func_names.push_back (ConstString (names[i]));
AddNameLookup (ConstString (names[i]), name_type_mask);
}
}
@ -90,28 +75,18 @@ BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
uint32_t name_type_mask,
bool skip_prologue) :
BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
m_func_name_type_mask (name_type_mask),
m_match_type (Breakpoint::Exact),
m_skip_prologue (skip_prologue)
{
size_t num_names = names.size();
const bool append = true;
for (size_t i = 0; i < num_names; i++)
for (const std::string& name : names)
{
ObjCLanguageRuntime::MethodName objc_name(names[i].c_str(), false);
if (objc_name.IsValid(false))
objc_name.GetFullNames(m_func_names, append);
else
m_func_names.push_back (ConstString (names[i].c_str()));
AddNameLookup (ConstString (name.c_str(), name.size()), name_type_mask);
}
}
BreakpointResolverName::BreakpointResolverName
(
Breakpoint *bkpt,
RegularExpression &func_regex,
bool skip_prologue
) :
BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
RegularExpression &func_regex,
bool skip_prologue) :
BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
m_class_name (NULL),
m_regex (func_regex),
@ -134,13 +109,71 @@ BreakpointResolverName::BreakpointResolverName
m_match_type (type),
m_skip_prologue (skip_prologue)
{
m_func_names.push_back(ConstString(method));
LookupInfo lookup;
lookup.name.SetCString(method);
lookup.lookup_name = lookup.name;
lookup.name_type_mask = eFunctionNameTypeMethod;
lookup.match_name_after_lookup = false;
m_lookups.push_back (lookup);
}
BreakpointResolverName::~BreakpointResolverName ()
{
}
void
BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask)
{
ObjCLanguageRuntime::MethodName objc_method(name.GetCString(), false);
if (objc_method.IsValid(false))
{
std::vector<ConstString> objc_names;
objc_method.GetFullNames(objc_names, true);
for (ConstString objc_name : objc_names)
{
LookupInfo lookup;
lookup.name = name;
lookup.lookup_name = objc_name;
lookup.name_type_mask = eFunctionNameTypeFull;
lookup.match_name_after_lookup = false;
m_lookups.push_back (lookup);
}
}
else
{
LookupInfo lookup;
lookup.name = name;
Module::PrepareForFunctionNameLookup(lookup.name, name_type_mask, lookup.lookup_name, lookup.name_type_mask, lookup.match_name_after_lookup);
m_lookups.push_back (lookup);
}
}
void
BreakpointResolverName::LookupInfo::Prune (SymbolContextList &sc_list, size_t start_idx) const
{
if (match_name_after_lookup && name)
{
SymbolContext sc;
size_t i = start_idx;
while (i < sc_list.GetSize())
{
if (!sc_list.GetContextAtIndex(i, sc))
break;
ConstString full_name (sc.GetFunctionName());
if (full_name && ::strstr(full_name.GetCString(), name.GetCString()) == NULL)
{
sc_list.RemoveContextAtIndex(i);
}
else
{
++i;
}
}
}
}
// FIXME: Right now we look at the module level, and call the module's "FindFunctions".
// Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
// lookup. At that point, we should switch the depth to CompileUnit, and look in these tables.
@ -159,7 +192,6 @@ BreakpointResolverName::SearchCallback
uint32_t i;
bool new_location;
SymbolContext sc;
Address break_addr;
assert (m_breakpoint != NULL);
@ -182,22 +214,29 @@ BreakpointResolverName::SearchCallback
case Breakpoint::Exact:
if (context.module_sp)
{
size_t num_names = m_func_names.size();
for (int j = 0; j < num_names; j++)
for (const LookupInfo &lookup : m_lookups)
{
size_t num_functions = context.module_sp->FindFunctions (m_func_names[j],
NULL,
m_func_name_type_mask,
include_symbols,
include_inlines,
append,
func_list);
const size_t start_func_idx = func_list.GetSize();
context.module_sp->FindFunctions (lookup.lookup_name,
NULL,
lookup.name_type_mask,
include_symbols,
include_inlines,
append,
func_list);
const size_t end_func_idx = func_list.GetSize();
if (start_func_idx < end_func_idx)
lookup.Prune (func_list, start_func_idx);
// If the search filter specifies a Compilation Unit, then we don't need to bother to look in plain
// symbols, since all the ones from a set compilation unit will have been found above already.
if (num_functions == 0 && !filter_by_cu)
else if (!filter_by_cu)
{
context.module_sp->FindFunctionSymbols (m_func_names[j], m_func_name_type_mask, sym_list);
const size_t start_symbol_idx = sym_list.GetSize();
context.module_sp->FindFunctionSymbols (lookup.lookup_name, lookup.name_type_mask, sym_list);
const size_t end_symbol_idx = sym_list.GetSize();
if (start_symbol_idx < end_symbol_idx)
lookup.Prune (func_list, start_symbol_idx);
}
}
}
@ -239,6 +278,7 @@ BreakpointResolverName::SearchCallback
}
// Remove any duplicates between the funcion list and the symbol list
SymbolContext sc;
if (func_list.GetSize())
{
for (i = 0; i < func_list.GetSize(); i++)
@ -356,17 +396,17 @@ BreakpointResolverName::GetDescription (Stream *s)
s->Printf("regex = '%s'", m_regex.GetText());
else
{
size_t num_names = m_func_names.size();
size_t num_names = m_lookups.size();
if (num_names == 1)
s->Printf("name = '%s'", m_func_names[0].AsCString());
s->Printf("name = '%s'", m_lookups[0].name.GetCString());
else
{
s->Printf("names = {");
for (size_t i = 0; i < num_names - 1; i++)
{
s->Printf ("'%s', ", m_func_names[i].AsCString());
s->Printf ("'%s', ", m_lookups[i].name.GetCString());
}
s->Printf ("'%s'}", m_func_names[num_names - 1].AsCString());
s->Printf ("'%s'}", m_lookups[num_names - 1].name.GetCString());
}
}
}

View File

@ -29,6 +29,8 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@ -589,42 +591,83 @@ Module::FindFunctions (const ConstString &name,
if (!append)
sc_list.Clear();
const size_t start_size = sc_list.GetSize();
const size_t old_size = sc_list.GetSize();
// Find all the functions (not symbols, but debug information functions...
SymbolVendor *symbols = GetSymbolVendor ();
if (symbols)
symbols->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, append, sc_list);
// Now check our symbol table for symbols that are code symbols if requested
if (include_symbols)
if (name_type_mask & eFunctionNameTypeAuto)
{
ObjectFile *objfile = GetObjectFile();
if (objfile)
ConstString lookup_name;
uint32_t lookup_name_type_mask = 0;
bool match_name_after_lookup = false;
Module::PrepareForFunctionNameLookup (name,
name_type_mask,
lookup_name,
lookup_name_type_mask,
match_name_after_lookup);
if (symbols)
symbols->FindFunctions(lookup_name,
namespace_decl,
lookup_name_type_mask,
include_inlines,
append,
sc_list);
// Now check our symbol table for symbols that are code symbols if requested
if (include_symbols)
{
Symtab *symtab = objfile->GetSymtab();
if (symtab)
ObjectFile *objfile = GetObjectFile();
if (objfile)
{
std::vector<uint32_t> symbol_indexes;
symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
const size_t num_matches = symbol_indexes.size();
if (num_matches)
Symtab *symtab = objfile->GetSymtab();
if (symtab)
symtab->FindFunctionSymbols(lookup_name, lookup_name_type_mask, sc_list);
}
}
if (match_name_after_lookup)
{
SymbolContext sc;
size_t i = old_size;
while (i<sc_list.GetSize())
{
if (sc_list.GetContextAtIndex(i, sc))
{
const bool merge_symbol_into_function = true;
SymbolContext sc(this);
for (size_t i=0; i<num_matches; i++)
const char *func_name = sc.GetFunctionName().GetCString();
if (func_name && strstr (func_name, name.GetCString()) == NULL)
{
sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
SymbolType sym_type = sc.symbol->GetType();
if (sc.symbol && (sym_type == eSymbolTypeCode ||
sym_type == eSymbolTypeResolver))
sc_list.AppendIfUnique (sc, merge_symbol_into_function);
// Remove the current context
sc_list.RemoveContextAtIndex(i);
// Don't increment i and continue in the loop
continue;
}
}
++i;
}
}
}
else
{
if (symbols)
symbols->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, append, sc_list);
// Now check our symbol table for symbols that are code symbols if requested
if (include_symbols)
{
ObjectFile *objfile = GetObjectFile();
if (objfile)
{
Symtab *symtab = objfile->GetSymtab();
if (symtab)
symtab->FindFunctionSymbols(name, name_type_mask, sc_list);
}
}
}
return sc_list.GetSize() - start_size;
return sc_list.GetSize() - old_size;
}
size_t
@ -1347,3 +1390,78 @@ Module::GetVersion (uint32_t *versions, uint32_t num_versions)
}
return 0;
}
void
Module::PrepareForFunctionNameLookup (const ConstString &name,
uint32_t name_type_mask,
ConstString &lookup_name,
uint32_t &lookup_name_type_mask,
bool &match_name_after_lookup)
{
const char *name_cstr = name.GetCString();
lookup_name_type_mask = eFunctionNameTypeNone;
match_name_after_lookup = false;
const char *base_name_start = NULL;
const char *base_name_end = NULL;
if (name_type_mask & eFunctionNameTypeAuto)
{
if (CPPLanguageRuntime::IsCPPMangledName (name_cstr))
lookup_name_type_mask = eFunctionNameTypeFull;
else if (ObjCLanguageRuntime::IsPossibleObjCMethodName (name_cstr))
lookup_name_type_mask = eFunctionNameTypeFull;
else
{
if (ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
lookup_name_type_mask |= eFunctionNameTypeSelector;
if (CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end))
lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
}
}
else
{
lookup_name_type_mask = name_type_mask;
if (lookup_name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase)
{
// If they've asked for a CPP method or function name and it can't be that, we don't
// even need to search for CPP methods or names.
if (!CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end))
{
lookup_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase);
if (lookup_name_type_mask == eFunctionNameTypeNone)
return;
}
}
if (lookup_name_type_mask & eFunctionNameTypeSelector)
{
if (!ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
{
lookup_name_type_mask &= ~(eFunctionNameTypeSelector);
if (lookup_name_type_mask == eFunctionNameTypeNone)
return;
}
}
}
if (base_name_start &&
base_name_end &&
base_name_start != name_cstr &&
base_name_start < base_name_end)
{
// The name supplied was a partial C++ path like "a::count". In this case we want to do a
// lookup on the basename "count" and then make sure any matching results contain "a::count"
// so that it would match "b::a::count" and "a::count". This is why we set "match_name_after_lookup"
// to true
lookup_name.SetCStringWithLength(base_name_start, base_name_end - base_name_start);
match_name_after_lookup = true;
}
else
{
// The name is already correct, just use the exact name as supplied, and we won't need
// to check if any matches contain "name"
lookup_name = name;
match_name_after_lookup = false;
}
}

View File

@ -337,14 +337,64 @@ ModuleList::FindFunctions (const ConstString &name,
if (!append)
sc_list.Clear();
Mutex::Locker locker(m_modules_mutex);
collection::const_iterator pos, end = m_modules.end();
for (pos = m_modules.begin(); pos != end; ++pos)
{
(*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list);
}
const size_t old_size = sc_list.GetSize();
return sc_list.GetSize();
if (name_type_mask & eFunctionNameTypeAuto)
{
ConstString lookup_name;
uint32_t lookup_name_type_mask = 0;
bool match_name_after_lookup = false;
Module::PrepareForFunctionNameLookup (name, name_type_mask,
lookup_name,
lookup_name_type_mask,
match_name_after_lookup);
Mutex::Locker locker(m_modules_mutex);
collection::const_iterator pos, end = m_modules.end();
for (pos = m_modules.begin(); pos != end; ++pos)
{
(*pos)->FindFunctions (lookup_name,
NULL,
lookup_name_type_mask,
include_symbols,
include_inlines,
true,
sc_list);
}
if (match_name_after_lookup)
{
SymbolContext sc;
size_t i = old_size;
while (i<sc_list.GetSize())
{
if (sc_list.GetContextAtIndex(i, sc))
{
const char *func_name = sc.GetFunctionName().GetCString();
if (func_name && strstr (func_name, name.GetCString()) == NULL)
{
// Remove the current context
sc_list.RemoveContextAtIndex(i);
// Don't increment i and continue in the loop
continue;
}
}
++i;
}
}
}
else
{
Mutex::Locker locker(m_modules_mutex);
collection::const_iterator pos, end = m_modules.end();
for (pos = m_modules.begin(); pos != end; ++pos)
{
(*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list);
}
}
return sc_list.GetSize() - old_size;
}
size_t

View File

@ -3116,7 +3116,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
// instance methods for eFunctionNameTypeBase.
target->GetImages().FindFunctions(name,
eFunctionNameTypeBase,
eFunctionNameTypeFull,
include_symbols,
include_inlines,
append,

View File

@ -35,8 +35,8 @@ CommandObjectRegexCommand::CommandObjectRegexCommand
) :
CommandObjectRaw (interpreter, name, help, syntax),
m_max_matches (max_matches),
m_entries (),
m_completion_type_mask (completion_type_mask)
m_completion_type_mask (completion_type_mask),
m_entries ()
{
}

View File

@ -3322,6 +3322,9 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
"SymbolFileDWARF::FindFunctions (name = '%s')",
name.AsCString());
// eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup()
assert ((name_type_mask & eFunctionNameTypeAuto) == 0);
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log)
@ -3347,59 +3350,16 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
// Remember how many sc_list are in the list before we search in case
// we are appending the results to a variable list.
const uint32_t original_size = sc_list.GetSize();
const char *name_cstr = name.GetCString();
uint32_t effective_name_type_mask = eFunctionNameTypeNone;
const char *base_name_start = name_cstr;
const char *base_name_end = name_cstr + strlen(name_cstr);
if (name_type_mask & eFunctionNameTypeAuto)
{
if (CPPLanguageRuntime::IsCPPMangledName (name_cstr))
effective_name_type_mask = eFunctionNameTypeFull;
else if (ObjCLanguageRuntime::IsPossibleObjCMethodName (name_cstr))
effective_name_type_mask = eFunctionNameTypeFull;
else
{
if (ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
effective_name_type_mask |= eFunctionNameTypeSelector;
if (CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end))
effective_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
}
}
else
{
effective_name_type_mask = name_type_mask;
if (effective_name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase)
{
// If they've asked for a CPP method or function name and it can't be that, we don't
// even need to search for CPP methods or names.
if (!CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end))
{
effective_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase);
if (effective_name_type_mask == eFunctionNameTypeNone)
return 0;
}
}
if (effective_name_type_mask & eFunctionNameTypeSelector)
{
if (!ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
{
effective_name_type_mask &= ~(eFunctionNameTypeSelector);
if (effective_name_type_mask == eFunctionNameTypeNone)
return 0;
}
}
}
const uint32_t original_size = sc_list.GetSize();
DWARFDebugInfo* info = DebugInfo();
if (info == NULL)
return 0;
DWARFCompileUnit *dwarf_cu = NULL;
std::set<const DWARFDebugInfoEntry *> resolved_dies;
if (m_using_apple_tables)
{
if (m_apple_names_ap.get())
@ -3409,7 +3369,7 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
uint32_t num_matches = 0;
if (effective_name_type_mask & eFunctionNameTypeFull)
if (name_type_mask & eFunctionNameTypeFull)
{
// If they asked for the full name, match what they typed. At some point we may
// want to canonicalize this (strip double spaces, etc. For now, we just add all the
@ -3427,7 +3387,11 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
continue;
ResolveFunction (dwarf_cu, die, sc_list);
if (resolved_dies.find(die) == resolved_dies.end())
{
if (ResolveFunction (dwarf_cu, die, sc_list))
resolved_dies.insert(die);
}
}
else
{
@ -3436,87 +3400,116 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
}
}
}
else
{
if (effective_name_type_mask & eFunctionNameTypeSelector)
{
if (namespace_decl && *namespace_decl)
return 0; // no selectors in namespaces
num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
// Now make sure these are actually ObjC methods. In this case we can simply look up the name,
// and if it is an ObjC method name, we're good.
if (name_type_mask & eFunctionNameTypeSelector)
{
if (namespace_decl && *namespace_decl)
return 0; // no selectors in namespaces
for (uint32_t i = 0; i < num_matches; i++)
{
const dw_offset_t die_offset = die_offsets[i];
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
if (die)
{
const char *die_name = die->GetName(this, dwarf_cu);
if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name))
{
if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
continue;
ResolveFunction (dwarf_cu, die, sc_list);
}
}
else
{
GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
die_offset, name_cstr);
}
}
die_offsets.clear();
}
num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
// Now make sure these are actually ObjC methods. In this case we can simply look up the name,
// and if it is an ObjC method name, we're good.
if (effective_name_type_mask & eFunctionNameTypeMethod
|| effective_name_type_mask & eFunctionNameTypeBase)
for (uint32_t i = 0; i < num_matches; i++)
{
if ((effective_name_type_mask & eFunctionNameTypeMethod) &&
(namespace_decl && *namespace_decl))
return 0; // no methods in namespaces
// The apple_names table stores just the "base name" of C++ methods in the table. So we have to
// extract the base name, look that up, and if there is any other information in the name we were
// passed in we have to post-filter based on that.
// FIXME: Arrange the logic above so that we don't calculate the base name twice:
std::string base_name(base_name_start, base_name_end - base_name_start);
num_matches = m_apple_names_ap->FindByName (base_name.c_str(), die_offsets);
for (uint32_t i = 0; i < num_matches; i++)
const dw_offset_t die_offset = die_offsets[i];
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
if (die)
{
const dw_offset_t die_offset = die_offsets[i];
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
if (die)
const char *die_name = die->GetName(this, dwarf_cu);
if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name))
{
if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
continue;
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
if (!FunctionDieMatchesPartialName(die,
dwarf_cu,
effective_name_type_mask,
name_cstr,
base_name_start,
base_name_end))
continue;
// If we get to here, the die is good, and we should add it:
ResolveFunction (dwarf_cu, die, sc_list);
if (resolved_dies.find(die) == resolved_dies.end())
{
if (ResolveFunction (dwarf_cu, die, sc_list))
resolved_dies.insert(die);
}
}
else
{
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
die_offset, name_cstr);
}
}
die_offsets.clear();
else
{
GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
die_offset, name_cstr);
}
}
die_offsets.clear();
}
if (((name_type_mask & eFunctionNameTypeMethod) && !namespace_decl) || name_type_mask & eFunctionNameTypeBase)
{
// The apple_names table stores just the "base name" of C++ methods in the table. So we have to
// extract the base name, look that up, and if there is any other information in the name we were
// passed in we have to post-filter based on that.
// FIXME: Arrange the logic above so that we don't calculate the base name twice:
num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
for (uint32_t i = 0; i < num_matches; i++)
{
const dw_offset_t die_offset = die_offsets[i];
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
if (die)
{
if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
continue;
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
// If we get to here, the die is good, and we should add it:
if (resolved_dies.find(die) == resolved_dies.end())
if (ResolveFunction (dwarf_cu, die, sc_list))
{
bool keep_die = true;
if ((name_type_mask & (eFunctionNameTypeBase|eFunctionNameTypeMethod)) != (eFunctionNameTypeBase|eFunctionNameTypeMethod))
{
// We are looking for either basenames or methods, so we need to
// trim out the ones we won't want by looking at the type
SymbolContext sc;
if (sc_list.GetLastContext(sc))
{
if (sc.block)
{
// We have an inlined function
}
else if (sc.function)
{
Type *type = sc.function->GetType();
clang::DeclContext* decl_ctx = GetClangDeclContextContainingTypeUID (type->GetID());
if (decl_ctx->isRecord())
{
if (name_type_mask & eFunctionNameTypeBase)
{
sc_list.RemoveContextAtIndex(sc_list.GetSize()-1);
keep_die = false;
}
}
else
{
if (name_type_mask & eFunctionNameTypeMethod)
{
sc_list.RemoveContextAtIndex(sc_list.GetSize()-1);
keep_die = false;
}
}
}
}
}
if (keep_die)
resolved_dies.insert(die);
}
}
else
{
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
die_offset, name_cstr);
}
}
die_offsets.clear();
}
}
}
@ -3530,14 +3523,12 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if (name_type_mask & eFunctionNameTypeFull)
FindFunctions (name, m_function_fullname_index, sc_list);
std::string base_name(base_name_start, base_name_end - base_name_start);
ConstString base_name_const(base_name.c_str());
DIEArray die_offsets;
DWARFCompileUnit *dwarf_cu = NULL;
if (effective_name_type_mask & eFunctionNameTypeBase)
if (name_type_mask & eFunctionNameTypeBase)
{
uint32_t num_base = m_function_basename_index.Find(base_name_const, die_offsets);
uint32_t num_base = m_function_basename_index.Find(name, die_offsets);
for (uint32_t i = 0; i < num_base; i++)
{
const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu);
@ -3549,27 +3540,23 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
continue;
if (!FunctionDieMatchesPartialName(die,
dwarf_cu,
eFunctionNameTypeBase,
name_cstr,
base_name_start,
base_name_end))
continue;
// If we get to here, the die is good, and we should add it:
ResolveFunction (dwarf_cu, die, sc_list);
if (resolved_dies.find(die) == resolved_dies.end())
{
if (ResolveFunction (dwarf_cu, die, sc_list))
resolved_dies.insert(die);
}
}
}
die_offsets.clear();
}
if (effective_name_type_mask & eFunctionNameTypeMethod)
if (name_type_mask & eFunctionNameTypeMethod)
{
if (namespace_decl && *namespace_decl)
return 0; // no methods in namespaces
uint32_t num_base = m_function_method_index.Find(base_name_const, die_offsets);
uint32_t num_base = m_function_method_index.Find(name, die_offsets);
{
for (uint32_t i = 0; i < num_base; i++)
{
@ -3579,23 +3566,19 @@ SymbolFileDWARF::FindFunctions (const ConstString &name,
if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
continue;
if (!FunctionDieMatchesPartialName(die,
dwarf_cu,
eFunctionNameTypeMethod,
name_cstr,
base_name_start,
base_name_end))
continue;
// If we get to here, the die is good, and we should add it:
ResolveFunction (dwarf_cu, die, sc_list);
if (resolved_dies.find(die) == resolved_dies.end())
{
if (ResolveFunction (dwarf_cu, die, sc_list))
resolved_dies.insert(die);
}
}
}
}
die_offsets.clear();
}
if ((effective_name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl))
if ((name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl))
{
FindFunctions (name, m_function_selector_index, sc_list);
}

View File

@ -1055,6 +1055,17 @@ SymbolContextList::GetContextAtIndex(size_t idx, SymbolContext& sc) const
return false;
}
bool
SymbolContextList::GetLastContext(SymbolContext& sc) const
{
if (!m_symbol_contexts.empty())
{
sc = m_symbol_contexts.back();
return true;
}
return false;
}
bool
SymbolContextList::RemoveContextAtIndex (size_t idx)
{

View File

@ -16,6 +16,7 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symtab.h"
#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
using namespace lldb;
@ -263,9 +264,9 @@ Symtab::InitNameIndexes()
m_name_indexes_computed = true;
Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
// Create the name index vector to be able to quickly search by name
const size_t count = m_symbols.size();
const size_t num_symbols = m_symbols.size();
#if 1
m_name_to_index.Reserve (count);
m_name_to_index.Reserve (num_symbols);
#else
// TODO: benchmark this to see if we save any memory. Otherwise we
// will always keep the memory reserved in the vector unless we pull
@ -288,7 +289,12 @@ Symtab::InitNameIndexes()
NameToIndexMap::Entry entry;
for (entry.value = 0; entry.value < count; ++entry.value)
// The "const char *" in "class_contexts" must come from a ConstString::GetCString()
std::set<const char *> class_contexts;
UniqueCStringMap<uint32_t> mangled_name_to_index;
std::vector<const char *> symbol_contexts(num_symbols, NULL);
for (entry.value = 0; entry.value<num_symbols; ++entry.value)
{
const Symbol *symbol = &m_symbols[entry.value];
@ -303,8 +309,66 @@ Symtab::InitNameIndexes()
const Mangled &mangled = symbol->GetMangled();
entry.cstring = mangled.GetMangledName().GetCString();
if (entry.cstring && entry.cstring[0])
{
m_name_to_index.Append (entry);
const SymbolType symbol_type = symbol->GetType();
if (symbol_type == eSymbolTypeCode || symbol_type == eSymbolTypeResolver)
{
if (entry.cstring[0] == '_' && entry.cstring[1] == 'Z' &&
(entry.cstring[2] != 'T' && // avoid virtual table, VTT structure, typeinfo structure, and typeinfo name
entry.cstring[2] != 'G' && // avoid guard variables
entry.cstring[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back)
{
CPPLanguageRuntime::MethodName cxx_method (mangled.GetDemangledName());
entry.cstring = cxx_method.GetBasename ().GetCString();
if (entry.cstring && entry.cstring[0])
{
// ConstString objects permanently store the string in the pool so calling
// GetCString() on the value gets us a const char * that will never go away
const char *const_context = ConstString(cxx_method.GetContext()).GetCString();
if (entry.cstring[0] == '~' || !cxx_method.GetQualifiers().empty())
{
// The first character of the demangled basename is '~' which
// means we have a class destructor. We can use this information
// to help us know what is a class and what isn't.
if (class_contexts.find(const_context) == class_contexts.end())
class_contexts.insert(const_context);
m_method_to_index.Append (entry);
}
else
{
if (const_context && const_context[0])
{
if (class_contexts.find(const_context) != class_contexts.end())
{
// The current decl context is in our "class_contexts" which means
// this is a method on a class
m_method_to_index.Append (entry);
}
else
{
// We don't know if this is a function basename or a method,
// so put it into a temporary collection so once we are done
// we can look in class_contexts to see if each entry is a class
// or just a function and will put any remaining items into
// m_method_to_index or m_basename_to_index as needed
mangled_name_to_index.Append (entry);
symbol_contexts[entry.value] = const_context;
}
}
else
{
// No context for this function so this has to be a basename
m_basename_to_index.Append(entry);
}
}
}
}
}
}
entry.cstring = mangled.GetDemangledName().GetCString();
if (entry.cstring && entry.cstring[0])
m_name_to_index.Append (entry);
@ -326,15 +390,64 @@ Symtab::InitNameIndexes()
}
}
size_t count;
if (!mangled_name_to_index.IsEmpty())
{
count = mangled_name_to_index.GetSize();
for (size_t i=0; i<count; ++i)
{
if (mangled_name_to_index.GetValueAtIndex(i, entry.value))
{
entry.cstring = mangled_name_to_index.GetCStringAtIndex(i);
if (symbol_contexts[entry.value] && class_contexts.find(symbol_contexts[entry.value]) != class_contexts.end())
{
m_method_to_index.Append (entry);
}
else
{
// If we got here, we have something that had a context (was inside a namespace or class)
// yet we don't know if the entry
m_method_to_index.Append (entry);
m_basename_to_index.Append (entry);
}
}
}
}
m_name_to_index.Sort();
m_name_to_index.SizeToFit();
m_selector_to_index.Sort();
m_selector_to_index.SizeToFit();
m_basename_to_index.Sort();
m_basename_to_index.SizeToFit();
m_method_to_index.Sort();
m_method_to_index.SizeToFit();
// static StreamFile a ("/tmp/a.txt");
//
// count = m_basename_to_index.GetSize();
// if (count)
// {
// for (size_t i=0; i<count; ++i)
// {
// if (m_basename_to_index.GetValueAtIndex(i, entry.value))
// a.Printf ("%s BASENAME\n", m_symbols[entry.value].GetMangled().GetName().GetCString());
// }
// }
// count = m_method_to_index.GetSize();
// if (count)
// {
// for (size_t i=0; i<count; ++i)
// {
// if (m_method_to_index.GetValueAtIndex(i, entry.value))
// a.Printf ("%s METHOD\n", m_symbols[entry.value].GetMangled().GetName().GetCString());
// }
// }
}
}
void
Symtab::AppendSymbolNamesToMap (const IndexCollection &indexes,
Symtab::AppendSymbolNamesToMap (const IndexCollection &indexes,
bool add_demangled,
bool add_mangled,
NameToIndexMap &name_to_index_map) const
@ -1009,6 +1122,7 @@ Symtab::SymbolIndicesToSymbolContextList (std::vector<uint32_t> &symbol_indexes,
// No need to protect this call using m_mutex all other method calls are
// already thread safe.
const bool merge_symbol_into_function = true;
size_t num_indices = symbol_indexes.size();
if (num_indices > 0)
{
@ -1018,7 +1132,7 @@ Symtab::SymbolIndicesToSymbolContextList (std::vector<uint32_t> &symbol_indexes,
{
sc.symbol = SymbolAtIndex (symbol_indexes[i]);
if (sc.symbol)
sc_list.Append (sc);
sc_list.AppendIfUnique(sc, merge_symbol_into_function);
}
}
}
@ -1031,11 +1145,53 @@ Symtab::FindFunctionSymbols (const ConstString &name,
{
size_t count = 0;
std::vector<uint32_t> symbol_indexes;
if (name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeAuto))
const char *name_cstr = name.GetCString();
// eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup()
assert ((name_type_mask & eFunctionNameTypeAuto) == 0);
if (name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull))
{
FindAllSymbolsWithNameAndType (name, eSymbolTypeCode, symbol_indexes);
}
if (name_type_mask & eFunctionNameTypeBase)
{
// From mangled names we can't tell what is a basename and what
// is a method name, so we just treat them the same
if (!m_name_indexes_computed)
InitNameIndexes();
if (!m_basename_to_index.IsEmpty())
{
const UniqueCStringMap<uint32_t>::Entry *match;
for (match = m_basename_to_index.FindFirstValueForName(name_cstr);
match != NULL;
match = m_basename_to_index.FindNextValueForName(match))
{
symbol_indexes.push_back(match->value);
}
}
}
if (name_type_mask & eFunctionNameTypeMethod)
{
if (!m_name_indexes_computed)
InitNameIndexes();
if (!m_method_to_index.IsEmpty())
{
const UniqueCStringMap<uint32_t>::Entry *match;
for (match = m_method_to_index.FindFirstValueForName(name_cstr);
match != NULL;
match = m_method_to_index.FindNextValueForName(match))
{
symbol_indexes.push_back(match->value);
}
}
}
if (name_type_mask & eFunctionNameTypeSelector)
{
if (!m_name_indexes_computed)
@ -1044,7 +1200,7 @@ Symtab::FindFunctionSymbols (const ConstString &name,
if (!m_selector_to_index.IsEmpty())
{
const UniqueCStringMap<uint32_t>::Entry *match;
for (match = m_selector_to_index.FindFirstValueForName(name.AsCString());
for (match = m_selector_to_index.FindFirstValueForName(name_cstr);
match != NULL;
match = m_selector_to_index.FindNextValueForName(match))
{

View File

@ -190,65 +190,65 @@ CPPLanguageRuntime::IsCPPMangledName (const char *name)
bool
CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end)
{
if (base_name_end == NULL)
base_name_end = name + strlen (name);
if (base_name_end == NULL)
base_name_end = name + strlen (name);
const char *last_colon = NULL;
for (const char *ptr = base_name_end; ptr != name; ptr--)
const char *last_colon = NULL;
for (const char *ptr = base_name_end; ptr != name; ptr--)
{
if (*ptr == ':')
if (*ptr == ':')
{
last_colon = ptr;
break;
last_colon = ptr;
break;
}
}
if (last_colon == NULL)
if (last_colon == NULL)
{
base_name_start = name;
return true;
base_name_start = name;
return true;
}
// Can't have a C++ name that begins with a single ':', nor contains an internal single ':'
if (last_colon == name)
return false;
else if (last_colon[-1] != ':')
return false;
else
// Can't have a C++ name that begins with a single ':', nor contains an internal single ':'
if (last_colon == name)
return false;
else if (last_colon[-1] != ':')
return false;
else
{
// FIXME: should check if there is
base_name_start = last_colon + 1;
return true;
// FIXME: should check if there is
base_name_start = last_colon + 1;
return true;
}
}
bool
CPPLanguageRuntime::IsPossibleCPPCall (const char *name, const char *&base_name_start, const char *&base_name_end)
{
if (!name)
return false;
return false;
// For now, I really can't handle taking template names apart, so if you
// have < or > I'll say "could be CPP but leave the base_name empty which
// means I couldn't figure out what to use for that.
// FIXME: Do I need to do more sanity checking here?
if (strchr(name, '>') != NULL || strchr (name, '>') != NULL)
return true;
return true;
size_t name_len = strlen (name);
if (name[name_len - 1] == ')')
{
// We've got arguments.
base_name_end = strchr (name, '(');
if (base_name_end == NULL)
return false;
return false;
// FIXME: should check that this parenthesis isn't a template specialized
// on a function type or something gross like that...
}
else
base_name_end = name + strlen (name);
return StripNamespacesFromVariableName (name, base_name_start, base_name_end);
}
@ -267,3 +267,156 @@ CPPLanguageRuntime::FindEquivalentNames(ConstString type_name, std::vector<Const
return count;
}
void
CPPLanguageRuntime::MethodName::Clear()
{
m_full.Clear();
m_basename.Clear();
m_context = llvm::StringRef();
m_arguments = llvm::StringRef();
m_qualifiers = llvm::StringRef();
m_type = eTypeInvalid;
m_parsed = false;
m_parse_error = false;
}
bool
ReverseFindMatchingChars (const llvm::StringRef &s,
const llvm::StringRef &left_right_chars,
size_t &left_pos,
size_t &right_pos,
size_t pos = llvm::StringRef::npos)
{
assert (left_right_chars.size() == 2);
left_pos = llvm::StringRef::npos;
const char left_char = left_right_chars[0];
const char right_char = left_right_chars[1];
pos = s.find_last_of(left_right_chars, pos);
if (pos == llvm::StringRef::npos || s[pos] == left_char)
return false;
right_pos = pos;
uint32_t depth = 1;
while (pos > 0 && depth > 0)
{
pos = s.find_last_of(left_right_chars, pos);
if (pos == llvm::StringRef::npos)
return false;
if (s[pos] == left_char)
{
if (--depth == 0)
{
left_pos = pos;
return left_pos < right_pos;
}
}
else if (s[pos] == right_char)
{
++depth;
}
}
return false;
}
void
CPPLanguageRuntime::MethodName::Parse()
{
if (!m_parsed && m_full)
{
// ConstString mangled;
// m_full.GetMangledCounterpart(mangled);
// printf ("\n parsing = '%s'\n", m_full.GetCString());
// if (mangled)
// printf (" mangled = '%s'\n", mangled.GetCString());
m_parse_error = false;
m_parsed = true;
llvm::StringRef full (m_full.GetCString());
size_t arg_start, arg_end;
llvm::StringRef parens("()", 2);
if (ReverseFindMatchingChars (full, parens, arg_start, arg_end))
{
m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
if (arg_end + 1 < full.size())
m_qualifiers = full.substr(arg_end + 1);
if (arg_start > 0)
{
size_t basename_end = arg_start;
size_t context_end = llvm::StringRef::npos;
if (basename_end > 0 && full[basename_end-1] == '>')
{
// TODO: handle template junk...
// Templated function
size_t template_start, template_end;
llvm::StringRef lt_gt("<>", 2);
if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end))
context_end = full.rfind(':', template_start);
}
if (context_end == llvm::StringRef::npos)
context_end = full.rfind(':', basename_end);
if (context_end == llvm::StringRef::npos)
m_basename.SetString(full.substr(0, basename_end));
else
{
m_context = full.substr(0, context_end - 1);
const size_t basename_begin = context_end + 1;
m_basename.SetString(full.substr(basename_begin, basename_end - basename_begin));
}
m_type = eTypeUnknownMethod;
}
else
{
m_parse_error = true;
return;
}
// if (!m_context.empty())
// printf (" context = '%s'\n", m_context.str().c_str());
// if (m_basename)
// printf (" basename = '%s'\n", m_basename.GetCString());
// if (!m_arguments.empty())
// printf (" arguments = '%s'\n", m_arguments.str().c_str());
// if (!m_qualifiers.empty())
// printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str());
}
else
{
m_parse_error = true;
// printf ("error: didn't find matching parens for arguments\n");
}
}
}
const ConstString &
CPPLanguageRuntime::MethodName::GetBasename ()
{
if (!m_parsed)
Parse();
return m_basename;
}
llvm::StringRef
CPPLanguageRuntime::MethodName::GetContext ()
{
if (!m_parsed)
Parse();
return m_context;
}
llvm::StringRef
CPPLanguageRuntime::MethodName::GetArguments ()
{
if (!m_parsed)
Parse();
return m_arguments;
}
llvm::StringRef
CPPLanguageRuntime::MethodName::GetQualifiers ()
{
if (!m_parsed)
Parse();
return m_qualifiers;
}