[Lldb-commits] [lldb] [LLDB] Include qualified setting name in apropos search (PR #194873)

via lldb-commits lldb-commits at lists.llvm.org
Wed Apr 29 07:43:16 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: David Spickett (DavidSpickett)

<details>
<summary>Changes</summary>

Fixes #<!-- -->188479.

`apropos` was previously only looking at the "name" of the setting, which is the final part of what I as a user think of as the "name" as in the "platform.plugin.something.something-else" form. Except that that form is in fact the "qualified name".

In this change, I've added the qualified name to the search so you can search for any subset of the qualified name and find related settings. For example, "qemu-user" used to return no settings because "qemu-user" is an earlier part of the qualified name.
```
(lldb) apropos qemu-user
No commands found pertaining to 'qemu-user'. Try 'help' to see a complete list of debugger commands.
No settings found pertaining to 'qemu-user'. Try 'settings show' to see a complete list of debugger settings.
```
Now you will get all the "qemu-user.something" settings.
```
(lldb) apropos qemu-user
No commands found pertaining to 'qemu-user'. Try 'help' to see a complete list of debugger commands.

The following settings variables may relate to 'qemu-user':
  platform.plugin.qemu-user.architecture      -- Architecture to emulate.
  platform.plugin.qemu-user.emulator-args     -- Extra arguments to pass to the emulator.
  platform.plugin.qemu-user.emulator-env-vars -- Extra variables to add to the emulator environment.
  platform.plugin.qemu-user.emulator-path     -- Path to the emulator binary. If the path does not contain a directory separator, the filename is looked up in the PATH environment variable.
                                                 If empty, the filename is derived from the architecture setting.
  platform.plugin.qemu-user.target-env-vars   -- Extra variables to add to emulated target environment.
```

This does result in more results for terms that are settings categories, for example "apropos platform" now includes these settings as well as the original results:
```
  platform.module-cache-directory             -- Root directory for cached modules.
  platform.use-module-cache                   -- Use module cache.
  platform.plugin.remote-android.package-name -- Specify package name to run adb shell command with 'run-as' as the package user when necessary (e.g. to get file with 'cat' and 'dd').
  platform.plugin.darwin.ignored-exceptions   -- List the mach exceptions to ignore, separated by '|' (e.g. 'EXC_BAD_ACCESS|EXC_BAD_INSTRUCTION'). lldb will instead stop on the BSD signal
                                                 the exception was converted into, if there is one.
  platform.plugin.qemu-user.architecture      -- Architecture to emulate.
  platform.plugin.qemu-user.emulator-args     -- Extra arguments to pass to the emulator.
  platform.plugin.qemu-user.emulator-env-vars -- Extra variables to add to the emulator environment.
  platform.plugin.qemu-user.emulator-path     -- Path to the emulator binary. If the path does not contain a directory separator, the filename is looked up in the PATH environment variable.
                                                 If empty, the filename is derived from the architecture setting.
  platform.plugin.qemu-user.target-env-vars   -- Extra variables to add to emulated target environment.
  platform.plugin.wasm.port-arg               -- Argument to the WebAssembly runtime to specify the GDB remote port. The port number chosen by LLDB will be concatenated to this argument.
                                                 For example: `-g=127.0.0.1:` or `--debugger-port `.
  platform.plugin.wasm.runtime-args           -- Extra arguments to pass to the WebAssembly runtime. For the argument that specifies the GDB remote port, use port-arg instead.
  platform.plugin.wasm.runtime-path           -- Path to the WebAssembly runtime binary. If the path does not contain a directory separator, the filename is looked up in the PATH
                                                 environment variable.
```
I don't think that rises to a level of spam because it's easy to see why they are in the results (and so how to refine the search if needed) and looking for common names is a normal thing to do and I want to see them all when I do that.

---
Full diff: https://github.com/llvm/llvm-project/pull/194873.diff


3 Files Affected:

- (modified) lldb/include/lldb/Interpreter/OptionValueProperties.h (+2) 
- (modified) lldb/source/Interpreter/OptionValueProperties.cpp (+57-18) 
- (modified) lldb/test/API/commands/settings/TestSettings.py (+24) 


``````````diff
diff --git a/lldb/include/lldb/Interpreter/OptionValueProperties.h b/lldb/include/lldb/Interpreter/OptionValueProperties.h
index 21da8e584a7b4..84118a06a61ff 100644
--- a/lldb/include/lldb/Interpreter/OptionValueProperties.h
+++ b/lldb/include/lldb/Interpreter/OptionValueProperties.h
@@ -84,6 +84,8 @@ class OptionValueProperties
     return ProtectedGetPropertyAtIndex(idx);
   }
 
