Michael137 updated this revision to Diff 471743.
Michael137 added a comment.
- Don't handle function-pointer return types for now
- Add more documentation
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D136935/new/
https://reviews.llvm.org/D136935
Files:
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
Index: lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
===================================================================
--- lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
+++ lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
@@ -17,130 +17,136 @@
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 @@
"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 @@
{"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 @@
"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 @@
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());
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
@@ -33,6 +33,7 @@
ParsedName name;
llvm::StringRef arguments;
llvm::StringRef qualifiers;
+ llvm::StringRef return_type;
};
// Treats given text as a function definition and parses it.
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -105,10 +105,16 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ // 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 @@
start_position.Remove();
return maybe_inner_function_ptr_name;
}
+
return None;
}
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -55,7 +55,13 @@
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 @@
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;
};
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -109,6 +109,7 @@
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 @@
m_basename = llvm::StringRef();
m_arguments = llvm::StringRef();
m_qualifiers = llvm::StringRef();
+ m_return_type = llvm::StringRef();
return false;
}
}
@@ -223,6 +225,7 @@
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 @@
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();
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits