[Lldb-commits] [lldb] cf5d8de - [lldb-vscode] Show a fake child with the raw value of synthetic types (#65552)

via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 6 17:13:52 PDT 2023


Author: Walter Erquinigo
Date: 2023-09-06T20:13:48-04:00
New Revision: cf5d8def5cf66fbdfffa00a4845bd648ec58ed60

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

LOG: [lldb-vscode] Show a fake child with the raw value of synthetic types (#65552)

Currently, if the user wants to inspect the raw version of a synthetic
variable, they have to go to the debug console and type `frame var
<variable>`, which is not a great experience. Taking inspiration from
CodeLLDB, this adds a `[raw]` child to every synthetic variable so that
this kind of inspection can be done visually.

Some examples:

<img width="500" alt="Screenshot 2023-09-06 at 7 56 25 PM"
src="https://github.com/llvm/llvm-project/assets/1613874/7fefb7c5-0da7-49c7-968b-78ac88348fea">
<img width="479" alt="Screenshot 2023-09-06 at 6 58 25 PM"
src="https://github.com/llvm/llvm-project/assets/1613874/6e650567-16e1-462f-9bf5-4a3a605cf6fc">

Added: 
    

Modified: 
    lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py
    lldb/tools/lldb-vscode/JSONUtils.cpp
    lldb/tools/lldb-vscode/JSONUtils.h
    lldb/tools/lldb-vscode/lldb-vscode.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py b/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py
index 6eb8e87190d0074..953f330e14a0f97 100644
--- a/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py
+++ b/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py
@@ -517,6 +517,20 @@ def test_indexedVariables(self):
         }
         self.verify_variables(verify_locals, locals)
 
+        # We also verify that we produce a "[raw]" fake child with the real
+        # SBValue for the synthetic type.
+        verify_children = {
+            "[0]": {"equals": {"type": "int", "value": "0"}},
+            "[1]": {"equals": {"type": "int", "value": "0"}},
+            "[2]": {"equals": {"type": "int", "value": "0"}},
+            "[3]": {"equals": {"type": "int", "value": "0"}},
+            "[4]": {"equals": {"type": "int", "value": "0"}},
+            "[raw]": {"contains": {"type": ["vector"]}},
+        }
+        children = self.vscode.request_variables(locals[2]["variablesReference"])["body"]["variables"]
+        self.verify_variables(verify_children, children)
+
+
     @skipIfWindows
     @skipIfRemote
     def test_registers(self):

diff  --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp
index 9a6fd26d2bd5864..e34448c9b7f2f85 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.cpp
+++ b/lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -1103,10 +1103,13 @@ std::string CreateUniqueVariableNameForDisplay(lldb::SBValue v,
 // }
 llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
                                  int64_t varID, bool format_hex,
-                                 bool is_name_duplicated) {
+                                 bool is_name_duplicated,
+                                 std::optional<std::string> custom_name) {
   llvm::json::Object object;
-  EmplaceSafeString(object, "name",
-                    CreateUniqueVariableNameForDisplay(v, is_name_duplicated));
+  EmplaceSafeString(
+      object, "name",
+      custom_name ? *custom_name
+                  : CreateUniqueVariableNameForDisplay(v, is_name_duplicated));
 
   if (format_hex)
     v.SetFormat(lldb::eFormatHex);
@@ -1131,15 +1134,19 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
   const bool is_synthetic = v.IsSynthetic();
   if (is_array || is_synthetic) {
     const auto num_children = v.GetNumChildren();
+    // We create a "[raw]" fake child for each synthetic type, so we have to
+    // account for it when returning indexed variables. We don't need to do this
+    // for non-indexed ones.
+    int actual_num_children = num_children + (is_synthetic ? 1 : 0);
     if (is_array) {
-      object.try_emplace("indexedVariables", num_children);
+      object.try_emplace("indexedVariables", actual_num_children);
     } else if (num_children > 0) {
       // If a type has a synthetic child provider, then the SBType of "v" won't
       // tell us anything about what might be displayed. So we can check if the
       // first child's name is "[0]" and then we can say it is indexed.
       const char *first_child_name = v.GetChildAtIndex(0).GetName();
       if (first_child_name && strcmp(first_child_name, "[0]") == 0)
-        object.try_emplace("indexedVariables", num_children);
+        object.try_emplace("indexedVariables", actual_num_children);
     }
   }
   EmplaceSafeString(object, "type", type_cstr ? type_cstr : NO_TYPENAME);

diff  --git a/lldb/tools/lldb-vscode/JSONUtils.h b/lldb/tools/lldb-vscode/JSONUtils.h
index 516bc462eae1b16..2013147f5d3532a 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.h
+++ b/lldb/tools/lldb-vscode/JSONUtils.h
@@ -440,12 +440,17 @@ std::string CreateUniqueVariableNameForDisplay(lldb::SBValue v,
 ///     As VSCode doesn't render two of more variables with the same name, we
 ///     apply a suffix to distinguish duplicated variables.
 ///
+/// \param[in] custom_name
+///     A provided custom name that is used instead of the SBValue's when
+///     creating the JSON representation.
+///
 /// \return
 ///     A "Variable" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
 llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
                                  int64_t varID, bool format_hex,
-                                 bool is_name_duplicated = false);
+                                 bool is_name_duplicated = false,
+                                 std::optional<std::string> custom_name = {});
 
 llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit);
 

