[Lldb-commits] [lldb] 76f34ed - [lldb][CPlusPlus] Introduce CPlusPlusLanguage::MethodName::GetReturnType

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 31 05:25:41 PDT 2022


Author: Michael Buch
Date: 2022-10-31T12:25:18Z
New Revision: 76f34ed2837880c1865202f28988b01c93ac4f89

URL: https://github.com/llvm/llvm-project/commit/76f34ed2837880c1865202f28988b01c93ac4f89
DIFF: https://github.com/llvm/llvm-project/commit/76f34ed2837880c1865202f28988b01c93ac4f89.diff

LOG: [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

Added: 
    

Modified: 
    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

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index d4dfc4c0e1d2e..3e94f555d3cda 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 4d4226accd02b..f9b3251374d0e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -55,7 +55,13 @@ class CPlusPlusLanguage : public Language {
     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 @@ class CPlusPlusLanguage : public Language {
     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 427e5190846d0..70d8652f40cff 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 9a85934e8d670..e931401bed5ca 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
@@ -33,6 +33,7 @@ class CPlusPlusNameParser {
     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 795c0fad153c0..0a55238f92210 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());


        


More information about the lldb-commits mailing list