forked from OSchip/llvm-project
Improve C++ function name handling and step-in avoid regerxp handling
If the function is a template then the return type is part of the function name. This CL fixes the parsing of these function names in the case when the return type contains ':'. The name of free functions in C++ don't have context part. Fix the logic geting the function name without arguments out from a full function name to handle this case. Change the handling of step-in-avoid-regexp to match the value against the function name without it's arguments and return value. This is required because the default regex ("^std::") would match any template function returning an std object. Fifferential revision: http://reviews.llvm.org/D11461 llvm-svn: 243099
This commit is contained in:
parent
327675baa9
commit
5aa27e1acc
|
@ -95,10 +95,11 @@ get_demangled_name_without_arguments (ConstString mangled, ConstString demangled
|
|||
mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back)
|
||||
{
|
||||
CPPLanguageRuntime::MethodName cxx_method (demangled);
|
||||
if (!cxx_method.GetBasename().empty() && !cxx_method.GetContext().empty())
|
||||
if (!cxx_method.GetBasename().empty())
|
||||
{
|
||||
std::string shortname = cxx_method.GetContext().str();
|
||||
shortname += "::";
|
||||
std::string shortname;
|
||||
if (!cxx_method.GetContext().empty())
|
||||
shortname = cxx_method.GetContext().str() + "::";
|
||||
shortname += cxx_method.GetBasename().str();
|
||||
ConstString result(shortname.c_str());
|
||||
g_most_recent_mangled_to_name_sans_args.first = mangled;
|
||||
|
|
|
@ -306,17 +306,14 @@ CPPLanguageRuntime::MethodName::Parse()
|
|||
llvm::StringRef lt_gt("<>", 2);
|
||||
if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end))
|
||||
{
|
||||
// Check for templated functions that include return type like: 'void foo<Int>()'
|
||||
context_start = full.rfind(' ', template_start);
|
||||
if (context_start == llvm::StringRef::npos)
|
||||
context_start = 0;
|
||||
|
||||
context_end = full.rfind(':', template_start);
|
||||
if (context_end == llvm::StringRef::npos)
|
||||
{
|
||||
// Check for templated functions that include return type like:
|
||||
// 'void foo<Int>()'
|
||||
context_end = full.rfind(' ', template_start);
|
||||
if (context_end != llvm::StringRef::npos)
|
||||
{
|
||||
context_start = context_end;
|
||||
}
|
||||
}
|
||||
if (context_end == llvm::StringRef::npos || context_end < context_start)
|
||||
context_end = context_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -375,7 +375,7 @@ ThreadPlanStepInRange::FrameMatchesAvoidCriteria ()
|
|||
SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
|
||||
if (sc.symbol != NULL)
|
||||
{
|
||||
const char *frame_function_name = sc.GetFunctionName().GetCString();
|
||||
const char *frame_function_name = sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments).GetCString();
|
||||
if (frame_function_name)
|
||||
{
|
||||
size_t num_matches = 0;
|
||||
|
|
|
@ -53,7 +53,7 @@ class DisassemblyTestCase(TestBase):
|
|||
self.assertFalse(op in disassembly)
|
||||
|
||||
# make sure a few reasonable assembly instructions are here
|
||||
self.expect(disassembly, exe=False, startstr = "a.out`sum(int, int)", substrs = instructions)
|
||||
self.expect(disassembly, exe=False, startstr = "a.out`sum", substrs = instructions)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
|
|
|
@ -45,6 +45,21 @@ class TestInlineStepping(TestBase):
|
|||
"""Test stepping over and into inlined functions."""
|
||||
self.buildDwarf()
|
||||
self.inline_stepping_step_over()
|
||||
|
||||
@skipUnlessDarwin
|
||||
@python_api_test
|
||||
@dsym_test
|
||||
def test_step_in_template_with_dsym_and_python_api(self):
|
||||
"""Test stepping in to templated functions."""
|
||||
self.buildDsym()
|
||||
self.step_in_template()
|
||||
|
||||
@python_api_test
|
||||
@dwarf_test
|
||||
def test_step_in_template_with_dwarf_and_python_api(self):
|
||||
"""Test stepping in to templated functions."""
|
||||
self.buildDwarf()
|
||||
self.step_in_template()
|
||||
|
||||
def setUp(self):
|
||||
# Call super's setUp().
|
||||
|
@ -120,7 +135,6 @@ class TestInlineStepping(TestBase):
|
|||
target_line_entry.SetLine(step_stop_line)
|
||||
self.do_step (step_pattern[1], target_line_entry, test_stack_depth)
|
||||
|
||||
|
||||
def inline_stepping(self):
|
||||
"""Use Python APIs to test stepping over and hitting breakpoints."""
|
||||
exe = os.path.join(os.getcwd(), "a.out")
|
||||
|
@ -245,8 +259,40 @@ class TestInlineStepping(TestBase):
|
|||
["// At increment in caller_ref_2.", "over"]]
|
||||
self.run_step_sequence (step_sequence)
|
||||
|
||||
def step_in_template(self):
|
||||
"""Use Python APIs to test stepping in to templated functions."""
|
||||
exe = os.path.join(os.getcwd(), "a.out")
|
||||
|
||||
target = self.dbg.CreateTarget(exe)
|
||||
self.assertTrue(target, VALID_TARGET)
|
||||
|
||||
break_1_in_main = target.BreakpointCreateBySourceRegex ('// Call max_value template', self.main_source_spec)
|
||||
self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
|
||||
|
||||
break_2_in_main = target.BreakpointCreateBySourceRegex ('// Call max_value specialized', self.main_source_spec)
|
||||
self.assertTrue(break_2_in_main, VALID_BREAKPOINT)
|
||||
|
||||
# Now launch the process, and do not stop at entry point.
|
||||
self.process = target.LaunchSimple (None, None, self.get_process_working_directory())
|
||||
self.assertTrue(self.process, PROCESS_IS_VALID)
|
||||
|
||||
# The stop reason of the thread should be breakpoint.
|
||||
threads = lldbutil.get_threads_stopped_at_breakpoint (self.process, break_1_in_main)
|
||||
|
||||
if len(threads) != 1:
|
||||
self.fail ("Failed to stop at first breakpoint in main.")
|
||||
|
||||
self.thread = threads[0]
|
||||
|
||||
step_sequence = [["// In max_value template", "into"]]
|
||||
self.run_step_sequence(step_sequence)
|
||||
|
||||
threads = lldbutil.continue_to_breakpoint (self.process, break_2_in_main)
|
||||
self.assertEqual(len(threads), 1, "Successfully ran to call site of second caller_trivial_1 call.")
|
||||
self.thread = threads[0]
|
||||
|
||||
step_sequence = [["// In max_value specialized", "into"]]
|
||||
self.run_step_sequence(step_sequence)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
inline int inline_ref_1 (int &value) __attribute__((always_inline));
|
||||
inline int inline_ref_2 (int &value) __attribute__((always_inline));
|
||||
|
@ -97,6 +99,18 @@ inline_trivial_2 ()
|
|||
called_by_inline_trivial (); // At caller_by_inline_trivial in inline_trivial_2.
|
||||
}
|
||||
|
||||
template<typename T> T
|
||||
max_value(const T& lhs, const T& rhs)
|
||||
{
|
||||
return std::max(lhs, rhs); // In max_value template
|
||||
}
|
||||
|
||||
template<> std::string
|
||||
max_value(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
return (lhs.size() > rhs.size()) ? lhs : rhs; // In max_value specialized
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
@ -114,6 +128,9 @@ main (int argc, char **argv)
|
|||
caller_ref_1 (argc); // At second call of caller_ref_1 in main.
|
||||
|
||||
function_to_call (); // Make sure debug info for this function gets generated.
|
||||
|
||||
max_value(123, 456); // Call max_value template
|
||||
max_value(std::string("abc"), std::string("0022")); // Call max_value specialized
|
||||
|
||||
return 0; // About to return from main.
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue