debugger: Add inline value tests (#29815)

## Context

This PR improves the accuracy of our inline values for Rust/Python. It
does this by only adding inline value hints to the last valid use of a
variable and checking whether variables are valid within a given scope
or not.

We also added tests for Rust/Python inline values and inline values
refreshing when stepping in a debug session.

### Future tasks
1. Handle functions that have inner functions defined within them.
2. Add inline values to variables that were used in inner scopes but not
defined in them.
3. Move the inline value provider trait and impls to the language trait
(or somewhere else).
4. Use Semantic tokens as the first inline value provider and fall back
to tree sitter
5. add let some variable statement, for loops, and function inline value
hints to Rust.
6. Make writing tests more streamlined. 
6.1 We should be able to write a test by only passing in variables,
language, source file, expected result, and stop position to a function.
7. Write a test that has coverage for selecting different stack frames. 

co-authored-by: Remco Smits \<djsmits12@gmail.com\>

Release Notes:

- N/A

---------

Co-authored-by: Remco Smits <djsmits12@gmail.com>
This commit is contained in:
Anthony Eid 2025-05-07 14:39:35 +02:00 committed by GitHub
parent 7bc3f74cab
commit 1a520990cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 2273 additions and 281 deletions

View file

@ -27,7 +27,6 @@ dap.workspace = true
futures.workspace = true
gpui.workspace = true
language.workspace = true
lsp-types.workspace = true
paths.workspace = true
serde.workspace = true
serde_json.workspace = true

View file

@ -2,7 +2,7 @@ use std::{collections::HashMap, path::PathBuf, sync::OnceLock};
use anyhow::Result;
use async_trait::async_trait;
use dap::adapters::{DebugTaskDefinition, InlineValueProvider, latest_github_release};
use dap::adapters::{DebugTaskDefinition, latest_github_release};
use futures::StreamExt;
use gpui::AsyncApp;
use task::DebugRequest;
@ -159,25 +159,4 @@ impl DebugAdapter for CodeLldbDebugAdapter {
connection: None,
})
}
fn inline_value_provider(&self) -> Option<Box<dyn InlineValueProvider>> {
Some(Box::new(CodeLldbInlineValueProvider))
}
}
struct CodeLldbInlineValueProvider;
impl InlineValueProvider for CodeLldbInlineValueProvider {
fn provide(&self, variables: Vec<(String, lsp_types::Range)>) -> Vec<lsp_types::InlineValue> {
variables
.into_iter()
.map(|(variable, range)| {
lsp_types::InlineValue::VariableLookup(lsp_types::InlineValueVariableLookup {
range,
variable_name: Some(variable),
case_sensitive_lookup: true,
})
})
.collect()
}
}

View file

@ -16,6 +16,7 @@ use dap::{
self, AdapterVersion, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName,
GithubRepo,
},
inline_value::{PythonInlineValueProvider, RustInlineValueProvider},
};
use gdb::GdbDebugAdapter;
use go::GoDebugAdapter;
@ -34,6 +35,10 @@ pub fn init(cx: &mut App) {
registry.add_adapter(Arc::from(JsDebugAdapter::default()));
registry.add_adapter(Arc::from(GoDebugAdapter));
registry.add_adapter(Arc::from(GdbDebugAdapter));
registry.add_inline_value_provider("Rust".to_string(), Arc::from(RustInlineValueProvider));
registry
.add_inline_value_provider("Python".to_string(), Arc::from(PythonInlineValueProvider));
})
}

View file

@ -1,8 +1,5 @@
use crate::*;
use dap::{
DebugRequest, StartDebuggingRequestArguments, adapters::DebugTaskDefinition,
adapters::InlineValueProvider,
};
use dap::{DebugRequest, StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
use gpui::AsyncApp;
use std::{collections::HashMap, ffi::OsStr, path::PathBuf, sync::OnceLock};
use util::ResultExt;
@ -182,34 +179,4 @@ impl DebugAdapter for PythonDebugAdapter {
self.get_installed_binary(delegate, &config, user_installed_path, cx)
.await
}
fn inline_value_provider(&self) -> Option<Box<dyn InlineValueProvider>> {
Some(Box::new(PythonInlineValueProvider))
}
}
struct PythonInlineValueProvider;
impl InlineValueProvider for PythonInlineValueProvider {
fn provide(&self, variables: Vec<(String, lsp_types::Range)>) -> Vec<lsp_types::InlineValue> {
variables
.into_iter()
.map(|(variable, range)| {
if variable.contains(".") || variable.contains("[") {
lsp_types::InlineValue::EvaluatableExpression(
lsp_types::InlineValueEvaluatableExpression {
range,
expression: Some(variable),
},
)
} else {
lsp_types::InlineValue::VariableLookup(lsp_types::InlineValueVariableLookup {
range,
variable_name: Some(variable),
case_sensitive_lookup: true,
})
}
})
.collect()
}
}