Author: Michael Buch
Date: 2025-04-25T10:04:27+01:00
New Revision: 8b91b44a3be680788f914af72f38f90d35925c23

URL: 
https://github.com/llvm/llvm-project/commit/8b91b44a3be680788f914af72f38f90d35925c23
DIFF: 
https://github.com/llvm/llvm-project/commit/8b91b44a3be680788f914af72f38f90d35925c23.diff

LOG: [lldb][Format] Introduce new frame-format variables for function parts 
(#131836)

Adds new frame-format variables and implements them in the CPlusPlusLanguage 
plugin.

We use the `DemangledNameInfo` type to retrieve the necessary part of the 
demangled name.

https://github.com/llvm/llvm-project/pull/131836

Added: 
    lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
    lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test

Modified: 
    lldb/include/lldb/Core/FormatEntity.h
    lldb/include/lldb/Symbol/SymbolContext.h
    lldb/include/lldb/Target/Language.h
    lldb/source/Core/FormatEntity.cpp
    lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
    lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
    lldb/source/Symbol/SymbolContext.cpp
    lldb/test/Shell/Settings/TestFrameFormatName.test

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/FormatEntity.h 
b/lldb/include/lldb/Core/FormatEntity.h
index f6c3bd981e03a..31a08b3e4add0 100644
--- a/lldb/include/lldb/Core/FormatEntity.h
+++ b/lldb/include/lldb/Core/FormatEntity.h
@@ -88,6 +88,13 @@ struct Entry {
     FunctionNameWithArgs,
     FunctionNameNoArgs,
     FunctionMangledName,
+    FunctionScope,
+    FunctionBasename,
+    FunctionTemplateArguments,
+    FunctionFormattedArguments,
+    FunctionReturnLeft,
+    FunctionReturnRight,
+    FunctionQualifiers,
     FunctionAddrOffset,
     FunctionAddrOffsetConcrete,
     FunctionLineOffset,

diff  --git a/lldb/include/lldb/Symbol/SymbolContext.h 
b/lldb/include/lldb/Symbol/SymbolContext.h
index 4f8405f1f0db5..af2f694e554de 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -311,8 +311,7 @@ class SymbolContext {
   /// mangling preference. If this object represents an inlined function,
   /// returns the name of the inlined function. Returns nullptr if no function
   /// name could be determined.
-  const char *GetPossiblyInlinedFunctionName(
-      Mangled::NamePreference mangling_preference) const;
+  Mangled GetPossiblyInlinedFunctionName() const;
 
   // Member variables
   lldb::TargetSP target_sp; ///< The Target for a given query

diff  --git a/lldb/include/lldb/Target/Language.h 
b/lldb/include/lldb/Target/Language.h
index fa856843871e3..94ace6433df2f 100644
--- a/lldb/include/lldb/Target/Language.h
+++ b/lldb/include/lldb/Target/Language.h
@@ -15,6 +15,7 @@
 #include <set>
 #include <vector>
 
+#include "lldb/Core/FormatEntity.h"
 #include "lldb/Core/Highlighter.h"
 #include "lldb/Core/PluginInterface.h"
 #include "lldb/DataFormatters/DumpValueObjectOptions.h"
@@ -371,6 +372,13 @@ class Language : public PluginInterface {
                                       FunctionNameRepresentation 
representation,
                                       Stream &s);
 
+  virtual bool HandleFrameFormatVariable(const SymbolContext &sc,
+                                         const ExecutionContext *exe_ctx,
+                                         FormatEntity::Entry::Type type,
+                                         Stream &s) {
+    return false;
+  }
+
   virtual ConstString
   GetDemangledFunctionNameWithoutArguments(Mangled mangled) const {
     if (ConstString demangled = mangled.GetDemangledName())

diff  --git a/lldb/source/Core/FormatEntity.cpp 
b/lldb/source/Core/FormatEntity.cpp
index 874478340003c..eafc8c932208c 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -122,7 +122,15 @@ constexpr Definition g_function_child_entries[] = {
     Definition("pc-offset", EntryType::FunctionPCOffset),
     Definition("initial-function", EntryType::FunctionInitial),
     Definition("changed", EntryType::FunctionChanged),
-    Definition("is-optimized", EntryType::FunctionIsOptimized)};
+    Definition("is-optimized", EntryType::FunctionIsOptimized),
+    Definition("scope", EntryType::FunctionScope),
+    Definition("basename", EntryType::FunctionBasename),
+    Definition("template-arguments", EntryType::FunctionTemplateArguments),
+    Definition("formatted-arguments", EntryType::FunctionFormattedArguments),
+    Definition("return-left", EntryType::FunctionReturnLeft),
+    Definition("return-right", EntryType::FunctionReturnRight),
+    Definition("qualifiers", EntryType::FunctionQualifiers),
+};
 
 constexpr Definition g_line_child_entries[] = {
     Entry::DefinitionWithChildren("file", EntryType::LineEntryFile,
@@ -353,6 +361,13 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
     ENUM_TO_CSTR(FunctionNameWithArgs);
     ENUM_TO_CSTR(FunctionNameNoArgs);
     ENUM_TO_CSTR(FunctionMangledName);
+    ENUM_TO_CSTR(FunctionScope);
+    ENUM_TO_CSTR(FunctionBasename);
+    ENUM_TO_CSTR(FunctionTemplateArguments);
+    ENUM_TO_CSTR(FunctionFormattedArguments);
+    ENUM_TO_CSTR(FunctionReturnLeft);
+    ENUM_TO_CSTR(FunctionReturnRight);
+    ENUM_TO_CSTR(FunctionQualifiers);
     ENUM_TO_CSTR(FunctionAddrOffset);
     ENUM_TO_CSTR(FunctionAddrOffsetConcrete);
     ENUM_TO_CSTR(FunctionLineOffset);
@@ -1167,8 +1182,9 @@ static bool PrintFunctionNameWithArgs(Stream &s,
   ExecutionContextScope *exe_scope =
       exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
 
-  const char *cstr =
-      sc.GetPossiblyInlinedFunctionName(Mangled::ePreferDemangled);
+  const char *cstr = sc.GetPossiblyInlinedFunctionName()
+                         .GetName(Mangled::ePreferDemangled)
+                         .AsCString();
   if (!cstr)
     return false;
 
@@ -1186,7 +1202,8 @@ static bool PrintFunctionNameWithArgs(Stream &s,
   return true;
 }
 
-static bool HandleFunctionNameWithArgs(Stream &s,const ExecutionContext 
*exe_ctx,
+static bool HandleFunctionNameWithArgs(Stream &s,
+                                       const ExecutionContext *exe_ctx,
                                        const SymbolContext &sc) {
   Language *language_plugin = nullptr;
   bool language_plugin_handled = false;
@@ -1711,8 +1728,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
       return true;
     }
 
-    const char *name = sc->GetPossiblyInlinedFunctionName(
-        Mangled::NamePreference::ePreferDemangled);
+    const char *name = sc->GetPossiblyInlinedFunctionName()
+                           .GetName(Mangled::NamePreference::ePreferDemangled)
+                           .AsCString();
     if (!name)
       return false;
 
@@ -1743,8 +1761,10 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
       return true;
     }
 
-    const char *name = sc->GetPossiblyInlinedFunctionName(
-        Mangled::NamePreference::ePreferDemangledWithoutArguments);
+    const char *name =
+        sc->GetPossiblyInlinedFunctionName()
+            .GetName(Mangled::NamePreference::ePreferDemangledWithoutArguments)
+            .AsCString();
     if (!name)
       return false;
 
@@ -1753,19 +1773,38 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
     return true;
   }
 
+  case Entry::Type::FunctionScope:
+  case Entry::Type::FunctionBasename:
+  case Entry::Type::FunctionTemplateArguments:
+  case Entry::Type::FunctionFormattedArguments:
+  case Entry::Type::FunctionReturnRight:
+  case Entry::Type::FunctionReturnLeft:
+  case Entry::Type::FunctionQualifiers: {
+    if (!sc->function)
+      return false;
+
+    Language *language_plugin =
+        Language::FindPlugin(sc->function->GetLanguage());
+    if (!language_plugin)
+      return false;
+
+    return language_plugin->HandleFrameFormatVariable(*sc, exe_ctx, entry.type,
+                                                      s);
+  }
+
   case Entry::Type::FunctionNameWithArgs: {
     if (!sc)
       return false;
 
     return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
   }
-
   case Entry::Type::FunctionMangledName: {
     if (!sc)
       return false;
 
-    const char *name = sc->GetPossiblyInlinedFunctionName(
-        Mangled::NamePreference::ePreferMangled);
+    const char *name = sc->GetPossiblyInlinedFunctionName()
+                           .GetName(Mangled::NamePreference::ePreferMangled)
+                           .AsCString();
     if (!name)
       return false;
 

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 40b6563aeb410..cf425fcc81c2f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -235,6 +235,151 @@ static bool PrettyPrintFunctionNameWithArgs(Stream 
&out_stream,
   return true;
 }
 
+static std::optional<llvm::StringRef>
+GetDemangledBasename(const SymbolContext &sc) {
+  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
+  if (!mangled)
+    return std::nullopt;
+
+  auto demangled_name = mangled.GetDemangledName().GetStringRef();
+  if (demangled_name.empty())
+    return std::nullopt;
+
+  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+  if (!info)
+    return std::nullopt;
+
+  // Function without a basename is nonsense.
+  if (!info->hasBasename())
+    return std::nullopt;
+
+  return demangled_name.slice(info->BasenameRange.first,
+                              info->BasenameRange.second);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledTemplateArguments(const SymbolContext &sc) {
+  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
+  if (!mangled)
+    return std::nullopt;
+
+  auto demangled_name = mangled.GetDemangledName().GetStringRef();
+  if (demangled_name.empty())
+    return std::nullopt;
+
+  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+  if (!info)
+    return std::nullopt;
+
+  // Function without a basename is nonsense.
+  if (!info->hasBasename())
+    return std::nullopt;
+
+  if (info->ArgumentsRange.first < info->BasenameRange.second)
+    return std::nullopt;
+
+  return demangled_name.slice(info->BasenameRange.second,
+                              info->ArgumentsRange.first);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledReturnTypeLHS(const SymbolContext &sc) {
+  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
+  if (!mangled)
+    return std::nullopt;
+
+  auto demangled_name = mangled.GetDemangledName().GetStringRef();
+  if (demangled_name.empty())
+    return std::nullopt;
+
+  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+  if (!info)
+    return std::nullopt;
+
+  // Function without a basename is nonsense.
+  if (!info->hasBasename())
+    return std::nullopt;
+
+  if (info->ScopeRange.first >= demangled_name.size())
+    return std::nullopt;
+
+  return demangled_name.substr(0, info->ScopeRange.first);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledFunctionQualifiers(const SymbolContext &sc) {
+  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
+  if (!mangled)
+    return std::nullopt;
+
+  auto demangled_name = mangled.GetDemangledName().GetStringRef();
+  if (demangled_name.empty())
+    return std::nullopt;
+
+  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+  if (!info)
+    return std::nullopt;
+
+  // Function without a basename is nonsense.
+  if (!info->hasBasename())
+    return std::nullopt;
+
+  if (info->QualifiersRange.second < info->QualifiersRange.first)
+    return std::nullopt;
+
+  return demangled_name.slice(info->QualifiersRange.first,
+                              info->QualifiersRange.second);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledReturnTypeRHS(const SymbolContext &sc) {
+  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
+  if (!mangled)
+    return std::nullopt;
+
+  auto demangled_name = mangled.GetDemangledName().GetStringRef();
+  if (demangled_name.empty())
+    return std::nullopt;
+
+  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+  if (!info)
+    return std::nullopt;
+
+  // Function without a basename is nonsense.
+  if (!info->hasBasename())
+    return std::nullopt;
+
+  if (info->QualifiersRange.first < info->ArgumentsRange.second)
+    return std::nullopt;
+
+  return demangled_name.slice(info->ArgumentsRange.second,
+                              info->QualifiersRange.first);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledScope(const SymbolContext &sc) {
+  Mangled mangled = sc.GetPossiblyInlinedFunctionName();
+  if (!mangled)
+    return std::nullopt;
+
+  auto demangled_name = mangled.GetDemangledName().GetStringRef();
+  if (demangled_name.empty())
+    return std::nullopt;
+
+  const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+  if (!info)
+    return std::nullopt;
+
+  // Function without a basename is nonsense.
+  if (!info->hasBasename())
+    return std::nullopt;
+
+  if (info->ScopeRange.second < info->ScopeRange.first)
+    return std::nullopt;
+
+  return demangled_name.slice(info->ScopeRange.first, info->ScopeRange.second);
+}
+
 bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() {
   // This method tries to parse simple method definitions which are presumably
   // most comman in user programs. Definitions that can be parsed by this
@@ -1694,8 +1839,9 @@ static bool PrintFunctionNameWithArgs(Stream &s,
   ExecutionContextScope *exe_scope =
       exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
 
-  const char *cstr = sc.GetPossiblyInlinedFunctionName(
-      Mangled::NamePreference::ePreferDemangled);
+  const char *cstr = sc.GetPossiblyInlinedFunctionName()
+                         .GetName(Mangled::NamePreference::ePreferDemangled)
+                         .AsCString();
   if (!cstr)
     return false;
 
@@ -1739,3 +1885,86 @@ bool CPlusPlusLanguage::GetFunctionDisplayName(
     return false;
   }
 }
+bool CPlusPlusLanguage::HandleFrameFormatVariable(
+    const SymbolContext &sc, const ExecutionContext *exe_ctx,
+    FormatEntity::Entry::Type type, Stream &s) {
+  assert(sc.function);
+
+  switch (type) {
+  case FormatEntity::Entry::Type::FunctionScope: {
+    std::optional<llvm::StringRef> scope = GetDemangledScope(sc);
+    if (!scope)
+      return false;
+
+    s << *scope;
+
+    return true;
+  }
+
+  case FormatEntity::Entry::Type::FunctionBasename: {
+    std::optional<llvm::StringRef> name = GetDemangledBasename(sc);
+    if (!name)
+      return false;
+
+    s << *name;
+
+    return true;
+  }
+
+  case FormatEntity::Entry::Type::FunctionTemplateArguments: {
+    std::optional<llvm::StringRef> template_args =
+        GetDemangledTemplateArguments(sc);
+    if (!template_args)
+      return false;
+
+    s << *template_args;
+
+    return true;
+  }
+
+  case FormatEntity::Entry::Type::FunctionFormattedArguments: {
+    VariableList args;
+    if (auto variable_list_sp = GetFunctionVariableList(sc))
+      variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
+                                                 args);
+
+    ExecutionContextScope *exe_scope =
+        exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
+
+    s << '(';
+    FormatEntity::PrettyPrintFunctionArguments(s, args, exe_scope);
+    s << ')';
+
+    return true;
+  }
+  case FormatEntity::Entry::Type::FunctionReturnRight: {
+    std::optional<llvm::StringRef> return_rhs = GetDemangledReturnTypeRHS(sc);
+    if (!return_rhs)
+      return false;
+
+    s << *return_rhs;
+
+    return true;
+  }
+  case FormatEntity::Entry::Type::FunctionReturnLeft: {
+    std::optional<llvm::StringRef> return_lhs = GetDemangledReturnTypeLHS(sc);
+    if (!return_lhs)
+      return false;
+
+    s << *return_lhs;
+
+    return true;
+  }
+  case FormatEntity::Entry::Type::FunctionQualifiers: {
+    std::optional<llvm::StringRef> quals = GetDemangledFunctionQualifiers(sc);
+    if (!quals)
+      return false;
+
+    s << *quals;
+
+    return true;
+  }
+  default:
+    return false;
+  }
+}

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index b2b308f8e0c4d..6192ff702773a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -105,6 +105,13 @@ class CPlusPlusLanguage : public Language {
                               FunctionNameRepresentation representation,
                               Stream &s) override;
 
+  bool HandleFrameFormatVariable(const SymbolContext &sc,
+                                 const ExecutionContext *exe_ctx,
+                                 FormatEntity::Entry::Type type,
+                                 Stream &s) override;
+
+  static bool IsCPPMangledName(llvm::StringRef name);
+
   // Extract C++ context and identifier from a string using heuristic matching
   // (as opposed to
   // CPlusPlusLanguage::CxxMethodName which has to have a fully qualified C++

diff  --git a/lldb/source/Symbol/SymbolContext.cpp 
b/lldb/source/Symbol/SymbolContext.cpp
index a9626bbc37777..3bbd1eff824e6 100644
--- a/lldb/source/Symbol/SymbolContext.cpp
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -10,6 +10,7 @@
 
 #include "lldb/Core/Address.h"
 #include "lldb/Core/Debugger.h"
+#include "lldb/Core/DemangledNameInfo.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Host/Host.h"
@@ -872,34 +873,36 @@ const Symbol 
*SymbolContext::FindBestGlobalDataSymbol(ConstString name,
   return nullptr; // no error; we just didn't find anything
 }
 
-char const *SymbolContext::GetPossiblyInlinedFunctionName(
-    Mangled::NamePreference mangling_preference) const {
-  const char *name = nullptr;
-  if (function)
-    name = function->GetMangled().GetName(mangling_preference).AsCString();
-  else if (symbol)
-    name = symbol->GetMangled().GetName(mangling_preference).AsCString();
+Mangled SymbolContext::GetPossiblyInlinedFunctionName() const {
+  auto get_mangled = [this]() {
+    if (function)
+      return function->GetMangled();
+
+    if (symbol)
+      return symbol->GetMangled();
+
+    return Mangled{};
+  };
 
   if (!block)
-    return name;
+    return get_mangled();
 
   const Block *inline_block = block->GetContainingInlinedBlock();
   if (!inline_block)
-    return name;
+    return get_mangled();
 
   const InlineFunctionInfo *inline_info =
       inline_block->GetInlinedFunctionInfo();
   if (!inline_info)
-    return name;
+    return get_mangled();
 
   // If we do have an inlined frame name, return that.
-  if (char const *inline_name =
-          inline_info->GetMangled().GetName(mangling_preference).AsCString())
+  if (const Mangled &inline_name = inline_info->GetMangled())
     return inline_name;
 
   // Sometimes an inline frame may not have mangling information,
   // but does have a valid name.
-  return inline_info->GetName().AsCString();
+  return Mangled{inline_info->GetName().AsCString()};
 }
 
 //

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
new file mode 100644
index 0000000000000..249a5fac5b55e
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
@@ -0,0 +1,46 @@
+# Test the ${function.basename} frame-format variable.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+#
+#--- main.cpp
+namespace ns {
+template<typename T>
+struct Bar {
+  template<typename K>
+  T bar(K k) const & { return 1.0f; }
+};
+
+template<typename T>
+struct Foo {
+  template<typename K>
+  [[gnu::abi_tag("Test")]] void foo() const volatile && {
+    Bar<float> b;
+    b.bar(b);
+  }
+};
+
+template<typename T>
+T func() {
+  ns::Foo<int>{}.foo<int>();
+  return T{};
+}
+} // namespace ns
+
+int main() {
+  ns::func<ns::Foo<int>>();
+  return 0;
+}
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.basename}'\n"
+break set -n bar
+
+run
+bt
+
+# CHECK: custom-frame 'bar'
+# CHECK: custom-frame 'foo[abi:Test]'
+# CHECK: custom-frame 'func'

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test
new file mode 100644
index 0000000000000..1a36d049db06c
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for ${function.basename} in 
languages that
+# don't implement this frame format variable (in this case Objective-C).
+#
+# RUN: split-file %s %t
+# RUN: %build %t/main.m -o %t.objc.out
+# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.m
+
+int func() {}
+int bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.basename}'\n"
+break set -n bar
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame

diff  --git 
a/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
new file mode 100644
index 0000000000000..5554830d3a247
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
@@ -0,0 +1,42 @@
+# Test the ${function.formatted-arguments} frame-format variable.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.cpp
+struct Foo {
+  void func() {}
+};
+
+void bar() {
+  Foo{}.func();
+}
+
+void foo(int, int x) {
+  bar();
+}
+
+void myFunc(char const * str,
+          void (*fptr)(int, int)) {
+  fptr(5, 10);
+}
+
+int main(int argc, char const *argv[]) {
+    myFunc("hello", &foo);
+    return 0;
+}
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.formatted-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: custom-frame '(this={{.*}})'
+# CHECK: custom-frame '()'
+# CHECK: custom-frame '((null)=5, x=10)'
+# CHECK: custom-frame '(str="hello", fptr=({{.*}}.out`foo(int, int) at 
main.cpp:{{[0-9]+}}))'
+# CHECK: custom-frame '(argc=1, argv={{.*}})'

diff  --git 
a/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test
new file mode 100644
index 0000000000000..fdafa65c6d05d
--- /dev/null
+++ 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for 
${function.formatted-arguments} in languages that
+# don't implement this frame format variable (in this case Objective-C).
+#
+# RUN: split-file %s %t
+# RUN: %build %t/main.m -o %t.objc.out
+# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.m
+
+int func() {}
+int bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.formatted-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
new file mode 100644
index 0000000000000..95a3be3811d85
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
@@ -0,0 +1,24 @@
+# Test the ${function.qualifiers} frame-format variable.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.cpp
+struct Foo {
+    void foo() const volatile && {}
+    void bar() { Foo{}.foo(); }
+};
+
+int main() { Foo{}.bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.qualifiers}'\n"
+break set -n foo
+
+run
+bt
+
+# CHECK: custom-frame ' const volatile &&'
+# CHECK: custom-frame ''

diff  --git 
a/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test
new file mode 100644
index 0000000000000..eff1b581c15dc
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test
@@ -0,0 +1,25 @@
+# Check that we have an appropriate fallback for ${function.qualifiers} in
+# languages that don't implement this frame format variable (in this case 
Objective-C).
+
+# RUN: split-file %s %t
+#
+# RUN: %build %t/main.m -o %t.objc.out
+# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.m
+
+int foo() {}
+int bar() { foo(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.qualifiers}'\n"
+break set -n foo
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
new file mode 100644
index 0000000000000..a5e49a1054c86
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
@@ -0,0 +1,55 @@
+# Test the ${function.return-left} and ${function.return-right}
+# frame-format variables.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.cpp
+namespace ns::ns2 {
+template<typename T>
+struct Foo {};
+
+template<typename T>
+Foo<int> qux(int) {
+  return {};
+}
+
+template<typename T>
+Foo<int> (*bar(Foo<float>))(int) {
+  qux<T>(5);
+  return qux<T>;
+}
+
+struct Bar {
+  template<typename T>
+  Foo<int> (* (*foo(int) const &&)(Foo<float>))(int) {
+    bar<T>(Foo<float>{});
+    return bar<T>;
+  }
+};
+}
+
+int main(int argc, char const *argv[]) {
+    ns::ns2::Bar{}.foo<int>(5);
+    return 0;
+}
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.return-left}'\n"
+break set -n qux
+
+run
+bt
+
+# CHECK: custom-frame 'ns::ns2::Foo<int> '
+# CHECK: custom-frame 'ns::ns2::Foo<int> (*'
+# CHECK: custom-frame 'ns::ns2::Foo<int> (* (*'
+
+settings set -f frame-format "other-frame '${function.return-right}'\n"
+bt
+
+# CHECK: other-frame ''
+# CHECK: other-frame ')(int)'
+# CHECK: other-frame ')(ns::ns2::Foo<float>))(int)'

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test
new file mode 100644
index 0000000000000..69dd0fdbb0c19
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test
@@ -0,0 +1,31 @@
+# Check that we have an appropriate fallback for ${function.return-left} and
+# ${function.return-right} in languages that don't implement this frame
+# format variable (in this case Objective-C).
+#
+# RUN: split-file %s %t
+# RUN: %build %t/main.m -o %t.objc.out
+# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.m
+
+int qux() {}
+int bar() { qux(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.return-left}'\n"
+break set -n qux
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
+
+settings set -f frame-format "other-frame '${function.return-right}'\n"
+bt
+
+# CHECK: bt
+# CHECK-NOT: other-frame

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
new file mode 100644
index 0000000000000..28f0ab7ca39e3
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
@@ -0,0 +1,41 @@
+# Test the ${function.scope} frame-format variable.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.out
+# RUN: %lldb -o "settings set interpreter.stop-command-source-on-error false" \
+# RUN:       -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.cpp
+namespace ns::ns2 {
+inline namespace ins {
+template <typename T>
+struct Foo {
+    void func() {}
+};
+
+int foo() {
+    Foo<int>{}.func();
+    return 5;
+}
+}  // namespace ins
+}  // namespace ns::ns2
+
+using namespace ns::ns2;
+
+int bar() {
+  return ns::ns2::foo();
+}
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.scope}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: frame 'ns::ns2::ins::Foo<int>::'
+# CHECK: frame 'ns::ns2::ins::'
+# CHECK: frame ''

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test
new file mode 100644
index 0000000000000..310b5e1992ab8
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for ${function.scope} in 
languages that
+# don't implement this frame format variable (in this case Objective-C).
+#
+# RUN: split-file %s %t
+# RUN: %build %t/main.m -o %t.objc.out
+# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.m
+
+int func() {}
+int bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.scope}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame

diff  --git 
a/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
new file mode 100644
index 0000000000000..396dd29dfd02c
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
@@ -0,0 +1,37 @@
+# Test the ${function.template-arguments} frame-format variable.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.cxx.out
+# RUN: %lldb -x -b -s %t/commands.input %t.cxx.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.cpp
+template<typename K>
+struct Foo {
+    template<typename T>
+    void func() {}
+};
+
+template<typename T, template <typename> class K,
+         typename M>
+int foo() {
+    Foo<int>{}.func<T>();
+    return 5;
+}
+
+int bar() {
+  return foo<int, Foo, Foo<float>>();
+}
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.template-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: custom-frame '<int>'
+# CHECK: custom-frame '<int, Foo, Foo<float>>'
+# CHECK: custom-frame ''

diff  --git 
a/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test 
b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test
new file mode 100644
index 0000000000000..1726aebacb9eb
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for 
${function.template-arguments} in
+# languages that don't implement this frame format variable (in this case 
Objective-C).
+#
+# RUN: split-file %s %t
+# RUN: %build %t/main.m -o %t.objc.out
+# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.m
+
+int func() {}
+int bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.template-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame

diff  --git a/lldb/test/Shell/Settings/TestFrameFormatName.test 
b/lldb/test/Shell/Settings/TestFrameFormatName.test
index 110daceb47b40..34eb2f4975315 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatName.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatName.test
@@ -22,13 +22,13 @@ c
 c
 # NAME_WITH_ARGS: frame int ns::foo<void (Foo::*)(int (*)(int)) const 
noexcept>(str="method")
 c
-# NAME_WITH_ARGS: frame ns::returns_func_ptr<int>((null)={{.*}})
+# NAME_WITH_ARGS: frame detail::Quux<double> (* 
(*ns::returns_func_ptr<int>((null)={{.*}}))(int))(float)
 c
 # NAME_WITH_ARGS: frame void Foo::foo<int (*)()>(this={{.*}}, 
arg=({{.*}}`(anonymous namespace)::anon_bar() at {{.*}}))
 c
 # NAME_WITH_ARGS: frame void Foo::operator<<<1>(this={{.*}}, (null)=0)
 c
-# NAME_WITH_ARGS: frame Foo::returns_func_ptr<int>(this={{.*}}, (null)={{.*}})
+# NAME_WITH_ARGS: frame detail::Quux<double> (* 
(*Foo::returns_func_ptr<int>(this={{.*}}, (null)={{.*}}))(int))(float) const
 c
 # NAME_WITH_ARGS: frame inlined_foo(str="bar")
 q


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to