Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lldb
diff options
context:
space:
mode:
authorMichael Buch <michaelbuch12@gmail.com>2022-10-27 13:09:22 +0300
committerMichael Buch <michaelbuch12@gmail.com>2022-10-31 15:25:18 +0300
commit76f34ed2837880c1865202f28988b01c93ac4f89 (patch)
treef614a6fe4033d33ea98408507dba92ff64eb18a8 /lldb
parentd0bf48c7b179027d978c479167e23825b8d0c4f6 (diff)
[lldb][CPlusPlus] Introduce CPlusPlusLanguage::MethodName::GetReturnType
This patch adds a way to extract the return type out of the `CPlusPlusNameParser`. This will be useful for cases where we want a function's basename *and* the return type but not the function arguments; this is currently not possible (the parser either gives us the full name or just the basename). Since the parser knows how to handle return types already we should just expose this to users that need it. **Testing** * Added unit-tests Differential Revision: https://reviews.llvm.org/D136935
Diffstat (limited to 'lldb')
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp9
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h21
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp47
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h1
-rw-r--r--lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp107
5 files changed, 129 insertions, 56 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index d4dfc4c0e1d2..3e94f555d3cd 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -109,6 +109,7 @@ void CPlusPlusLanguage::MethodName::Clear() {
m_context = llvm::StringRef();
m_arguments = llvm::StringRef();
m_qualifiers = llvm::StringRef();
+ m_return_type = llvm::StringRef();
m_parsed = false;
m_parse_error = false;
}
@@ -206,6 +207,7 @@ bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
m_basename = llvm::StringRef();
m_arguments = llvm::StringRef();
m_qualifiers = llvm::StringRef();
+ m_return_type = llvm::StringRef();
return false;
}
}
@@ -223,6 +225,7 @@ void CPlusPlusLanguage::MethodName::Parse() {
m_context = function.value().name.context;
m_arguments = function.value().arguments;
m_qualifiers = function.value().qualifiers;
+ m_return_type = function.value().return_type;
m_parse_error = false;
} else {
m_parse_error = true;
@@ -256,6 +259,12 @@ llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
return m_qualifiers;
}
+llvm::StringRef CPlusPlusLanguage::MethodName::GetReturnType() {
+ if (!m_parsed)
+ Parse();
+ return m_return_type;
+}
+
std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
if (!m_parsed)
Parse();
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 4d4226accd02..f9b3251374d0 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -55,7 +55,13 @@ public:
llvm::StringRef GetArguments();
llvm::StringRef GetQualifiers();
-
+
+ /// Returns the methods return-type.
+ ///
+ /// Currently returns an empty llvm::StringRef
+ /// if the return-type is a function pointer.
+ llvm::StringRef GetReturnType();
+
bool ContainsPath(llvm::StringRef path);
private:
@@ -78,12 +84,13 @@ public:
bool TrySimplifiedParse();
ConstString m_full; // Full name:
- // "lldb::SBTarget::GetBreakpointAtIndex(unsigned int)
- // const"
- llvm::StringRef 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"
+ // "size_t lldb::SBTarget::GetBreakpointAtIndex(unsigned
+ // int) const"
+ llvm::StringRef 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"
+ llvm::StringRef m_return_type; // Return type: "size_t"
bool m_parsed = false;
bool m_parse_error = false;
};
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index 427e5190846d..70d8652f40cf 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -105,10 +105,16 @@ clang::Token &CPlusPlusNameParser::Peek() {
Optional<ParsedFunction>
CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
Bookmark start_position = SetBookmark();
+
+ ParsedFunction result;
if (expect_return_type) {
+ size_t return_start = GetCurrentPosition();
// Consume return type if it's expected.
if (!ConsumeToken(tok::kw_auto) && !ConsumeTypename())
return None;
+
+ size_t return_end = GetCurrentPosition();
+ result.return_type = GetTextForRange(Range(return_start, return_end));
}
auto maybe_name = ParseFullNameImpl();
@@ -125,7 +131,6 @@ CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
SkipFunctionQualifiers();
size_t end_position = GetCurrentPosition();
- ParsedFunction result;
result.name.basename = GetTextForRange(maybe_name.value().basename_range);
result.name.context = GetTextForRange(maybe_name.value().context_range);
result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
@@ -136,6 +141,16 @@ CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
Optional<ParsedFunction>
CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
+ // This function parses a function definition
+ // that returns a pointer type.
+ // E.g., double (*(*func(long))(int))(float)
+
+ // Step 1:
+ // Remove the return type of the innermost
+ // function pointer type.
+ //
+ // Leaves us with:
+ // (*(*func(long))(int))(float)
Bookmark start_position = SetBookmark();
if (expect_return_type) {
// Consume return type.
@@ -143,11 +158,22 @@ CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
return None;
}
+ // Step 2:
+ //
+ // Skip a pointer and parenthesis pair.
+ //
+ // Leaves us with:
+ // (*func(long))(int))(float)
if (!ConsumeToken(tok::l_paren))
return None;
if (!ConsumePtrsAndRefs())
return None;
+ // Step 3:
+ //
+ // Consume inner function name. This will fail unless
+ // we stripped all the pointers on the left hand side
+ // of the funciton name.
{
Bookmark before_inner_function_pos = SetBookmark();
auto maybe_inner_function_name = ParseFunctionImpl(false);
@@ -161,6 +187,24 @@ CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
}
}
+ // Step 4:
+ //
+ // Parse the remaining string as a function pointer again.
+ // This time don't consume the inner-most typename since
+ // we're left with pointers only. This will strip another
+ // layer of pointers until we're left with the innermost
+ // function name/argument. I.e., func(long))(int))(float)
+ //
+ // Once we successfully stripped all pointers and gotten
+ // the innermost function name from ParseFunctionImpl above,
+ // we consume a single ')' and the arguments '(...)' that follows.
+ //
+ // Leaves us with:
+ // )(float)
+ //
+ // This is the remnant of the outer function pointers' arguments.
+ // Unwinding the recursive calls will remove the remaining
+ // arguments.
auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
if (maybe_inner_function_ptr_name)
if (ConsumeToken(tok::r_paren))
@@ -169,6 +213,7 @@ CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
start_position.Remove();
return maybe_inner_function_ptr_name;
}
+
return None;
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
index 9a85934e8d67..e931401bed5c 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
@@ -33,6 +33,7 @@ public:
ParsedName name;
llvm::StringRef arguments;
llvm::StringRef qualifiers;
+ llvm::StringRef return_type;
};
// Treats given text as a function definition and parses it.
diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
index 795c0fad153c..0a55238f9221 100644
--- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
+++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
@@ -17,130 +17,136 @@ using namespace lldb_private;
TEST(CPlusPlusLanguage, MethodNameParsing) {
struct TestCase {
std::string input;
- std::string context, basename, arguments, qualifiers, scope_qualified_name;
+ std::string return_type, context, basename, arguments, qualifiers,
+ scope_qualified_name;
};
TestCase test_cases[] = {
- {"main(int, char *[]) ", "", "main", "(int, char *[])", "", "main"},
- {"foo::bar(baz) const", "foo", "bar", "(baz)", "const", "foo::bar"},
- {"foo::~bar(baz)", "foo", "~bar", "(baz)", "", "foo::~bar"},
- {"a::b::c::d(e,f)", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},
- {"void f(int)", "", "f", "(int)", "", "f"},
+ {"main(int, char *[]) ", "", "", "main", "(int, char *[])", "", "main"},
+ {"foo::bar(baz) const", "", "foo", "bar", "(baz)", "const", "foo::bar"},
+ {"foo::~bar(baz)", "", "foo", "~bar", "(baz)", "", "foo::~bar"},
+ {"a::b::c::d(e,f)", "", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},
+ {"void f(int)", "void", "", "f", "(int)", "", "f"},
// Operators
{"std::basic_ostream<char, std::char_traits<char> >& "
- "std::operator<<<std::char_traits<char> >"
- "(std::basic_ostream<char, std::char_traits<char> >&, char const*)",
- "std", "operator<<<std::char_traits<char> >",
+ "std::operator<<<std::char_traits<char> >(std::basic_ostream<char, "
+ "std::char_traits<char> >&, char const*)",
+ "std::basic_ostream<char, std::char_traits<char> >&", "std",
+ "operator<<<std::char_traits<char> >",
"(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "",
"std::operator<<<std::char_traits<char> >"},
{"operator delete[](void*, clang::ASTContext const&, unsigned long)", "",
- "operator delete[]", "(void*, clang::ASTContext const&, unsigned long)",
- "", "operator delete[]"},
- {"llvm::Optional<clang::PostInitializer>::operator bool() const",
+ "", "operator delete[]",
+ "(void*, clang::ASTContext const&, unsigned long)", "",
+ "operator delete[]"},
+ {"llvm::Optional<clang::PostInitializer>::operator bool() const", "",
"llvm::Optional<clang::PostInitializer>", "operator bool", "()", "const",
"llvm::Optional<clang::PostInitializer>::operator bool"},
- {"(anonymous namespace)::FactManager::operator[](unsigned short)",
+ {"(anonymous namespace)::FactManager::operator[](unsigned short)", "",
"(anonymous namespace)::FactManager", "operator[]", "(unsigned short)",
"", "(anonymous namespace)::FactManager::operator[]"},
{"const int& std::map<int, pair<short, int>>::operator[](short) const",
- "std::map<int, pair<short, int>>", "operator[]", "(short)", "const",
- "std::map<int, pair<short, int>>::operator[]"},
- {"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)",
+ "const int&", "std::map<int, pair<short, int>>", "operator[]", "(short)",
+ "const", "std::map<int, pair<short, int>>::operator[]"},
+ {"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)", "",
"CompareInsn", "operator()", "(llvm::StringRef, InsnMatchEntry const&)",
"", "CompareInsn::operator()"},
- {"llvm::Optional<llvm::MCFixupKind>::operator*() const &",
+ {"llvm::Optional<llvm::MCFixupKind>::operator*() const &", "",
"llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const &",
"llvm::Optional<llvm::MCFixupKind>::operator*"},
{"auto std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char "
"const, 18ul>(char const (&) [18ul]) const",
- "std::__1::ranges::__begin::__fn",
+ "auto", "std::__1::ranges::__begin::__fn",
"operator()[abi:v160000]<char const, 18ul>", "(char const (&) [18ul])",
"const",
"std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char const, "
"18ul>"},
// Internal classes
- {"operator<<(Cls, Cls)::Subclass::function()",
+ {"operator<<(Cls, Cls)::Subclass::function()", "",
"operator<<(Cls, Cls)::Subclass", "function", "()", "",
"operator<<(Cls, Cls)::Subclass::function"},
- {"SAEC::checkFunction(context&) const::CallBack::CallBack(int)",
+ {"SAEC::checkFunction(context&) const::CallBack::CallBack(int)", "",
"SAEC::checkFunction(context&) const::CallBack", "CallBack", "(int)", "",
"SAEC::checkFunction(context&) const::CallBack::CallBack"},
// Anonymous namespace
- {"XX::(anonymous namespace)::anon_class::anon_func() const",
+ {"XX::(anonymous namespace)::anon_class::anon_func() const", "",
"XX::(anonymous namespace)::anon_class", "anon_func", "()", "const",
"XX::(anonymous namespace)::anon_class::anon_func"},
// Lambda
{"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() "
"const",
- "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",
+ "", "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",
"()", "const",
"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},
// Function pointers
- {"string (*f(vector<int>&&))(float)", "", "f", "(vector<int>&&)", "",
- "f"},
- {"void (*&std::_Any_data::_M_access<void (*)()>())()", "std::_Any_data",
- "_M_access<void (*)()>", "()", "",
+ {"string (*f(vector<int>&&))(float)", "", "", "f",
+ "(vector<int>&&)", "", "f"},
+ {"void (*&std::_Any_data::_M_access<void (*)()>())()", "",
+ "std::_Any_data", "_M_access<void (*)()>", "()", "",
"std::_Any_data::_M_access<void (*)()>"},
{"void (*(*(*(*(*(*(*(* const&func1(int))())())())())())())())()", "",
- "func1", "(int)", "", "func1"},
+ "", "func1", "(int)", "", "func1"},
// Decltype
{"decltype(nullptr)&& std::forward<decltype(nullptr)>"
"(std::remove_reference<decltype(nullptr)>::type&)",
- "std", "forward<decltype(nullptr)>",
+ "decltype(nullptr)&&", "std", "forward<decltype(nullptr)>",
"(std::remove_reference<decltype(nullptr)>::type&)", "",
"std::forward<decltype(nullptr)>"},
// Templates
{"void llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
"addPass<llvm::VP>(llvm::VP)",
- "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>", "addPass<llvm::VP>",
- "(llvm::VP)", "",
+ "void", "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>",
+ "addPass<llvm::VP>", "(llvm::VP)", "",
"llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
"addPass<llvm::VP>"},
{"void std::vector<Class, std::allocator<Class> >"
"::_M_emplace_back_aux<Class const&>(Class const&)",
- "std::vector<Class, std::allocator<Class> >",
+ "void", "std::vector<Class, std::allocator<Class> >",
"_M_emplace_back_aux<Class const&>", "(Class const&)", "",
"std::vector<Class, std::allocator<Class> >::"
"_M_emplace_back_aux<Class const&>"},
{"unsigned long llvm::countTrailingOnes<unsigned int>"
"(unsigned int, llvm::ZeroBehavior)",
- "llvm", "countTrailingOnes<unsigned int>",
+ "unsigned long", "llvm", "countTrailingOnes<unsigned int>",
"(unsigned int, llvm::ZeroBehavior)", "",
"llvm::countTrailingOnes<unsigned int>"},
{"std::enable_if<(10u)<(64), bool>::type llvm::isUInt<10u>(unsigned "
"long)",
- "llvm", "isUInt<10u>", "(unsigned long)", "", "llvm::isUInt<10u>"},
- {"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "",
+ "std::enable_if<(10u)<(64), bool>::type", "llvm", "isUInt<10u>",
+ "(unsigned long)", "", "llvm::isUInt<10u>"},
+ {"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "", "",
"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",
"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"},
- {"llvm::Optional<llvm::MCFixupKind>::operator*() const volatile &&",
+ {"llvm::Optional<llvm::MCFixupKind>::operator*() const volatile &&", "",
"llvm::Optional<llvm::MCFixupKind>", "operator*", "()",
"const volatile &&", "llvm::Optional<llvm::MCFixupKind>::operator*"},
- {"void foo<Dummy<char [10]>>()", "", "foo<Dummy<char [10]>>", "()", "",
- "foo<Dummy<char [10]>>"},
- {"void foo<Bar<Bar<int>[10]>>()", "", "foo<Bar<Bar<int>[10]>>", "()", "",
- "foo<Bar<Bar<int>[10]>>"},
- {"void foo<Bar[10]>()", "", "foo<Bar[10]>", "()", "",
+ {"void foo<Dummy<char [10]>>()", "void", "", "foo<Dummy<char [10]>>",
+ "()", "", "foo<Dummy<char [10]>>"},
+ {"void foo<Bar<Bar<int>[10]>>()", "void", "", "foo<Bar<Bar<int>[10]>>",
+ "()", "", "foo<Bar<Bar<int>[10]>>"},
+ {"void foo<Bar[10]>()", "void", "", "foo<Bar[10]>", "()", "",
"foo<Bar[10]>"},
- {"void foo<Bar[]>()", "", "foo<Bar[]>", "()", "",
- "foo<Bar[]>"},
+ {"void foo<Bar[]>()", "void", "", "foo<Bar[]>", "()", "", "foo<Bar[]>"},
// auto return type
- {"auto std::test_return_auto<int>() const", "std",
+ {"auto std::test_return_auto<int>() const", "auto", "std",
"test_return_auto<int>", "()", "const", "std::test_return_auto<int>"},
- {"decltype(auto) std::test_return_auto<int>(int) const", "std",
- "test_return_auto<int>", "(int)", "const", "std::test_return_auto<int>"},
+ {"decltype(auto) std::test_return_auto<int>(int) const", "decltype(auto)",
+ "std", "test_return_auto<int>", "(int)", "const",
+ "std::test_return_auto<int>"},
// abi_tag on class method
{"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>> "
"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>"
"::method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"
"int>>>(int, v1::v2::Dummy<int>) const &&",
+ // Return type
+ "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",
// Context
"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",
// Basename
@@ -158,6 +164,8 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
"v1::v2::with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]"
"<v1::v2::Dummy[abi:c1][abi:c2]<int>>>(int, v1::v2::Dummy<int>) const "
"&&",
+ // Return type
+ "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",
// Context
"v1::v2",
// Basename
@@ -173,6 +181,8 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
{"auto ns::with_tag_in_ns[abi:special tag,0.0][abi:special "
"tag,1.0]<Dummy<int>>"
"(float) const &&",
+ // Return type
+ "auto",
// Context
"ns",
// Basename
@@ -184,15 +194,15 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
"tag,1.0]<Dummy<int>>"},
// abi_tag on operator overloads
- {"std::__1::error_code::operator bool[abi:v160000]() const",
+ {"std::__1::error_code::operator bool[abi:v160000]() const", "",
"std::__1::error_code", "operator bool[abi:v160000]", "()", "const",
"std::__1::error_code::operator bool[abi:v160000]"},
- {"auto ns::foo::operator[][abi:v160000](size_t) const", "ns::foo",
+ {"auto ns::foo::operator[][abi:v160000](size_t) const", "auto", "ns::foo",
"operator[][abi:v160000]", "(size_t)", "const",
"ns::foo::operator[][abi:v160000]"},
- {"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &",
+ {"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &", "auto",
"Foo[abi:abc]<int>", "operator<<<Foo[abi:abc]<int>>", "(int)", "&",
"Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"}};
@@ -200,6 +210,7 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
CPlusPlusLanguage::MethodName method(ConstString(test.input));
EXPECT_TRUE(method.IsValid()) << test.input;
if (method.IsValid()) {
+ EXPECT_EQ(test.return_type, method.GetReturnType().str());
EXPECT_EQ(test.context, method.GetContext().str());
EXPECT_EQ(test.basename, method.GetBasename().str());
EXPECT_EQ(test.arguments, method.GetArguments().str());