From 6f5909ec367303d569129dea075c283bd9f92405 Mon Sep 17 00:00:00 2001 From: Hegui Dai Date: Fri, 14 Nov 2025 11:40:29 +0800 Subject: [PATCH] make postfix completion handle all references correctly --- .../ide-completion/src/completions/postfix.rs | 80 ++++++++++++++++++- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs index d62b47152adb..ba1fe649dc4d 100644 --- a/crates/ide-completion/src/completions/postfix.rs +++ b/crates/ide-completion/src/completions/postfix.rs @@ -11,10 +11,11 @@ use ide_db::{ text_edit::TextEdit, ty_filter::TryEnum, }; +use itertools::Itertools; use stdx::never; use syntax::{ SyntaxKind::{EXPR_STMT, STMT_LIST}, - T, TextRange, TextSize, + T, TextRange, TextSize, ToSmolStr, ast::{self, AstNode, AstToken}, match_ast, }; @@ -360,10 +361,18 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) { resulting_element.syntax().parent().and_then(ast::RefExpr::cast) { found_ref_or_deref = true; - let exclusive = parent_ref_element.mut_token().is_some(); + let last_child_or_token = parent_ref_element.syntax().last_child_or_token(); + prefix.insert_str( + 0, + parent_ref_element + .syntax() + .children_with_tokens() + .filter(|it| Some(it) != last_child_or_token.as_ref()) + .format("") + .to_smolstr() + .as_str(), + ); resulting_element = ast::Expr::from(parent_ref_element); - - prefix.insert_str(0, if exclusive { "&mut " } else { "&" }); } if !found_ref_or_deref { @@ -1005,6 +1014,20 @@ fn main() { r#"fn main() { Ok(&&42) }"#, ); + check_edit_with_config( + CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG }, + "ok", + r#"fn main() { &raw mut 42.$0 }"#, + r#"fn main() { Ok(&raw mut 42) }"#, + ); + + check_edit_with_config( + CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG }, + "ok", + r#"fn main() { &raw const 42.$0 }"#, + r#"fn main() { Ok(&raw const 42) }"#, + ); + check_edit_with_config( CompletionConfig { snippets: vec![snippet], ..TEST_CONFIG }, "ok", @@ -1031,6 +1054,55 @@ fn main() { ); } + #[test] + fn postfix_custom_snippets_completion_for_reference_expr() { + // https://github.com/rust-lang/rust-analyzer/issues/21035 + let snippet = Snippet::new( + &[], + &["group".into()], + &["(${receiver})".into()], + "", + &[], + crate::SnippetScope::Expr, + ) + .unwrap(); + + check_edit_with_config( + CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG }, + "group", + r#"fn main() { &[1, 2, 3].g$0 }"#, + r#"fn main() { (&[1, 2, 3]) }"#, + ); + + check_edit_with_config( + CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG }, + "group", + r#"fn main() { &&foo(a, b, 1+1).$0 }"#, + r#"fn main() { (&&foo(a, b, 1+1)) }"#, + ); + + check_edit_with_config( + CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG }, + "group", + r#"fn main() { &mut Foo { a: 1, b: 2, c: 3 }.$0 }"#, + r#"fn main() { (&mut Foo { a: 1, b: 2, c: 3 }) }"#, + ); + + check_edit_with_config( + CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG }, + "group", + r#"fn main() { &raw mut Foo::new().$0 }"#, + r#"fn main() { (&raw mut Foo::new()) }"#, + ); + + check_edit_with_config( + CompletionConfig { snippets: vec![snippet.clone()], ..TEST_CONFIG }, + "group", + r#"fn main() { &raw const Foo::bar::SOME_CONST.$0 }"#, + r#"fn main() { (&raw const Foo::bar::SOME_CONST) }"#, + ); + } + #[test] fn no_postfix_completions_in_if_block_that_has_an_else() { check(