tberghammer created this revision.
tberghammer added a reviewer: clayborg.
tberghammer added a subscriber: lldb-commits.
Herald added a subscriber: mgorny.

Improve Type::GetTypeScopeAndBasenameHelper and add unit tests

      

Previously it failed to handle nested types inside templated classes
making it impossible to look up these types using the fully qualified
name.


https://reviews.llvm.org/D28466

Files:
  source/Symbol/Type.cpp
  unittests/Symbol/CMakeLists.txt
  unittests/Symbol/TestType.cpp

Index: unittests/Symbol/TestType.cpp
===================================================================
--- /dev/null
+++ unittests/Symbol/TestType.cpp
@@ -0,0 +1,51 @@
+//===-- TestType.cpp --------------------------------------------*- C++ -*-===//
+//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Symbol/Type.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+void TestGetTypeScopeAndBasenameHelper(const char *full_type,
+                                       bool expected_is_scoped,
+                                       const char *expected_scope,
+                                       const char *expected_name) {
+  std::string scope, name;
+  lldb::TypeClass type_class;
+  bool is_scoped =
+      Type::GetTypeScopeAndBasename(full_type, scope, name, type_class);
+  EXPECT_EQ(is_scoped, expected_is_scoped);
+  if (expected_is_scoped) {
+    EXPECT_EQ(scope, expected_scope);
+    EXPECT_EQ(name, expected_name);
+  }
+}
+};
+
+TEST(Type, GetTypeScopeAndBasename) {
+  TestGetTypeScopeAndBasenameHelper("int", false, "", "");
+  TestGetTypeScopeAndBasenameHelper("std::string", true, "std::", "string");
+  TestGetTypeScopeAndBasenameHelper("std::set<int>", true, "std::", "set<int>");
+  TestGetTypeScopeAndBasenameHelper("std::set<int, std::less<int>>", true,
+                                    "std::", "set<int, std::less<int>>");
+  TestGetTypeScopeAndBasenameHelper("std::string::iterator", true,
+                                    "std::string::", "iterator");
+  TestGetTypeScopeAndBasenameHelper("std::set<int>::iterator", true,
+                                    "std::set<int>::", "iterator");
+  TestGetTypeScopeAndBasenameHelper(
+      "std::set<int, std::less<int>>::iterator", true,
+      "std::set<int, std::less<int>>::", "iterator");
+  TestGetTypeScopeAndBasenameHelper(
+      "std::set<int, std::less<int>>::iterator<bool>", true,
+      "std::set<int, std::less<int>>::", "iterator<bool>");
+}
Index: unittests/Symbol/CMakeLists.txt
===================================================================
--- unittests/Symbol/CMakeLists.txt
+++ unittests/Symbol/CMakeLists.txt
@@ -1,3 +1,4 @@
 add_lldb_unittest(SymbolTests
   TestClangASTContext.cpp
+  TestType.cpp
   )
Index: source/Symbol/Type.cpp
===================================================================
--- source/Symbol/Type.cpp
+++ source/Symbol/Type.cpp
@@ -623,47 +623,62 @@
 bool Type::GetTypeScopeAndBasename(const char *&name_cstr, std::string &scope,
                                    std::string &basename,
                                    TypeClass &type_class) {
+  type_class = eTypeClassAny;
+
   // Protect against null c string.
+  if (!name_cstr || !name_cstr[0])
+    return false;
 
-  type_class = eTypeClassAny;
+  llvm::StringRef name_strref(name_cstr);
+  if (name_strref.startswith("struct ")) {
+    name_cstr += 7;
+    type_class = eTypeClassStruct;
+  } else if (name_strref.startswith("class ")) {
+    name_cstr += 6;
+    type_class = eTypeClassClass;
+  } else if (name_strref.startswith("union ")) {
+    name_cstr += 6;
+    type_class = eTypeClassUnion;
+  } else if (name_strref.startswith("enum ")) {
+    name_cstr += 5;
+    type_class = eTypeClassEnumeration;
+  } else if (name_strref.startswith("typedef ")) {
+    name_cstr += 8;
+    type_class = eTypeClassTypedef;
+  }
 
-  if (name_cstr && name_cstr[0]) {
-    llvm::StringRef name_strref(name_cstr);
-    if (name_strref.startswith("struct ")) {
-      name_cstr += 7;
-      type_class = eTypeClassStruct;
-    } else if (name_strref.startswith("class ")) {
-      name_cstr += 6;
-      type_class = eTypeClassClass;
-    } else if (name_strref.startswith("union ")) {
-      name_cstr += 6;
-      type_class = eTypeClassUnion;
-    } else if (name_strref.startswith("enum ")) {
-      name_cstr += 5;
-      type_class = eTypeClassEnumeration;
-    } else if (name_strref.startswith("typedef ")) {
-      name_cstr += 8;
-      type_class = eTypeClassTypedef;
-    }
-    const char *basename_cstr = name_cstr;
-    const char *namespace_separator = ::strstr(basename_cstr, "::");
-    if (namespace_separator) {
-      const char *template_arg_char = ::strchr(basename_cstr, '<');
-      while (namespace_separator != nullptr) {
-        if (template_arg_char &&
-            namespace_separator > template_arg_char) // but namespace'd template
-                                                     // arguments are still good
-                                                     // to go
-          break;
-        basename_cstr = namespace_separator + 2;
-        namespace_separator = strstr(basename_cstr, "::");
-      }
-      if (basename_cstr > name_cstr) {
-        scope.assign(name_cstr, basename_cstr - name_cstr);
-        basename.assign(basename_cstr);
-        return true;
+  const char *basename_cstr = name_cstr;
+  const char *namespace_separator = ::strstr(basename_cstr, "::");
+  const char *template_arg_char = ::strchr(basename_cstr, '<');
+  if (!namespace_separator)
+    return false;
+
+  while (namespace_separator) {
+    if (template_arg_char && namespace_separator > template_arg_char) {
+      const char *template_end = template_arg_char + 1;
+      size_t template_depth = 1;
+      while (template_depth > 0 && *template_end) {
+        if (*template_end == '<')
+          template_depth++;
+        else if (*template_end == '>')
+          template_depth--;
+        template_end++;
       }
+      if (template_depth != 0)
+        return false; // We have an invalid type name. Bail out.
+      if (!template_end[0])
+        break; // The template ends at the end of the full name.
+      basename_cstr = template_end;
+    } else {
+      basename_cstr = namespace_separator + 2;
     }
+    namespace_separator = strstr(basename_cstr, "::");
+    template_arg_char = ::strchr(basename_cstr, '<');
+  }
+  if (basename_cstr > name_cstr) {
+    scope.assign(name_cstr, basename_cstr - name_cstr);
+    basename.assign(basename_cstr);
+    return true;
   }
   return false;
 }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to