friss created this revision.
friss added reviewers: jingham, clayborg.
Herald added a subscriber: JDevlieghere.

When looking at template arguments in LLDB, we usually care about what
the user passed in his code, not whether some of those arguments where
passed as a variadic parameter pack.

This patch extends all the C++ APIs to look at template parameters to
take an additional 'expand_pack' boolean that automatically unwraps the
potential argument packs. The equivalent SBAPI calls have been changed
to pass true for this parameter.

A byproduct of the patch is to also fix the support for template type
that have only a parameter pack as argument (like the OnlyPack type in
the test). Those were not recognized as template instanciations before.

The added test verifies that the SBAPI is able to iterate over the
arguments of a variadic template.


https://reviews.llvm.org/D51387

Files:
  include/lldb/Symbol/ClangASTContext.h
  include/lldb/Symbol/CompilerType.h
  include/lldb/Symbol/GoASTContext.h
  include/lldb/Symbol/JavaASTContext.h
  include/lldb/Symbol/OCamlASTContext.h
  include/lldb/Symbol/TypeSystem.h
  
packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
  packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/main.cpp
  source/API/SBType.cpp
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
  source/Symbol/ClangASTContext.cpp
  source/Symbol/CompilerType.cpp
  source/Symbol/JavaASTContext.cpp
  source/Symbol/TypeSystem.cpp

Index: source/Symbol/TypeSystem.cpp
===================================================================
--- source/Symbol/TypeSystem.cpp
+++ source/Symbol/TypeSystem.cpp
@@ -102,18 +102,19 @@
 }
 
 TemplateArgumentKind
-TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx) {
+TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx,
+                                    bool expand_pack) {
   return eTemplateArgumentKindNull;
 }
 
 CompilerType TypeSystem::GetTypeTemplateArgument(opaque_compiler_type_t type,
-                                                 size_t idx) {
+                                                 size_t idx, bool expand_pack) {
   return CompilerType();
 }
 
 llvm::Optional<CompilerType::IntegralTemplateArgument>
-TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type,
-                                        size_t idx) {
+TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type, size_t idx,
+                                        bool expand_pack) {
   return llvm::None;
 }
 
Index: source/Symbol/JavaASTContext.cpp
===================================================================
--- source/Symbol/JavaASTContext.cpp
+++ source/Symbol/JavaASTContext.cpp
@@ -879,7 +879,8 @@
 }
 
 size_t
-JavaASTContext::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
+JavaASTContext::GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
+                                        bool expand_pack) {
   return 0;
 }
 
Index: source/Symbol/CompilerType.cpp
===================================================================
--- source/Symbol/CompilerType.cpp
+++ source/Symbol/CompilerType.cpp
@@ -680,30 +680,32 @@
   return 0;
 }
 
-size_t CompilerType::GetNumTemplateArguments() const {
+size_t CompilerType::GetNumTemplateArguments(bool expand_pack) const {
   if (IsValid()) {
-    return m_type_system->GetNumTemplateArguments(m_type);
+    return m_type_system->GetNumTemplateArguments(m_type, expand_pack);
   }
   return 0;
 }
 
-TemplateArgumentKind CompilerType::GetTemplateArgumentKind(size_t idx) const {
+TemplateArgumentKind
+CompilerType::GetTemplateArgumentKind(size_t idx, bool expand_pack) const {
   if (IsValid())
-    return m_type_system->GetTemplateArgumentKind(m_type, idx);
+    return m_type_system->GetTemplateArgumentKind(m_type, idx, expand_pack);
   return eTemplateArgumentKindNull;
 }
 
-CompilerType CompilerType::GetTypeTemplateArgument(size_t idx) const {
+CompilerType CompilerType::GetTypeTemplateArgument(size_t idx,
+                                                   bool expand_pack) const {
   if (IsValid()) {
-    return m_type_system->GetTypeTemplateArgument(m_type, idx);
+    return m_type_system->GetTypeTemplateArgument(m_type, idx, expand_pack);
   }
   return CompilerType();
 }
 
 llvm::Optional<CompilerType::IntegralTemplateArgument>
-CompilerType::GetIntegralTemplateArgument(size_t idx) const {
+CompilerType::GetIntegralTemplateArgument(size_t idx, bool expand_pack) const {
   if (IsValid())
-    return m_type_system->GetIntegralTemplateArgument(m_type, idx);
+    return m_type_system->GetIntegralTemplateArgument(m_type, idx, expand_pack);
   return llvm::None;
 }
 
Index: source/Symbol/ClangASTContext.cpp
===================================================================
--- source/Symbol/ClangASTContext.cpp
+++ source/Symbol/ClangASTContext.cpp
@@ -7546,7 +7546,8 @@
 }
 
 size_t
-ClangASTContext::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
+ClangASTContext::GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
+                                         bool expand_pack) {
   if (!type)
     return 0;
 
@@ -7561,8 +7562,16 @@
         const clang::ClassTemplateSpecializationDecl *template_decl =
             llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
                 cxx_record_decl);
-        if (template_decl)
-          return template_decl->getTemplateArgs().size();
+        if (template_decl) {
+          const auto &template_arg_list = template_decl->getTemplateArgs();
+          int num_args = template_arg_list.size();
+          if (expand_pack) {
+            auto &pack = template_arg_list[num_args - 1];
+            if (pack.getKind() == clang::TemplateArgument::Pack)
+              num_args += pack.pack_size() - 1;
+          }
+          return num_args;
+        }
       }
     }
     break;
