[Lldb-commits] [lldb] [lldb] Add completion support for direct ivars (PR #195187)

Dave Lee via lldb-commits lldb-commits at lists.llvm.org
Sat May 2 18:07:17 PDT 2026


https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/195187

>From d4be48e289dac926b20a001f58ad624fe6068bbd Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Sun, 26 Apr 2026 20:21:20 -0700
Subject: [PATCH 1/3] [lldb] Add completion support for direct ivars

---
 lldb/source/Symbol/Variable.cpp               | 39 +++++++++++++++++++
 .../completion/TestCompletion.py              |  8 ++++
 2 files changed, 47 insertions(+)

diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
index eb4d740fa7efa..1a9843a3d753d 100644
--- a/lldb/source/Symbol/Variable.cpp
+++ b/lldb/source/Symbol/Variable.cpp
@@ -21,6 +21,7 @@
 #include "lldb/Symbol/TypeSystem.h"
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/ABI.h"
+#include "lldb/Target/Language.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrame.h"
@@ -475,6 +476,28 @@ static void PrivateAutoComplete(
         &prefix_path, // Anything that has been resolved already will be in here
     const CompilerType &compiler_type, CompletionRequest &request);
 
+// Get the CompilerType of the instance variable (this/self) for direct ivar
+// completion. Returns an invalid CompilerType if not in a method context.
+static CompilerType GetInstanceVariableType(StackFrame &frame,
+                                            VariableList &variable_list) {
+  auto *lang = Language::FindPlugin(frame.GetLanguage().AsLanguageType());
+  if (!lang)
+    return {};
+  llvm::StringRef instance_name = lang->GetInstanceVariableName();
+  if (instance_name.empty())
+    return {};
+  VariableSP var_sp = variable_list.FindVariable(ConstString(instance_name));
+  if (!var_sp)
+    return {};
+  Type *var_type = var_sp->GetType();
+  if (!var_type)
+    return {};
+  CompilerType compiler_type = var_type->GetForwardCompilerType();
+  if (compiler_type.IsPointerType())
+    compiler_type = compiler_type.GetPointeeType();
+  return compiler_type.GetCanonicalType();
+}
+
 static void PrivateAutoCompleteMembers(
     StackFrame *frame, const std::string &partial_member_name,
     llvm::StringRef partial_path,
@@ -598,6 +621,14 @@ static void PrivateAutoComplete(
         if (variable_list) {
           for (const VariableSP &var_sp : *variable_list)
             request.AddCompletion(var_sp->GetName());
+
+          // Offer members of this/self so that direct ivar access can be
+          // completed (eg "frame variable member" for "this->member").
+          CompilerType instance_type =
+              GetInstanceVariableType(*frame, *variable_list);
+          if (instance_type)
+            PrivateAutoCompleteMembers(frame, "", "", "", instance_type,
+                                       request);
         }
       }
     }
@@ -720,6 +751,14 @@ static void PrivateAutoComplete(
               }
             }
           }
+
+          // Try also completing the token as a member of this/self (direct ivar
+          // access).
+          CompilerType instance_type =
+              GetInstanceVariableType(*frame, *variable_list);
+          if (instance_type)
+            PrivateAutoCompleteMembers(frame, token, remaining_partial_path,
+                                       prefix_path, instance_type, request);
         }
       }
       break;
diff --git a/lldb/test/API/functionalities/completion/TestCompletion.py b/lldb/test/API/functionalities/completion/TestCompletion.py
index 8a972da9cc902..04253b15c041d 100644
--- a/lldb/test/API/functionalities/completion/TestCompletion.py
+++ b/lldb/test/API/functionalities/completion/TestCompletion.py
@@ -82,6 +82,14 @@ def do_test_variable_completion(self, command):
             f"{command} ptr_container->Mem", f"{command} ptr_container->MemberVar"
         )
 
+    def test_frame_variable_direct_ivar(self):
+        """Test that 'frame variable' completes members of 'this' directly."""
+        self.build()
+        lldbutil.run_to_name_breakpoint(self, "Bar")
+        self.completions_contain("frame variable ", ["t", "temp"])
+        self.complete_from_to("frame variable te", "frame variable temp")
+        self.complete_from_to("frame variable t.", "frame variable t.x")
+
     def test_process_attach_dash_dash_con(self):
         """Test that 'process attach --con' completes to 'process attach --continue '."""
         self.complete_from_to("process attach --con", "process attach --continue ")

>From aed6ab82b89bf4fe50c61203166e8a3c4cff84c4 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Sat, 2 May 2026 18:06:48 -0700
Subject: [PATCH 2/3] Apply docstring suggestion from @JDevlieghere

Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
---
 lldb/source/Symbol/Variable.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
index 1a9843a3d753d..f1f873cdc403d 100644
--- a/lldb/source/Symbol/Variable.cpp
+++ b/lldb/source/Symbol/Variable.cpp
@@ -476,8 +476,8 @@ static void PrivateAutoComplete(
         &prefix_path, // Anything that has been resolved already will be in here
     const CompilerType &compiler_type, CompletionRequest &request);
 
-// Get the CompilerType of the instance variable (this/self) for direct ivar
-// completion. Returns an invalid CompilerType if not in a method context.
+/// Get the CompilerType of the instance variable (this/self) for direct ivar
+/// completion. Returns an invalid CompilerType if not in a method context.
 static CompilerType GetInstanceVariableType(StackFrame &frame,
                                             VariableList &variable_list) {
   auto *lang = Language::FindPlugin(frame.GetLanguage().AsLanguageType());

>From 7f93fafe4f3e293ba3f7e855e09a91c56817f3b1 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Sat, 2 May 2026 18:07:08 -0700
Subject: [PATCH 3/3] Apply IsValid suggestion from @JDevlieghere

Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
---
 lldb/source/Symbol/Variable.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
index f1f873cdc403d..fa3da1fc7fdf3 100644
--- a/lldb/source/Symbol/Variable.cpp
+++ b/lldb/source/Symbol/Variable.cpp
@@ -626,7 +626,7 @@ static void PrivateAutoComplete(
           // completed (eg "frame variable member" for "this->member").
           CompilerType instance_type =
               GetInstanceVariableType(*frame, *variable_list);
-          if (instance_type)
+          if (instance_type.IsValid())
             PrivateAutoCompleteMembers(frame, "", "", "", instance_type,
                                        request);
         }



More information about the lldb-commits mailing list