Extend the member function discovery APIs to also support Objective-C as well as C++

For the Objective-C case, we do not have a "function type" notion, so we actually end up wrapping the clang ObjCMethodDecl in the Impl object, and ask function-y questions of it
In general, you can always ask for return type, number of arguments, and type of each argument using the TypeMemberFunction layer - but in the C++ case, you can also acquire a Type object for the function itself, which instead you can't do in the Objective-C case

llvm-svn: 218132
This commit is contained in:
Enrico Granata
2014-09-19 18:21:05 +00:00
parent 4505f3a73d
commit 47caf9a956
10 changed files with 288 additions and 28 deletions

View File

@@ -89,6 +89,15 @@ public:
lldb::SBType
GetType ();
lldb::SBType
GetReturnType ();
uint32_t
GetNumberOfArguments ();
lldb::SBType
GetArgumentTypeAtIndex (uint32_t);
lldb::MemberFunctionKind
GetKind();

View File

@@ -162,7 +162,7 @@ public:
GetNumberOfFunctionArguments () const;
ClangASTType
GetFunctionArgumentAtIndex (const size_t index);
GetFunctionArgumentAtIndex (const size_t index) const;
bool
IsVariadicFunctionType () const;
@@ -329,7 +329,7 @@ public:
GetFunctionArgumentCount () const;
ClangASTType
GetFunctionArgumentTypeAtIndex (size_t idx);
GetFunctionArgumentTypeAtIndex (size_t idx) const;
ClangASTType
GetFunctionReturnType () const;
@@ -337,10 +337,8 @@ public:
size_t
GetNumMemberFunctions () const;
ClangASTType
GetMemberFunctionAtIndex (size_t idx,
std::string& name,
lldb::MemberFunctionKind& kind);
TypeMemberFunctionImpl
GetMemberFunctionAtIndex (size_t idx);
ClangASTType
GetLValueReferenceType () const;

View File

@@ -816,6 +816,7 @@ class TypeMemberFunctionImpl
public:
TypeMemberFunctionImpl() :
m_type(),
m_objc_method_decl(nullptr),
m_name(),
m_kind(lldb::eMemberFunctionKindUnknown)
{
@@ -825,13 +826,25 @@ public:
const std::string& name,
const lldb::MemberFunctionKind& kind) :
m_type(type),
m_objc_method_decl(nullptr),
m_name(name),
m_kind(kind)
{
}
TypeMemberFunctionImpl (clang::ObjCMethodDecl *method,
const std::string& name,
const lldb::MemberFunctionKind& kind) :
m_type(),
m_objc_method_decl(method),
m_name(name),
m_kind(kind)
{
}
TypeMemberFunctionImpl (const TypeMemberFunctionImpl& rhs) :
m_type(rhs.m_type),
m_objc_method_decl(rhs.m_objc_method_decl),
m_name(rhs.m_name),
m_kind(rhs.m_kind)
{
@@ -849,14 +862,28 @@ public:
ClangASTType
GetType () const;
ClangASTType
GetReturnType () const;
size_t
GetNumArguments () const;
ClangASTType
GetArgumentAtIndex (size_t idx) const;
lldb::MemberFunctionKind
GetKind () const;
bool
GetDescription (Stream& stream);
protected:
std::string
GetPrintableTypeName ();
private:
ClangASTType m_type;
clang::ObjCMethodDecl *m_objc_method_decl;
ConstString m_name;
lldb::MemberFunctionKind m_kind;
};

View File

@@ -86,6 +86,15 @@ public:
lldb::SBType
GetType ();
lldb::SBType
GetReturnType ();
uint32_t
GetNumberOfArguments ();
lldb::SBType
GetArgumentTypeAtIndex (uint32_t);
lldb::MemberFunctionKind
GetKind();

View File

