Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21926 from A4-Tacks/inlayhint-empty-arg
fix: Fix param inlayHints on empty expr and comma
| -rw-r--r-- | crates/ide/src/inlay_hints/param_name.rs | 16 | ||||
| -rw-r--r-- | crates/syntax/src/ast/node_ext.rs | 24 |
2 files changed, 39 insertions, 1 deletions
diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index 08588bbed0..8dddf9d37e 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -37,8 +37,9 @@ pub(super) fn hints( let hints = callable .params() .into_iter() - .zip(arg_list.args()) + .zip(arg_list.args_maybe_empty()) .filter_map(|(p, arg)| { + let arg = arg?; // Only annotate hints for expressions that exist in the original file let range = sema.original_range_opt(arg.syntax())?; if range.file_id != file_id { @@ -562,6 +563,19 @@ fn main() { } #[test] + fn param_name_hints_show_after_empty_arg() { + check_params( + r#"pub fn test(a: i32, b: i32, c: i32) {} +fn main() { + test(, 2,); + //^ b + test(, , 3); + //^ c +}"#, + ) + } + + #[test] fn function_call_parameter_hint() { check_params( r#" diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 63e4608d0f..3fc3b39fee 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -77,6 +77,15 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> { } } +fn into_comma(it: NodeOrToken<SyntaxNode, SyntaxToken>) -> Option<SyntaxToken> { + let token = match it { + NodeOrToken::Token(it) => it, + NodeOrToken::Node(node) if node.kind() == SyntaxKind::ERROR => node.first_token()?, + NodeOrToken::Node(_) => return None, + }; + (token.kind() == T![,]).then_some(token) +} + impl ast::Abi { pub fn abi_string(&self) -> Option<ast::String> { support::token(&self.syntax, SyntaxKind::STRING).and_then(ast::String::cast) @@ -1037,6 +1046,21 @@ impl ast::GenericParamList { } } +impl ast::ArgList { + /// Comma separated args, argument may be empty + pub fn args_maybe_empty(&self) -> impl Iterator<Item = Option<ast::Expr>> { + // (Expr? ','?)* + let mut after_arg = false; + self.syntax().children_with_tokens().filter_map(move |it| { + if into_comma(it.clone()).is_some() { + if std::mem::take(&mut after_arg) { None } else { Some(None) } + } else { + Some(ast::Expr::cast(it.into_node()?).inspect(|_| after_arg = true)) + } + }) + } +} + impl ast::ForExpr { pub fn iterable(&self) -> Option<ast::Expr> { // If the iterable is a BlockExpr, check if the body is missing. |