From 1d40867fc8b7f9ff85aa5fe7a8c03a6a4a3531cd Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 25 Nov 2025 16:13:59 +0800 Subject: [PATCH] Fix invalid completion arg nr Example --- ```rust fn foo() { bar(, $0); } fn bar(x: u32, y: i32) {} ``` **Before this PR** ```text ty: u32, name: x ``` **After this PR** ```text ty: i32, name: y ``` --- crates/ide-completion/src/context/analysis.rs | 2 +- crates/ide-completion/src/context/tests.rs | 14 ++++++++++++++ crates/ide-db/src/active_parameter.rs | 17 ++++++++++++----- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index d6d3978385d9..d5a1d2113674 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -657,7 +657,7 @@ fn expected_type_and_name<'db>( cov_mark::hit!(expected_type_fn_param); ActiveParameter::at_token( sema, - token.clone(), + token.clone(), ).map(|ap| { let name = ap.ident().map(NameOrNameRef::Name); (Some(ap.ty), name) diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs index 51d28bd4ff98..41f0db3c5282 100644 --- a/crates/ide-completion/src/context/tests.rs +++ b/crates/ide-completion/src/context/tests.rs @@ -90,6 +90,20 @@ fn bar(x: u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); + check_expected_type_and_name( + r#" +fn foo() { bar(, $0); } +fn bar(x: u32, y: i32) {} +"#, + expect![[r#"ty: i32, name: y"#]], + ); + check_expected_type_and_name( + r#" +fn foo() { bar(, c$0); } +fn bar(x: u32, y: i32) {} +"#, + expect![[r#"ty: i32, name: y"#]], + ); } #[test] diff --git a/crates/ide-db/src/active_parameter.rs b/crates/ide-db/src/active_parameter.rs index 4fb7d142ed5f..f5a5b76c336a 100644 --- a/crates/ide-db/src/active_parameter.rs +++ b/crates/ide-db/src/active_parameter.rs @@ -5,7 +5,7 @@ use hir::{InFile, Semantics, Type}; use parser::T; use span::TextSize; use syntax::{ - AstNode, NodeOrToken, SyntaxToken, + AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, ast::{self, AstChildren, HasArgList, HasAttrs, HasName}, match_ast, }; @@ -102,8 +102,7 @@ pub fn callable_for_node<'db>( arg_list .syntax() .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .filter(|t| t.kind() == T![,]) + .filter_map(into_comma) .take_while(|t| t.text_range().start() <= offset) .count() }); @@ -162,8 +161,7 @@ pub fn generic_def_for_node( let active_param = generic_arg_list .syntax() .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .filter(|t| t.kind() == T![,]) + .filter_map(into_comma) .take_while(|t| t.text_range().start() <= token.text_range().start()) .count(); @@ -174,3 +172,12 @@ pub fn generic_def_for_node( Some((def, active_param, first_arg_is_non_lifetime, variant)) } + +fn into_comma(it: NodeOrToken) -> Option { + 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) +}