@@ -267,12 +267,7 @@ SBType::GetMemberFunctionAtIndex (uint32_t idx)
{
SBTypeMemberFunction sb_func_type;
if (IsValid())
{
lldb::MemberFunctionKind kind;
std::string name;
ClangASTType func_type(m_opaque_sp->GetClangASTType(true).GetMemberFunctionAtIndex(idx,name,kind));
sb_func_type.reset(new TypeMemberFunctionImpl(func_type,name,kind));
}
sb_func_type.reset(new TypeMemberFunctionImpl(m_opaque_sp->GetClangASTType(true).GetMemberFunctionAtIndex(idx)));
return sb_func_type;
}
@@ -754,7 +749,36 @@ SBTypeMemberFunction::GetType ()
sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetType())));
}
return sb_type;
}
lldb::SBType
SBTypeMemberFunction::GetReturnType ()
{
SBType sb_type;
if (m_opaque_sp)
{
sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetReturnType())));
}
return sb_type;
}
uint32_t
SBTypeMemberFunction::GetNumberOfArguments ()
{
if (m_opaque_sp)
return m_opaque_sp->GetNumArguments();
return 0;
}
lldb::SBType
SBTypeMemberFunction::GetArgumentTypeAtIndex (uint32_t i)
{
SBType sb_type;
if (m_opaque_sp)
{
sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetArgumentAtIndex(i))));
}
return sb_type;
}
lldb::MemberFunctionKind

View File

@@ -516,7 +516,7 @@ ClangASTType::GetNumberOfFunctionArguments () const
}
ClangASTType
ClangASTType::GetFunctionArgumentAtIndex (const size_t index)
ClangASTType::GetFunctionArgumentAtIndex (const size_t index) const
{
if (IsValid())
{
@@ -1714,7 +1714,7 @@ ClangASTType::GetFunctionArgumentCount () const
}
ClangASTType
ClangASTType::GetFunctionArgumentTypeAtIndex (size_t idx)
ClangASTType::GetFunctionArgumentTypeAtIndex (size_t idx) const
{
if (IsValid())
{
@@ -1759,8 +1759,45 @@ ClangASTType::GetNumMemberFunctions () const
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;
}
break;
case clang::Type::ObjCObjectPointer:
if (GetCompleteType())
{
const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
if (objc_class_type)
{
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
if (class_interface_decl)
num_functions = std::distance(class_interface_decl->meth_begin(), class_interface_decl->meth_end());
}
}
break;
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface:
if (GetCompleteType())
{
const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
if (objc_class_type)
{
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
num_functions = std::distance(class_interface_decl->meth_begin(), class_interface_decl->meth_end());
}
}
break;
case clang::Type::Typedef:
return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumMemberFunctions();
case clang::Type::Elaborated:
return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetNumMemberFunctions();
case clang::Type::Paren:
return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetNumMemberFunctions();
default:
break;
@@ -1769,11 +1806,13 @@ ClangASTType::GetNumMemberFunctions () const
return num_functions;
}
ClangASTType
ClangASTType::GetMemberFunctionAtIndex (size_t idx,
std::string& name,
lldb::MemberFunctionKind& kind)
TypeMemberFunctionImpl
ClangASTType::GetMemberFunctionAtIndex (size_t idx)
{
std::string name("");
MemberFunctionKind kind(MemberFunctionKind::eMemberFunctionKindUnknown);
ClangASTType type{};
clang::ObjCMethodDecl *method_decl(nullptr);
if (IsValid())
{
clang::QualType qual_type(GetCanonicalQualType());
@@ -1807,18 +1846,94 @@ ClangASTType::GetMemberFunctionAtIndex (size_t idx,
kind = lldb::eMemberFunctionKindDestructor;
else
kind = lldb::eMemberFunctionKindInstanceMethod;
return ClangASTType(m_ast,method_decl->getType().getAsOpaquePtr());
type = ClangASTType(m_ast,method_decl->getType().getAsOpaquePtr());
}
}
}
}
break;
case clang::Type::ObjCObjectPointer:
if (GetCompleteType())
{
const clang::ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
if (objc_class_type)
{
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
if (class_interface_decl)
{
auto method_iter = class_interface_decl->meth_begin();
auto method_end = class_interface_decl->meth_end();
if (idx < static_cast<size_t>(std::distance(method_iter, method_end)))
{
std::advance(method_iter, idx);
method_decl = method_iter->getCanonicalDecl();
if (method_decl)
{
name = method_decl->getSelector().getAsString();
if (method_decl->isClassMethod())
kind = lldb::eMemberFunctionKindStaticMethod;
else
kind = lldb::eMemberFunctionKindInstanceMethod;
}
}
}
}
}
break;
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface:
if (GetCompleteType())
{
const clang::ObjCObjectType *objc_class_type = llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
if (objc_class_type)
{
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
auto method_iter = class_interface_decl->meth_begin();
auto method_end = class_interface_decl->meth_end();
if (idx < static_cast<size_t>(std::distance(method_iter, method_end)))
{
std::advance(method_iter, idx);
method_decl = method_iter->getCanonicalDecl();
if (method_decl)
{
name = method_decl->getSelector().getAsString();
if (method_decl->isClassMethod())
kind = lldb::eMemberFunctionKindStaticMethod;
else
kind = lldb::eMemberFunctionKindInstanceMethod;
}
}
}
}
}
break;
case clang::Type::Typedef:
return ClangASTType (m_ast, llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetMemberFunctionAtIndex(idx);
case clang::Type::Elaborated:
return ClangASTType (m_ast, llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType()).GetMemberFunctionAtIndex(idx);
case clang::Type::Paren:
return ClangASTType (m_ast, llvm::cast<clang::ParenType>(qual_type)->desugar()).GetMemberFunctionAtIndex(idx);
default:
break;
}
}
return ClangASTType();
if (kind == eMemberFunctionKindUnknown)
return TypeMemberFunctionImpl();
if (method_decl)
return TypeMemberFunctionImpl(method_decl, name, kind);
if (type)
return TypeMemberFunctionImpl(type, name, kind);
return TypeMemberFunctionImpl();
}
ClangASTType