+  size_t GetNumProperties() const { return m_properties.size(); }
+
   // Property can be a property path like
   // "target.process.extra-startup-command"
   virtual const Property *
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index def6cc462f76a..2248c7984ee55 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -462,32 +462,71 @@ void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,
   }
 }
 
+// This function flattens a nested set of properties. This is what we want for
+// search results. If we didn't do this, search results would be presented
+// split up by type of setting.
+static void
+FlattenProperties(const OptionValueProperties *properties,
+                  std::vector<const Property *> &matching_properties) {
+  size_t num_child_properties = properties->GetNumProperties();
+  for (size_t i = 0; i < num_child_properties; ++i)
+    if (auto property = properties->GetPropertyAtIndex(i)) {
+      if (auto children = property->GetValue()->GetAsProperties()) {
+        FlattenProperties(children, matching_properties);
+      } else {
+        matching_properties.push_back(property);
+      }
+    }
+}
+
 void OptionValueProperties::Apropos(
     llvm::StringRef keyword,
     std::vector<const Property *> &matching_properties) const {
   const size_t num_properties = m_properties.size();
-  StreamString strm;
   for (size_t i = 0; i < num_properties; ++i) {
     const Property *property = ProtectedGetPropertyAtIndex(i);
-    if (property) {
-      const OptionValueProperties *properties =
-          property->GetValue()->GetAsProperties();
-      if (properties) {
-        properties->Apropos(keyword, matching_properties);
+    if (!property)
+      continue;
+
+    // The qualified name includes the category parts. For example
+    // "platform.plugin.qemu-user.qemu-user".
+    StreamString qualified_name_strm;
+    std::optional<llvm::StringRef> qualified_name_str;
+    if (property->DumpQualifiedName(qualified_name_strm))
+      qualified_name_str = qualified_name_strm.GetString();
+
+    // Some properties are a group of other priorities.
+    if (const OptionValueProperties *properties =
+            property->GetValue()->GetAsProperties()) {
+      // If the keyword is already in the qualified name, any nested
+      // settings would match too and we can just add them, skipping
+      // getting their qualified names too.
+      if (qualified_name_str &&
+          qualified_name_str->contains_insensitive(keyword)) {
+        FlattenProperties(properties, matching_properties);
       } else {
-        bool match = false;
-        llvm::StringRef name = property->GetName();
-        if (name.contains_insensitive(keyword))
-          match = true;
-        else {
-          llvm::StringRef desc = property->GetDescription();
-          if (desc.contains_insensitive(keyword))
-            match = true;
-        }
-        if (match) {
-          matching_properties.push_back(property);
-        }
+        // Search in all the nested settings.
+        properties->Apropos(keyword, matching_properties);
       }
+
+      continue;
+    }
+
+    if (qualified_name_str) {
+      if (qualified_name_str->contains_insensitive(keyword)) {
+        matching_properties.push_back(property);
+        continue;
+      }
+    } else if (llvm::StringRef name = property->GetName();
+               name.contains_insensitive(keyword)) {
+      matching_properties.push_back(property);
+      continue;
+    }
+
+    if (llvm::StringRef desc = property->GetDescription();
+        desc.contains_insensitive(keyword)) {
+      matching_properties.push_back(property);
+      continue;
     }
   }
 }
diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py
index 8410befe399a3..e3302cb9b9aa5 100644
--- a/lldb/test/API/commands/settings/TestSettings.py
+++ b/lldb/test/API/commands/settings/TestSettings.py
@@ -26,6 +26,30 @@ def test_apropos_should_also_search_settings_description(self):
             ],
         )
 
+    def test_apropos_should_also_search_settings_qualified_name(self):
+        """Test that 'apropos' command searches the qualified name ("a.b.c.d") of settings not just
+        the name ("d")."""
+
+        # 'qemu-user' is one component of the qualified name.
+        self.expect(
+            "apropos 'qemu-user'",
+            substrs=[
+                "platform.plugin.qemu-user.architecture",
+                "platform.plugin.qemu-user.emulator-args",
+            ],
+        )
+
+        # Should be able to search for strings that overlap > 1 component of the
+        # qualified name.
+        self.expect(
+            "apropos 'qemu-user.emulator-'",
+            substrs=[
+                "platform.plugin.qemu-user.emulator-args",
+                "platform.plugin.qemu-user.emulator-env-vars",
+                "platform.plugin.qemu-user.emulator-path",
+            ],
+        )
+
     def test_set_interpreter_repeat_prev_command(self):
         """Test the `interpreter.repeat-previous-command` setting."""
         self.build()

``````````

</details>


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


More information about the lldb-commits mailing list