mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
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:
@@ -89,6 +89,15 @@ public:
|
||||
lldb::SBType
|
||||
GetType ();
|
||||
|
||||
lldb::SBType
|
||||
GetReturnType ();
|
||||
|
||||
uint32_t
|
||||
GetNumberOfArguments ();
|
||||
|
||||
lldb::SBType
|
||||
GetArgumentTypeAtIndex (uint32_t);
|
||||
|
||||
lldb::MemberFunctionKind
|
||||
GetKind();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -86,6 +86,15 @@ public:
|
||||
lldb::SBType
|
||||
GetType ();
|
||||
|
||||
lldb::SBType
|
||||
GetReturnType ();
|
||||
|
||||
uint32_t
|
||||
GetNumberOfArguments ();
|
||||
|
||||
lldb::SBType
|
||||
GetArgumentTypeAtIndex (uint32_t);
|
||||
|
||||
lldb::MemberFunctionKind
|
||||
GetKind();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
LEVEL = ../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
OBJCXX_SOURCES := main.mm
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user