View File

@@ -31,6 +31,7 @@
#include "llvm/ADT/StringRef.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
using namespace lldb;
using namespace lldb_private;
@@ -1297,6 +1298,7 @@ TypeMemberFunctionImpl::operator = (const TypeMemberFunctionImpl& rhs)
if (this != &rhs)
{
m_type = rhs.m_type;
m_objc_method_decl = rhs.m_objc_method_decl;
m_name = rhs.m_name;
m_kind = rhs.m_kind;
}
@@ -1327,6 +1329,21 @@ TypeMemberFunctionImpl::GetKind () const
return m_kind;
}
std::string
TypeMemberFunctionImpl::GetPrintableTypeName ()
{
if (m_type)
return m_type.GetTypeName().AsCString("<unknown>");
if (m_objc_method_decl)
{
if (m_objc_method_decl->getClassInterface())
{
return m_objc_method_decl->getClassInterface()->getName();
}
}
return "<unknown>";
}
bool
TypeMemberFunctionImpl::GetDescription (Stream& stream)
{
@@ -1334,25 +1351,58 @@ TypeMemberFunctionImpl::GetDescription (Stream& stream)
case lldb::eMemberFunctionKindUnknown:
return false;
case lldb::eMemberFunctionKindConstructor:
stream.Printf("constructor for %s", m_type.GetTypeName().AsCString());
stream.Printf("constructor for %s", GetPrintableTypeName().c_str());
break;
case lldb::eMemberFunctionKindDestructor:
stream.Printf("destructor for %s", m_type.GetTypeName().AsCString());
stream.Printf("destructor for %s", GetPrintableTypeName().c_str());
break;
case lldb::eMemberFunctionKindInstanceMethod:
stream.Printf("instance method %s of type %s",
m_name.AsCString(),
m_type.GetTypeName().AsCString());
GetPrintableTypeName().c_str());
break;
case lldb::eMemberFunctionKindStaticMethod:
stream.Printf("static method %s of type %s",
m_name.AsCString(),
m_type.GetTypeName().AsCString());
GetPrintableTypeName().c_str());
break;
}
return true;
}
ClangASTType
TypeMemberFunctionImpl::GetReturnType () const
{
if (m_type)
return m_type.GetFunctionReturnType();
if (m_objc_method_decl)
return ClangASTType(&m_objc_method_decl->getASTContext(),m_objc_method_decl->getReturnType().getAsOpaquePtr());
return ClangASTType();
}
size_t
TypeMemberFunctionImpl::GetNumArguments () const
{
if (m_type)
return m_type.GetNumberOfFunctionArguments();
if (m_objc_method_decl)
return m_objc_method_decl->param_size();
return 0;
}
ClangASTType
TypeMemberFunctionImpl::GetArgumentAtIndex (size_t idx) const
{
if (m_type)
return m_type.GetFunctionArgumentAtIndex (idx);
if (m_objc_method_decl)
{
if (idx < m_objc_method_decl->param_size())
return ClangASTType(&m_objc_method_decl->getASTContext(), m_objc_method_decl->parameters()[idx]->getOriginalType().getAsOpaquePtr());
}
return ClangASTType();
}
TypeEnumMemberImpl::TypeEnumMemberImpl (const clang::EnumConstantDecl* enum_member_decl,
const lldb_private::ClangASTType& integer_type) :
m_integer_type_sp(),