diff  --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp
index 294783c4f505d37..5480edd74f24f47 100644
--- a/lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -3251,7 +3251,7 @@ void request_variables(const llvm::json::Object &request) {
         break;
 
       int64_t var_ref = 0;
-      if (variable.MightHaveChildren()) {
+      if (variable.MightHaveChildren() || variable.IsSynthetic()) {
         var_ref = g_vsc.variables.InsertExpandableVariable(
             variable, /*is_permanent=*/false);
       }
@@ -3264,23 +3264,36 @@ void request_variables(const llvm::json::Object &request) {
     // children.
     lldb::SBValue variable = g_vsc.variables.GetVariable(variablesReference);
     if (variable.IsValid()) {
-      const auto num_children = variable.GetNumChildren();
-      const int64_t end_idx = start + ((count == 0) ? num_children : count);
-      for (auto i = start; i < end_idx; ++i) {
-        lldb::SBValue child = variable.GetChildAtIndex(i);
+      auto addChild = [&](lldb::SBValue child,
+                          std::optional<std::string> custom_name = {}) {
         if (!child.IsValid())
-          break;
+          return;
         if (child.MightHaveChildren()) {
           auto is_permanent =
               g_vsc.variables.IsPermanentVariableReference(variablesReference);
           auto childVariablesReferences =
               g_vsc.variables.InsertExpandableVariable(child, is_permanent);
-          variables.emplace_back(CreateVariable(child, childVariablesReferences,
-                                                childVariablesReferences, hex));
+          variables.emplace_back(CreateVariable(
+              child, childVariablesReferences, childVariablesReferences, hex,
+              /*is_name_duplicated=*/false, custom_name));
         } else {
-          variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex));
+          variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex,
+                                                /*is_name_duplicated=*/false,
+                                                custom_name));
         }
-      }
+      };
+      const int64_t num_children = variable.GetNumChildren();
+      int64_t end_idx = start + ((count == 0) ? num_children : count);
+      int64_t i = start;
+      for (; i < end_idx && i < num_children; ++i)
+        addChild(variable.GetChildAtIndex(i));
+
+      // If we haven't filled the count quota from the request, we insert a new
+      // "[raw]" child that can be used to inspect the raw version of a
+      // synthetic member. That eliminates the need for the user to go to the
+      // debug console and type `frame var <variable> to get these values.
+      if (variable.IsSynthetic() && i == num_children)
+        addChild(variable.GetNonSyntheticValue(), "[raw]");
     }
   }
   llvm::json::Object body;


        


More information about the lldb-commits mailing list