@@ -7644,15 +7653,37 @@
   }
 }
 
+const TemplateArgument *
+GetNthTemplateArgument(const clang::ClassTemplateSpecializationDecl *decl,
+                       int idx, bool expand_pack) {
+  const auto &args = decl->getTemplateArgs();
+
+  if (idx < args.size() - 1)
+    return &args[idx];
+
+  assert(args.size() &&
+         "We shouldn't have a template specialization without any args");
+  if (!expand_pack ||
+      args[args.size() - 1].getKind() != clang::TemplateArgument::Pack)
+    return idx >= args.size() ? nullptr : &args[idx];
+
+  const auto &pack = args[args.size() - 1];
+  return &pack.pack_elements()[idx - (args.size() - 1)];
+}
+
 lldb::TemplateArgumentKind
 ClangASTContext::GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
-                                         size_t arg_idx) {
+                                         size_t arg_idx, bool expand_pack) {
   const clang::ClassTemplateSpecializationDecl *template_decl =
       GetAsTemplateSpecialization(type);
-  if (! template_decl || arg_idx >= template_decl->getTemplateArgs().size())
+  if (!template_decl)
+    return eTemplateArgumentKindNull;
+
+  const auto *arg = GetNthTemplateArgument(template_decl, arg_idx, expand_pack);
+  if (!arg)
     return eTemplateArgumentKindNull;
 
-  switch (template_decl->getTemplateArgs()[arg_idx].getKind()) {
+  switch (arg->getKind()) {
   case clang::TemplateArgument::Null:
     return eTemplateArgumentKindNull;
 
@@ -7685,35 +7716,33 @@
 
 CompilerType
 ClangASTContext::GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
-                                         size_t idx) {
+                                         size_t idx, bool expand_pack) {
   const clang::ClassTemplateSpecializationDecl *template_decl =
       GetAsTemplateSpecialization(type);
-  if (!template_decl || idx >= template_decl->getTemplateArgs().size())
+  if (!template_decl)
     return CompilerType();
 
-  const clang::TemplateArgument &template_arg =
-      template_decl->getTemplateArgs()[idx];
-  if (template_arg.getKind() != clang::TemplateArgument::Type)
+  const auto *arg = GetNthTemplateArgument(template_decl, idx, expand_pack);
+  if (!arg || arg->getKind() != clang::TemplateArgument::Type)
     return CompilerType();
 
-  return CompilerType(getASTContext(), template_arg.getAsType());
+  return CompilerType(getASTContext(), arg->getAsType());
 }
 
 llvm::Optional<CompilerType::IntegralTemplateArgument>
 ClangASTContext::GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
-                                             size_t idx) {
+                                             size_t idx, bool expand_pack) {
   const clang::ClassTemplateSpecializationDecl *template_decl =
       GetAsTemplateSpecialization(type);
-  if (! template_decl || idx >= template_decl->getTemplateArgs().size())
+  if (!template_decl)
     return llvm::None;
 
-  const clang::TemplateArgument &template_arg =
-      template_decl->getTemplateArgs()[idx];
-  if (template_arg.getKind() != clang::TemplateArgument::Integral)
+  const auto *arg = GetNthTemplateArgument(template_decl, idx, expand_pack);
+  if (!arg || arg->getKind() != clang::TemplateArgument::Integral)
     return llvm::None;
 
-  return {{template_arg.getAsIntegral(),
-           CompilerType(getASTContext(), template_arg.getIntegralType())}};
+  return {{arg->getAsIntegral(),
+           CompilerType(getASTContext(), arg->getIntegralType())}};
 }
 
 CompilerType ClangASTContext::GetTypeForFormatters(void *type) {
Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2089,9 +2089,8 @@
       break;
     }
   }
-  if (template_param_infos.args.empty())
-    return false;
-  return template_param_infos.args.size() == template_param_infos.names.size();
+
+  return template_param_infos.IsValid();
 }
 
 bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die,
