forked from OSchip/llvm-project
Add logic to LLDB to figure out the types of member functions of C++ classes. Add plumbing for that all the way up to the SB layer
llvm-svn: 217701
This commit is contained in:
parent
ab4fe98b4a
commit
190064ad0d
|
@ -160,6 +160,12 @@ public:
|
|||
|
||||
lldb::SBTypeList
|
||||
GetFunctionArgumentTypes ();
|
||||
|
||||
uint32_t
|
||||
GetNumberOfMemberFunctions ();
|
||||
|
||||
lldb::SBType
|
||||
GetMemberFunctionAtIndex (uint32_t idx);
|
||||
|
||||
const char*
|
||||
GetName();
|
||||
|
|
|
@ -334,6 +334,12 @@ public:
|
|||
ClangASTType
|
||||
GetFunctionReturnType () const;
|
||||
|
||||
size_t
|
||||
GetNumMemberFunctions () const;
|
||||
|
||||
ClangASTType
|
||||
GetMemberFunctionAtIndex (size_t idx);
|
||||
|
||||
ClangASTType
|
||||
GetLValueReferenceType () const;
|
||||
|
||||
|
|
|
@ -239,6 +239,12 @@ public:
|
|||
|
||||
lldb::SBTypeList
|
||||
GetFunctionArgumentTypes ();
|
||||
|
||||
uint32_t
|
||||
GetNumberOfMemberFunctions ();
|
||||
|
||||
lldb::SBType
|
||||
GetMemberFunctionAtIndex (uint32_t idx);
|
||||
|
||||
bool
|
||||
IsTypeComplete ();
|
||||
|
|
|
@ -252,6 +252,28 @@ SBType::GetFunctionArgumentTypes ()
|
|||
return sb_type_list;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SBType::GetNumberOfMemberFunctions ()
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
return m_opaque_sp->GetClangASTType(true).GetNumMemberFunctions();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
lldb::SBType
|
||||
SBType::GetMemberFunctionAtIndex (uint32_t idx)
|
||||
{
|
||||
SBType sb_func_type;
|
||||
if (IsValid())
|
||||
{
|
||||
ClangASTType func_type(m_opaque_sp->GetClangASTType(true).GetMemberFunctionAtIndex(idx));
|
||||
sb_func_type = SBType(func_type);
|
||||
}
|
||||
return sb_func_type;
|
||||
}
|
||||
|
||||
lldb::SBType
|
||||
SBType::GetUnqualifiedType()
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <mutex>
|
||||
|
||||
using namespace lldb;
|
||||
|
@ -1741,6 +1742,68 @@ ClangASTType::GetFunctionReturnType () const
|
|||
return ClangASTType();
|
||||
}
|
||||
|
||||
size_t
|
||||
ClangASTType::GetNumMemberFunctions () const
|
||||
{
|
||||
size_t num_functions = 0;
|
||||
if (IsValid())
|
||||
{
|
||||
clang::QualType qual_type(GetCanonicalQualType());
|
||||
switch (qual_type->getTypeClass()) {
|
||||
case clang::Type::Record:
|
||||
if (GetCompleteQualType (m_ast, qual_type))
|
||||
{
|
||||
const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
|
||||
const clang::RecordDecl *record_decl = record_type->getDecl();
|
||||
assert(record_decl);
|
||||
const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
|
||||
if (cxx_record_decl)
|
||||
num_functions = std::distance(cxx_record_decl->method_begin(), cxx_record_decl->method_end());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return num_functions;
|
||||
}
|
||||
|
||||
ClangASTType
|
||||
ClangASTType::GetMemberFunctionAtIndex (size_t idx)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
clang::QualType qual_type(GetCanonicalQualType());
|
||||
switch (qual_type->getTypeClass()) {
|
||||
case clang::Type::Record:
|
||||
if (GetCompleteQualType (m_ast, qual_type))
|
||||
{
|
||||
const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
|
||||
const clang::RecordDecl *record_decl = record_type->getDecl();
|
||||
assert(record_decl);
|
||||
const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
|
||||
if (cxx_record_decl)
|
||||
{
|
||||
auto method_iter = cxx_record_decl->method_begin();
|
||||
auto method_end = cxx_record_decl->method_end();
|
||||
if (idx < std::distance(method_iter, method_end))
|
||||
{
|
||||
std::advance(method_iter, idx);
|
||||
auto method_decl = method_iter->getCanonicalDecl();
|
||||
if (method_decl)
|
||||
return ClangASTType(m_ast,method_decl->getType().getAsOpaquePtr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ClangASTType();
|
||||
}
|
||||
|
||||
ClangASTType
|
||||
ClangASTType::GetLValueReferenceType () const
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,81 @@
|
|||
"""
|
||||
Test SBType and SBTypeList API.
|
||||
"""
|
||||
|
||||
import os, time
|
||||
import re
|
||||
import unittest2
|
||||
import lldb, lldbutil
|
||||
from lldbtest import *
|
||||
|
||||
class TypeAndTypeListTestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
@python_api_test
|
||||
@dsym_test
|
||||
def test_with_dsym(self):
|
||||
"""Exercise SBType and SBTypeList API."""
|
||||
d = {'EXE': self.exe_name}
|
||||
self.buildDsym(dictionary=d)
|
||||
self.setTearDownCleanup(dictionary=d)
|
||||
self.type_api(self.exe_name)
|
||||
|
||||
@python_api_test
|
||||
@dwarf_test
|
||||
def test_with_dwarf(self):
|
||||
"""Exercise SBType and SBTypeList API."""
|
||||
d = {'EXE': self.exe_name}
|
||||
self.buildDwarf(dictionary=d)
|
||||
self.setTearDownCleanup(dictionary=d)
|
||||
self.type_api(self.exe_name)
|
||||
|
||||
def setUp(self):
|
||||
# Call super's setUp().
|
||||
TestBase.setUp(self)
|
||||
# We'll use the test method name as the exe_name.
|
||||
self.exe_name = self.testMethodName
|
||||
# Find the line number to break at.
|
||||
self.source = 'main.cpp'
|
||||
self.line = line_number(self.source, '// set breakpoint here')
|
||||
|
||||
def type_api(self, exe_name):
|
||||
"""Exercise SBType and SBTypeList API."""
|
||||
exe = os.path.join(os.getcwd(), exe_name)
|
||||
|
||||
# Create a target by the debugger.
|
||||
target = self.dbg.CreateTarget(exe)
|
||||
self.assertTrue(target, VALID_TARGET)
|
||||
|
||||
# Create the breakpoint inside function 'main'.
|
||||
breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
|
||||
self.assertTrue(breakpoint, VALID_BREAKPOINT)
|
||||
|
||||
# Now launch the process, and do not stop at entry point.
|
||||
process = target.LaunchSimple (None, None, self.get_process_working_directory())
|
||||
self.assertTrue(process, PROCESS_IS_VALID)
|
||||
|
||||
# Get Frame #0.
|
||||
self.assertTrue(process.GetState() == lldb.eStateStopped)
|
||||
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
|
||||
self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
|
||||
variable = frame0.FindVariable("d")
|
||||
Derived = variable.GetType()
|
||||
Base = Derived.GetDirectBaseClassAtIndex(0).GetType()
|
||||
|
||||
self.assertTrue(Derived.GetNumberOfMemberFunctions() == 2, "Derived declares two methods")
|
||||
self.assertTrue(Derived.GetMemberFunctionAtIndex(0).GetFunctionReturnType().GetName() == "int", "Derived::dImpl returns int")
|
||||
|
||||
self.assertTrue(Base.GetNumberOfMemberFunctions() == 4, "Base declares three methods")
|
||||
self.assertTrue(Base.GetMemberFunctionAtIndex(3).GetFunctionArgumentTypes().GetSize() == 3, "Base::sfunc takes three arguments")
|
||||
self.assertTrue(Base.GetMemberFunctionAtIndex(2).GetFunctionArgumentTypes().GetSize() == 0, "Base::dat takes no arguments")
|
||||
self.assertTrue(Base.GetMemberFunctionAtIndex(1).GetFunctionArgumentTypes().GetTypeAtIndex(1).GetName() == "char", "Base::bar takes a second 'char' argument")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
lldb.SBDebugger.Initialize()
|
||||
atexit.register(lambda: lldb.SBDebugger.Terminate())
|
||||
unittest2.main()
|
|
@ -0,0 +1,28 @@
|
|||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class Base {
|
||||
public:
|
||||
int foo(int x, int y) { return 1; }
|
||||
char bar(int x, char y) { return 2; }
|
||||
void dat() {}
|
||||
static int sfunc(char, int, float) { return 3; }
|
||||
};
|
||||
|
||||
class Derived: public Base {
|
||||
protected:
|
||||
int dImpl() { return 1; }
|
||||
public:
|
||||
float baz(float b) { return b + 1.0; }
|
||||
};
|
||||
|
||||
int main() {
|
||||
Derived d;
|
||||
return 0; // set breakpoint here
|
||||
}
|
Loading…
Reference in New Issue