Skip to content

Commit 5d575e6

Browse files
committed
[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 (cherry picked from commit 76f34ed)
1 parent 70f1307 commit 5d575e6

File tree

5 files changed

+136
-50
lines changed

5 files changed

+136
-50
lines changed

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ void CPlusPlusLanguage::MethodName::Clear() {
109109
m_context = llvm::StringRef();
110110
m_arguments = llvm::StringRef();
111111
m_qualifiers = llvm::StringRef();
112+
m_return_type = llvm::StringRef();
112113
m_parsed = false;
113114
m_parse_error = false;
114115
}
@@ -206,6 +207,7 @@ bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
206207
m_basename = llvm::StringRef();
207208
m_arguments = llvm::StringRef();
208209
m_qualifiers = llvm::StringRef();
210+
m_return_type = llvm::StringRef();
209211
return false;
210212
}
211213
}
@@ -223,6 +225,7 @@ void CPlusPlusLanguage::MethodName::Parse() {
223225
m_context = function.value().name.context;
224226
m_arguments = function.value().arguments;
225227
m_qualifiers = function.value().qualifiers;
228+
m_return_type = function.value().return_type;
226229
m_parse_error = false;
227230
} else {
228231
m_parse_error = true;
@@ -256,6 +259,12 @@ llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
256259
return m_qualifiers;
257260
}
258261

262+
llvm::StringRef CPlusPlusLanguage::MethodName::GetReturnType() {
263+
if (!m_parsed)
264+
Parse();
265+
return m_return_type;
266+
}
267+
259268
std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
260269
if (!m_parsed)
261270
Parse();

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ class CPlusPlusLanguage : public Language {
5555
llvm::StringRef GetArguments();
5656

5757
llvm::StringRef GetQualifiers();
58-
58+
59+
/// Returns the methods return-type.
60+
///
61+
/// Currently returns an empty llvm::StringRef
62+
/// if the return-type is a function pointer.
63+
llvm::StringRef GetReturnType();
64+
5965
bool ContainsPath(llvm::StringRef path);
6066

6167
private:
@@ -78,12 +84,13 @@ class CPlusPlusLanguage : public Language {
7884
bool TrySimplifiedParse();
7985

8086
ConstString m_full; // Full name:
81-
// "lldb::SBTarget::GetBreakpointAtIndex(unsigned int)
82-
// const"
83-
llvm::StringRef m_basename; // Basename: "GetBreakpointAtIndex"
84-
llvm::StringRef m_context; // Decl context: "lldb::SBTarget"
85-
llvm::StringRef m_arguments; // Arguments: "(unsigned int)"
86-
llvm::StringRef m_qualifiers; // Qualifiers: "const"
87+
// "size_t lldb::SBTarget::GetBreakpointAtIndex(unsigned
88+
// int) const"
89+
llvm::StringRef m_basename; // Basename: "GetBreakpointAtIndex"
90+
llvm::StringRef m_context; // Decl context: "lldb::SBTarget"
91+
llvm::StringRef m_arguments; // Arguments: "(unsigned int)"
92+
llvm::StringRef m_qualifiers; // Qualifiers: "const"
93+
llvm::StringRef m_return_type; // Return type: "size_t"
8794
bool m_parsed = false;
8895
bool m_parse_error = false;
8996
};

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,16 @@ clang::Token &CPlusPlusNameParser::Peek() {
105105
Optional<ParsedFunction>
106106
CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
107107
Bookmark start_position = SetBookmark();
108+
109+
ParsedFunction result;
108110
if (expect_return_type) {
111+
size_t return_start = GetCurrentPosition();
109112
// Consume return type if it's expected.
110113
if (!ConsumeToken(tok::kw_auto) && !ConsumeTypename())
111114
return None;
115+
116+
size_t return_end = GetCurrentPosition();
117+
result.return_type = GetTextForRange(Range(return_start, return_end));
112118
}
113119

114120
auto maybe_name = ParseFullNameImpl();
@@ -125,7 +131,6 @@ CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
125131
SkipFunctionQualifiers();
126132
size_t end_position = GetCurrentPosition();
127133

128-
ParsedFunction result;
129134
result.name.basename = GetTextForRange(maybe_name.value().basename_range);
130135
result.name.context = GetTextForRange(maybe_name.value().context_range);
131136
result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
@@ -136,18 +141,39 @@ CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
136141

137142
Optional<ParsedFunction>
138143
CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
144+
// This function parses a function definition
145+
// that returns a pointer type.
146+
// E.g., double (*(*func(long))(int))(float)
147+
148+
// Step 1:
149+
// Remove the return type of the innermost
150+
// function pointer type.
151+
//
152+
// Leaves us with:
153+
// (*(*func(long))(int))(float)
139154
Bookmark start_position = SetBookmark();
140155
if (expect_return_type) {
141156
// Consume return type.
142157
if (!ConsumeTypename())
143158
return None;
144159
}
145160

161+
// Step 2:
162+
//
163+
// Skip a pointer and parenthesis pair.
164+
//
165+
// Leaves us with:
166+
// (*func(long))(int))(float)
146167
if (!ConsumeToken(tok::l_paren))
147168
return None;
148169
if (!ConsumePtrsAndRefs())
149170
return None;
150171

172+
// Step 3:
173+
//
174+
// Consume inner function name. This will fail unless
175+
// we stripped all the pointers on the left hand side
176+
// of the funciton name.
151177
{
152178
Bookmark before_inner_function_pos = SetBookmark();
153179
auto maybe_inner_function_name = ParseFunctionImpl(false);
@@ -161,6 +187,24 @@ CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
161187
}
162188
}
163189

190+
// Step 4:
191+
//
192+
// Parse the remaining string as a function pointer again.
193+
// This time don't consume the inner-most typename since
194+
// we're left with pointers only. This will strip another
195+
// layer of pointers until we're left with the innermost
196+
// function name/argument. I.e., func(long))(int))(float)
197+
//
198+
// Once we successfully stripped all pointers and gotten
199+
// the innermost function name from ParseFunctionImpl above,
200+
// we consume a single ')' and the arguments '(...)' that follows.
201+
//
202+
// Leaves us with:
203+
// )(float)
204+
//
205+
// This is the remnant of the outer function pointers' arguments.
206+
// Unwinding the recursive calls will remove the remaining
207+
// arguments.
164208
auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
165209
if (maybe_inner_function_ptr_name)
166210
if (ConsumeToken(tok::r_paren))
@@ -169,6 +213,7 @@ CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
169213
start_position.Remove();
170214
return maybe_inner_function_ptr_name;
171215
}
216+
172217
return None;
173218
}
174219

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class CPlusPlusNameParser {
3333
ParsedName name;
3434
llvm::StringRef arguments;
3535
llvm::StringRef qualifiers;
36+
llvm::StringRef return_type;
3637
};
3738

3839
// Treats given text as a function definition and parses it.

lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,117 +17,136 @@ using namespace lldb_private;
1717
TEST(CPlusPlusLanguage, MethodNameParsing) {
1818
struct TestCase {
1919
std::string input;
20-
std::string context, basename, arguments, qualifiers, scope_qualified_name;
20+
std::string return_type, context, basename, arguments, qualifiers,
21+
scope_qualified_name;
2122
};
2223

2324
TestCase test_cases[] = {
24-
{"main(int, char *[]) ", "", "main", "(int, char *[])", "", "main"},
25-
{"foo::bar(baz) const", "foo", "bar", "(baz)", "const", "foo::bar"},
26-
{"foo::~bar(baz)", "foo", "~bar", "(baz)", "", "foo::~bar"},
27-
{"a::b::c::d(e,f)", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},
28-
{"void f(int)", "", "f", "(int)", "", "f"},
25+
{"main(int, char *[]) ", "", "", "main", "(int, char *[])", "", "main"},
26+
{"foo::bar(baz) const", "", "foo", "bar", "(baz)", "const", "foo::bar"},
27+
{"foo::~bar(baz)", "", "foo", "~bar", "(baz)", "", "foo::~bar"},
28+
{"a::b::c::d(e,f)", "", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},
29+
{"void f(int)", "void", "", "f", "(int)", "", "f"},
2930

3031
// Operators
3132
{"std::basic_ostream<char, std::char_traits<char> >& "
32-
"std::operator<<<std::char_traits<char> >"
33-
"(std::basic_ostream<char, std::char_traits<char> >&, char const*)",
34-
"std", "operator<<<std::char_traits<char> >",
33+
"std::operator<<<std::char_traits<char> >(std::basic_ostream<char, "
34+
"std::char_traits<char> >&, char const*)",
35+
"std::basic_ostream<char, std::char_traits<char> >&", "std",
36+
"operator<<<std::char_traits<char> >",
3537
"(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "",
3638
"std::operator<<<std::char_traits<char> >"},
3739
{"operator delete[](void*, clang::ASTContext const&, unsigned long)", "",
38-
"operator delete[]", "(void*, clang::ASTContext const&, unsigned long)",
39-
"", "operator delete[]"},
40-
{"llvm::Optional<clang::PostInitializer>::operator bool() const",
40+
"", "operator delete[]",
41+
"(void*, clang::ASTContext const&, unsigned long)", "",
42+
"operator delete[]"},
43+
{"llvm::Optional<clang::PostInitializer>::operator bool() const", "",
4144
"llvm::Optional<clang::PostInitializer>", "operator bool", "()", "const",
4245
"llvm::Optional<clang::PostInitializer>::operator bool"},
43-
{"(anonymous namespace)::FactManager::operator[](unsigned short)",
46+
{"(anonymous namespace)::FactManager::operator[](unsigned short)", "",
4447
"(anonymous namespace)::FactManager", "operator[]", "(unsigned short)",
4548
"", "(anonymous namespace)::FactManager::operator[]"},
4649
{"const int& std::map<int, pair<short, int>>::operator[](short) const",
47-
"std::map<int, pair<short, int>>", "operator[]", "(short)", "const",
48-
"std::map<int, pair<short, int>>::operator[]"},
49-
{"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)",
50+
"const int&", "std::map<int, pair<short, int>>", "operator[]", "(short)",
51+
"const", "std::map<int, pair<short, int>>::operator[]"},
52+
{"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)", "",
5053
"CompareInsn", "operator()", "(llvm::StringRef, InsnMatchEntry const&)",
5154
"", "CompareInsn::operator()"},
52-
{"llvm::Optional<llvm::MCFixupKind>::operator*() const &",
55+
{"llvm::Optional<llvm::MCFixupKind>::operator*() const &", "",
5356
"llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const &",
5457
"llvm::Optional<llvm::MCFixupKind>::operator*"},
58+
{"auto std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char "
59+
"const, 18ul>(char const (&) [18ul]) const",
60+
"auto", "std::__1::ranges::__begin::__fn",
61+
"operator()[abi:v160000]<char const, 18ul>", "(char const (&) [18ul])",
62+
"const",
63+
"std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char const, "
64+
"18ul>"},
5565
// Internal classes
56-
{"operator<<(Cls, Cls)::Subclass::function()",
66+
{"operator<<(Cls, Cls)::Subclass::function()", "",
5767
"operator<<(Cls, Cls)::Subclass", "function", "()", "",
5868
"operator<<(Cls, Cls)::Subclass::function"},
59-
{"SAEC::checkFunction(context&) const::CallBack::CallBack(int)",
69+
{"SAEC::checkFunction(context&) const::CallBack::CallBack(int)", "",
6070
"SAEC::checkFunction(context&) const::CallBack", "CallBack", "(int)", "",
6171
"SAEC::checkFunction(context&) const::CallBack::CallBack"},
6272
// Anonymous namespace
63-
{"XX::(anonymous namespace)::anon_class::anon_func() const",
73+
{"XX::(anonymous namespace)::anon_class::anon_func() const", "",
6474
"XX::(anonymous namespace)::anon_class", "anon_func", "()", "const",
6575
"XX::(anonymous namespace)::anon_class::anon_func"},
6676

6777
// Lambda
6878
{"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() "
6979
"const",
70-
"main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",
80+
"", "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",
7181
"()", "const",
7282
"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},
7383

7484
// Function pointers
75-
{"string (*f(vector<int>&&))(float)", "", "f", "(vector<int>&&)", "",
76-
"f"},
77-
{"void (*&std::_Any_data::_M_access<void (*)()>())()", "std::_Any_data",
78-
"_M_access<void (*)()>", "()", "",
85+
{"string (*f(vector<int>&&))(float)", "", "", "f",
86+
"(vector<int>&&)", "", "f"},
87+
{"void (*&std::_Any_data::_M_access<void (*)()>())()", "",
88+
"std::_Any_data", "_M_access<void (*)()>", "()", "",
7989
"std::_Any_data::_M_access<void (*)()>"},
8090
{"void (*(*(*(*(*(*(*(* const&func1(int))())())())())())())())()", "",
81-
"func1", "(int)", "", "func1"},
91+
"", "func1", "(int)", "", "func1"},
8292

8393
// Decltype
8494
{"decltype(nullptr)&& std::forward<decltype(nullptr)>"
8595
"(std::remove_reference<decltype(nullptr)>::type&)",
86-
"std", "forward<decltype(nullptr)>",
96+
"decltype(nullptr)&&", "std", "forward<decltype(nullptr)>",
8797
"(std::remove_reference<decltype(nullptr)>::type&)", "",
8898
"std::forward<decltype(nullptr)>"},
8999

90100
// Templates
91101
{"void llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
92102
"addPass<llvm::VP>(llvm::VP)",
93-
"llvm::PM<llvm::Module, llvm::AM<llvm::Module>>", "addPass<llvm::VP>",
94-
"(llvm::VP)", "",
103+
"void", "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>",
104+
"addPass<llvm::VP>", "(llvm::VP)", "",
95105
"llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
96106
"addPass<llvm::VP>"},
97107
{"void std::vector<Class, std::allocator<Class> >"
98108
"::_M_emplace_back_aux<Class const&>(Class const&)",
99-
"std::vector<Class, std::allocator<Class> >",
109+
"void", "std::vector<Class, std::allocator<Class> >",
100110
"_M_emplace_back_aux<Class const&>", "(Class const&)", "",
101111
"std::vector<Class, std::allocator<Class> >::"
102112
"_M_emplace_back_aux<Class const&>"},
103113
{"unsigned long llvm::countTrailingOnes<unsigned int>"
104114
"(unsigned int, llvm::ZeroBehavior)",
105-
"llvm", "countTrailingOnes<unsigned int>",
115+
"unsigned long", "llvm", "countTrailingOnes<unsigned int>",
106116
"(unsigned int, llvm::ZeroBehavior)", "",
107117
"llvm::countTrailingOnes<unsigned int>"},
108118
{"std::enable_if<(10u)<(64), bool>::type llvm::isUInt<10u>(unsigned "
109119
"long)",
110-
"llvm", "isUInt<10u>", "(unsigned long)", "", "llvm::isUInt<10u>"},
111-
{"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "",
120+
"std::enable_if<(10u)<(64), bool>::type", "llvm", "isUInt<10u>",
121+
"(unsigned long)", "", "llvm::isUInt<10u>"},
122+
{"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "", "",
112123
"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",
113124
"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"},
114-
{"llvm::Optional<llvm::MCFixupKind>::operator*() const volatile &&",
125+
{"llvm::Optional<llvm::MCFixupKind>::operator*() const volatile &&", "",
115126
"llvm::Optional<llvm::MCFixupKind>", "operator*", "()",
116127
"const volatile &&", "llvm::Optional<llvm::MCFixupKind>::operator*"},
117-
{"void foo<Dummy<char [10]>>()", "", "foo<Dummy<char [10]>>", "()", "",
118-
"foo<Dummy<char [10]>>"},
128+
{"void foo<Dummy<char [10]>>()", "void", "", "foo<Dummy<char [10]>>",
129+
"()", "", "foo<Dummy<char [10]>>"},
130+
{"void foo<Bar<Bar<int>[10]>>()", "void", "", "foo<Bar<Bar<int>[10]>>",
131+
"()", "", "foo<Bar<Bar<int>[10]>>"},
132+
{"void foo<Bar[10]>()", "void", "", "foo<Bar[10]>", "()", "",
133+
"foo<Bar[10]>"},
134+
{"void foo<Bar[]>()", "void", "", "foo<Bar[]>", "()", "", "foo<Bar[]>"},
119135

120136
// auto return type
121-
{"auto std::test_return_auto<int>() const", "std",
137+
{"auto std::test_return_auto<int>() const", "auto", "std",
122138
"test_return_auto<int>", "()", "const", "std::test_return_auto<int>"},
123-
{"decltype(auto) std::test_return_auto<int>(int) const", "std",
124-
"test_return_auto<int>", "(int)", "const", "std::test_return_auto<int>"},
139+
{"decltype(auto) std::test_return_auto<int>(int) const", "decltype(auto)",
140+
"std", "test_return_auto<int>", "(int)", "const",
141+
"std::test_return_auto<int>"},
125142

126143
// abi_tag on class method
127144
{"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>> "
128145
"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>"
129146
"::method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"
130147
"int>>>(int, v1::v2::Dummy<int>) const &&",
148+
// Return type
149+
"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",
131150
// Context
132151
"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",
133152
// Basename
@@ -145,6 +164,8 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
145164
"v1::v2::with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]"
146165
"<v1::v2::Dummy[abi:c1][abi:c2]<int>>>(int, v1::v2::Dummy<int>) const "
147166
"&&",
167+
// Return type
168+
"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",
148169
// Context
149170
"v1::v2",
150171
// Basename
@@ -160,6 +181,8 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
160181
{"auto ns::with_tag_in_ns[abi:special tag,0.0][abi:special "
161182
"tag,1.0]<Dummy<int>>"
162183
"(float) const &&",
184+
// Return type
185+
"auto",
163186
// Context
164187
"ns",
165188
// Basename
@@ -171,15 +194,15 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
171194
"tag,1.0]<Dummy<int>>"},
172195

173196
// abi_tag on operator overloads
174-
{"std::__1::error_code::operator bool[abi:v160000]() const",
197+
{"std::__1::error_code::operator bool[abi:v160000]() const", "",
175198
"std::__1::error_code", "operator bool[abi:v160000]", "()", "const",
176199
"std::__1::error_code::operator bool[abi:v160000]"},
177200

178-
{"auto ns::foo::operator[][abi:v160000](size_t) const", "ns::foo",
201+
{"auto ns::foo::operator[][abi:v160000](size_t) const", "auto", "ns::foo",
179202
"operator[][abi:v160000]", "(size_t)", "const",
180203
"ns::foo::operator[][abi:v160000]"},
181204

182-
{"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &",
205+
{"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &", "auto",
183206
"Foo[abi:abc]<int>", "operator<<<Foo[abi:abc]<int>>", "(int)", "&",
184207
"Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"},
185208

@@ -191,6 +214,7 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
191214
CPlusPlusLanguage::MethodName method(ConstString(test.input));
192215
EXPECT_TRUE(method.IsValid()) << test.input;
193216
if (method.IsValid()) {
217+
EXPECT_EQ(test.return_type, method.GetReturnType().str());
194218
EXPECT_EQ(test.context, method.GetContext().str());
195219
EXPECT_EQ(test.basename, method.GetBasename().str());
196220
EXPECT_EQ(test.arguments, method.GetArguments().str());

0 commit comments

Comments
 (0)