Index: source/API/SBType.cpp
===================================================================
--- source/API/SBType.cpp
+++ source/API/SBType.cpp
@@ -409,23 +409,27 @@
 }
 
 uint32_t SBType::GetNumberOfTemplateArguments() {
+  bool expand_pack = true;
   if (IsValid())
-    return m_opaque_sp->GetCompilerType(false).GetNumTemplateArguments();
+    return m_opaque_sp->GetCompilerType(false).GetNumTemplateArguments(
+        expand_pack);
   return 0;
 }
 
 lldb::SBType SBType::GetTemplateArgumentType(uint32_t idx) {
   if (!IsValid())
     return SBType();
 
   CompilerType type;
+  bool expand_pack = true;
   switch(GetTemplateArgumentKind(idx)) {
     case eTemplateArgumentKindType:
-      type = m_opaque_sp->GetCompilerType(false).GetTypeTemplateArgument(idx);
+      type = m_opaque_sp->GetCompilerType(false).GetTypeTemplateArgument(
+          idx, expand_pack);
       break;
     case eTemplateArgumentKindIntegral:
       type = m_opaque_sp->GetCompilerType(false)
-                 .GetIntegralTemplateArgument(idx)
+                 .GetIntegralTemplateArgument(idx, expand_pack)
                  ->type;
       break;
     default:
@@ -437,8 +441,10 @@
 }
 
 lldb::TemplateArgumentKind SBType::GetTemplateArgumentKind(uint32_t idx) {
+  bool expand_pack = true;
   if (IsValid())
-    return m_opaque_sp->GetCompilerType(false).GetTemplateArgumentKind(idx);
+    return m_opaque_sp->GetCompilerType(false).GetTemplateArgumentKind(
+        idx, expand_pack);
   return eTemplateArgumentKindNull;
 }
 
Index: packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/main.cpp
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/main.cpp
+++ packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/main.cpp
@@ -35,8 +35,12 @@
   bool isIntBool() { return true; }
 };
 