View File

@@ -1,5 +1,5 @@
LEVEL = ../../make
CXX_SOURCES := main.cpp
OBJCXX_SOURCES := main.mm
include $(LEVEL)/Makefile.rules

View File

@@ -37,7 +37,7 @@ class SBTypeMemberFunctionsTest(TestBase):
# 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.source = 'main.mm'
self.line = line_number(self.source, '// set breakpoint here')
def type_api(self, exe_name):
@@ -76,6 +76,15 @@ class SBTypeMemberFunctionsTest(TestBase):
self.assertTrue(Base.GetMemberFunctionAtIndex(2).GetType().GetFunctionArgumentTypes().GetSize() == 0, "Base::dat takes no arguments")
self.assertTrue(Base.GetMemberFunctionAtIndex(1).GetType().GetFunctionArgumentTypes().GetTypeAtIndex(1).GetName() == "char", "Base::bar takes a second 'char' argument")
self.assertTrue(Base.GetMemberFunctionAtIndex(1).GetName() == "bar", "Base::bar not found")
variable = frame0.FindVariable("thingy")
Thingy = variable.GetType()
self.assertTrue(Thingy.GetNumberOfMemberFunctions() == 2, "Thingy declares two methods")
self.assertTrue(Thingy.GetMemberFunctionAtIndex(0).GetReturnType().GetName() == "id", "Thingy::init returns an id")
self.assertTrue(Thingy.GetMemberFunctionAtIndex(1).GetNumberOfArguments() == 2, "Thingy::foo takes two arguments")
self.assertTrue(Thingy.GetMemberFunctionAtIndex(1).GetArgumentTypeAtIndex(0).GetName() == "int", "Thingy::foo takes an int")
if __name__ == '__main__':
import atexit

View File

@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
#import <Foundation/Foundation.h>
class Base {
public:
int foo(int x, int y) { return 1; }
@@ -22,7 +24,24 @@ public:
float baz(float b) { return b + 1.0; }
};
@interface Thingy: NSObject {
}
- (id)init;
- (id)fooWithBar: (int)bar andBaz:(id)baz;
@end
@implementation Thingy {
}
- (id)init {
return (self = [super init]);
}
- (id)fooWithBar: (int)bar andBaz:(id)baz {
return nil;
}
@end
int main() {
Derived d;
Thingy *thingy = [[Thingy alloc] init];
return 0; // set breakpoint here
}