+template <typename... Args> struct OnlyPack {};
+
 int main (int argc, char const *argv[])
 {
+    OnlyPack<int, char, double, D<int, int, bool>> onlyPack;
+
     C<int,16,32> myC;
     C<int,16> myLesserC;
     myC.member = 64;
@@ -52,7 +56,7 @@
     D<int,int> myLesserD;
     myD.member = 64;
     (void)D<int,int,bool>().isIntBool();
-    (void)D<int,int>().isIntBool();
+    (void)D<int,int>().isIntBool(); // breakpoint here
     return myD.member != 64;	//% self.expect("expression -- myD", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["64"])
                                 //% self.expect("expression -- D<int, int>().isIntBool()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["false"])
                                 //% self.expect("expression -- D<int, int, bool>().isIntBool()", DATA_TYPES_DISPLAYED_CORRECTLY, substrs = ["true"])
Index: packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
@@ -0,0 +1,34 @@
+"""
+Test that the type of arguments to C++ template classes that have variadic
+parameters can be enumerated.
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TemplatePackArgsTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def test_template_argument_pack(self):
+        self.build()
+        (_, _, thread, _) = lldbutil.run_to_source_breakpoint(self,
+          'breakpoint here', lldb.SBFileSpec('main.cpp'), exe_name = 'a.out')
+        frame = thread.GetSelectedFrame()
+
+        only_pack = frame.FindVariable('onlyPack')
+        self.assertTrue(only_pack.IsValid(),
+                        'make sure we find the onlyPack variable')
+        self.assertEqual(only_pack.GetType().GetNumberOfTemplateArguments(), 4)
+        self.assertEqual(only_pack.GetType().GetTemplateArgumentType(0).GetName(), 'int')
+        self.assertEqual(only_pack.GetType().GetTemplateArgumentType(1).GetName(), 'char')
+        self.assertEqual(only_pack.GetType().GetTemplateArgumentType(2).GetName(), 'double')
+        # Access the C<double, 42> template parameter.
+        nested_template = only_pack.GetType().GetTemplateArgumentType(3)
+        self.assertEqual(nested_template.GetName(), 'D<int, int, bool>')
+        self.assertEqual(nested_template.GetNumberOfTemplateArguments(), 3)
+        self.assertEqual(nested_template.GetTemplateArgumentType(0).GetName(), 'int')
+        self.assertEqual(nested_template.GetTemplateArgumentType(1).GetName(), 'int')
+        self.assertEqual(nested_template.GetTemplateArgumentType(2).GetName(), 'bool')
Index: include/lldb/Symbol/TypeSystem.h
===================================================================
--- include/lldb/Symbol/TypeSystem.h
+++ include/lldb/Symbol/TypeSystem.h
@@ -347,14 +347,18 @@
                                 const char *name, bool omit_empty_base_classes,
                                 std::vector<uint32_t> &child_indexes) = 0;
 
-  virtual size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) = 0;
+  virtual size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
+                                         bool expand_pack = false) = 0;
 
   virtual lldb::TemplateArgumentKind
-  GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, size_t idx);
-  virtual CompilerType GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
-                                           size_t idx);
+  GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, size_t idx,
+                          bool expand_pack = false);
+  virtual CompilerType
+  GetTypeTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
+                          bool expand_pack = false);
   virtual llvm::Optional<CompilerType::IntegralTemplateArgument>
-  GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx);
+  GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
+                              bool expand_pack = false);
 
   //----------------------------------------------------------------------
   // Dumping types
Index: include/lldb/Symbol/OCamlASTContext.h
===================================================================
--- include/lldb/Symbol/OCamlASTContext.h
+++ include/lldb/Symbol/OCamlASTContext.h
@@ -227,7 +227,8 @@
                                 const char *name, bool omit_empty_base_classes,
                                 std::vector<uint32_t> &child_indexes) override;
 
-  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override {
+  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
+                                 bool expand_pack) override {
     return 0;
   }
 
Index: include/lldb/Symbol/JavaASTContext.h
===================================================================
--- include/lldb/Symbol/JavaASTContext.h
+++ include/lldb/Symbol/JavaASTContext.h
@@ -201,7 +201,8 @@
 
   unsigned GetTypeQualifiers(lldb::opaque_compiler_type_t type) override;
 
-  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
+  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
+                                 bool expand_pack) override;
 
   int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override;
 
Index: include/lldb/Symbol/GoASTContext.h
===================================================================
--- include/lldb/Symbol/GoASTContext.h
+++ include/lldb/Symbol/GoASTContext.h
@@ -310,7 +310,8 @@
                                 const char *name, bool omit_empty_base_classes,
                                 std::vector<uint32_t> &child_indexes) override;
 
-  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override {
+  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
+                                 bool expand_pack) override {
     return 0;
   }
 
Index: include/lldb/Symbol/CompilerType.h
===================================================================
--- include/lldb/Symbol/CompilerType.h
+++ include/lldb/Symbol/CompilerType.h
@@ -364,14 +364,16 @@
   GetIndexOfChildMemberWithName(const char *name, bool omit_empty_base_classes,
                                 std::vector<uint32_t> &child_indexes) const;
 
-  size_t GetNumTemplateArguments() const;
+  size_t GetNumTemplateArguments(bool expand_pack = false) const;
 
-  lldb::TemplateArgumentKind GetTemplateArgumentKind(size_t idx) const;
-  CompilerType GetTypeTemplateArgument(size_t idx) const;
+  lldb::TemplateArgumentKind
+  GetTemplateArgumentKind(size_t idx, bool expand_pack = false) const;
+  CompilerType GetTypeTemplateArgument(size_t idx,
+                                       bool expand_pack = false) const;
 
   // Returns the value of the template argument and its type.
   llvm::Optional<IntegralTemplateArgument>
-  GetIntegralTemplateArgument(size_t idx) const;
+  GetIntegralTemplateArgument(size_t idx, bool expand_pack = false) const;
 
   CompilerType GetTypeForFormatters() const;
 
Index: include/lldb/Symbol/ClangASTContext.h
===================================================================
--- include/lldb/Symbol/ClangASTContext.h
+++ include/lldb/Symbol/ClangASTContext.h
@@ -277,11 +277,11 @@
   class TemplateParameterInfos {
   public:
     bool IsValid() const {
-      if (args.empty())
+      if (args.empty() && (!packed_args || packed_args->args.empty()))
         return false;
       return args.size() == names.size() &&
-        ((bool)pack_name == (bool)packed_args) &&
-        (!packed_args || !packed_args->packed_args);
+             ((bool)pack_name == (bool)packed_args) &&
+             (!packed_args || !packed_args->args.empty());
     }
 
     llvm::SmallVector<const char *, 2> names;
@@ -784,16 +784,17 @@
                                 const char *name, bool omit_empty_base_classes,
                                 std::vector<uint32_t> &child_indexes) override;
 
-  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
+  size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
+                                 bool expand_pack = false) override;
 
   lldb::TemplateArgumentKind
-  GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
-                          size_t idx) override;
+  GetTemplateArgumentKind(lldb::opaque_compiler_type_t type, size_t idx,
+                          bool expand_pack) override;
   CompilerType GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
-                                       size_t idx) override;
+                                       size_t idx, bool expand_pack) override;
   llvm::Optional<CompilerType::IntegralTemplateArgument>
-  GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
-                              size_t idx) override;
+  GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
+                              bool expand_pack) override;
 
   CompilerType GetTypeForFormatters(void *type) override;
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to