From 980914356205ce803e9c401a2b7917b08518cbda Mon Sep 17 00:00:00 2001 From: lh123 <1585086582@qq.com> Date: Thu, 16 Jan 2025 18:05:30 +0800 Subject: [PATCH 1/2] feat: complete raw, const keyword --- crates/hir-def/src/body/lower.rs | 3 - crates/ide-completion/src/completions/expr.rs | 27 +++++- crates/ide-completion/src/tests/expression.rs | 89 +++++++++++++++++++ crates/parser/src/grammar/expressions.rs | 13 ++- .../test_data/parser/inline/ok/ref_expr.rast | 19 ++++ .../test_data/parser/inline/ok/ref_expr.rs | 1 + 6 files changed, 144 insertions(+), 8 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index d7e28da644ab..1327bb3ab59c 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -581,10 +581,7 @@ impl ExprCollector<'_> { let mutability = if raw_tok { if e.mut_token().is_some() { Mutability::Mut - } else if e.const_token().is_some() { - Mutability::Shared } else { - never!("parser only remaps to raw_token() if matching mutability token follows"); Mutability::Shared } } else { diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index c2e5eefe1017..49a96e27e701 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -69,8 +69,25 @@ pub(crate) fn complete_expr_path( .. } = expr_ctx; - let wants_mut_token = - ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false); + let has_raw_token = + ref_expr_parent.as_ref().map(|it| it.raw_token().is_some()).unwrap_or(false); + let has_const_token = + ref_expr_parent.as_ref().map(|it| it.const_token().is_some()).unwrap_or(false); + let has_mut_token = + ref_expr_parent.as_ref().map(|it| it.mut_token().is_some()).unwrap_or(false); + + let wants_raw_token = ref_expr_parent.is_some() && !has_raw_token; + let wants_const_token = + ref_expr_parent.is_some() && has_raw_token && !has_const_token && !has_mut_token; + let wants_mut_token = if ref_expr_parent.is_some() { + if has_raw_token { + !has_const_token && !has_mut_token + } else { + !has_mut_token + } + } else { + false + }; let scope_def_applicable = |def| match def { ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false, @@ -354,6 +371,12 @@ pub(crate) fn complete_expr_path( add_keyword("else if", "else if $1 {\n $0\n}"); } + if wants_raw_token { + add_keyword("raw", "raw "); + } + if wants_const_token { + add_keyword("const", "const "); + } if wants_mut_token { add_keyword("mut", "mut "); } diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index d0dc6206f4d8..693787473405 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -66,6 +66,7 @@ fn baz() { kw loop kw match kw mut + kw raw kw return kw self:: kw true @@ -436,6 +437,94 @@ fn completes_in_let_initializer() { ) } +#[test] +fn completes_after_ref_expr() { + check( + r#"fn main() { let _ = &$0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw mut + kw raw + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + check( + r#"fn main() { let _ = &raw $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw const + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw mut + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + check( + r#"fn main() { let _ = &raw const $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + check( + r#"fn main() { let _ = &raw mut $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ) +} + #[test] fn struct_initializer_field_expr() { check( diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs index 3b3f11be1307..03439b784d35 100644 --- a/crates/parser/src/grammar/expressions.rs +++ b/crates/parser/src/grammar/expressions.rs @@ -339,13 +339,20 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik // // raw reference operator // let _ = &raw mut foo; // let _ = &raw const foo; + // let _ = &raw foo; // } T![&] => { m = p.start(); p.bump(T![&]); - if p.at_contextual_kw(T![raw]) && [T![mut], T![const]].contains(&p.nth(1)) { - p.bump_remap(T![raw]); - p.bump_any(); + if p.at_contextual_kw(T![raw]) { + if [T![mut], T![const]].contains(&p.nth(1)) { + p.bump_remap(T![raw]); + p.bump_any(); + } else if p.nth_at(1, SyntaxKind::IDENT) { + // we treat raw as keyword in this case + // &raw foo; + p.bump_remap(T![raw]); + } } else { p.eat(T![mut]); } diff --git a/crates/parser/test_data/parser/inline/ok/ref_expr.rast b/crates/parser/test_data/parser/inline/ok/ref_expr.rast index 108b0802c334..8dc916e5cc54 100644 --- a/crates/parser/test_data/parser/inline/ok/ref_expr.rast +++ b/crates/parser/test_data/parser/inline/ok/ref_expr.rast @@ -134,6 +134,25 @@ SOURCE_FILE NAME_REF IDENT "foo" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + WILDCARD_PAT + UNDERSCORE "_" + WHITESPACE " " + EQ "=" + WHITESPACE " " + REF_EXPR + AMP "&" + RAW_KW "raw" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/ref_expr.rs b/crates/parser/test_data/parser/inline/ok/ref_expr.rs index c5262f4469b0..31a2485b439b 100644 --- a/crates/parser/test_data/parser/inline/ok/ref_expr.rs +++ b/crates/parser/test_data/parser/inline/ok/ref_expr.rs @@ -7,4 +7,5 @@ fn foo() { // raw reference operator let _ = &raw mut foo; let _ = &raw const foo; + let _ = &raw foo; } From a282733b49f9a12092bc2253bf695bb3e90096e5 Mon Sep 17 00:00:00 2001 From: lh123 <1585086582@qq.com> Date: Thu, 16 Jan 2025 19:40:42 +0800 Subject: [PATCH 2/2] don't complete `raw` in `&mut $0` --- crates/ide-completion/src/completions/expr.rs | 13 ++++++------ crates/ide-completion/src/context.rs | 1 + crates/ide-completion/src/context/analysis.rs | 4 ++++ crates/ide-completion/src/tests/expression.rs | 20 +++++++++++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 49a96e27e701..db18b531d7c3 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -62,6 +62,7 @@ pub(crate) fn complete_expr_path( in_condition, incomplete_let, ref ref_expr_parent, + after_amp, ref is_func_update, ref innermost_ret_ty, ref impl_, @@ -69,14 +70,12 @@ pub(crate) fn complete_expr_path( .. } = expr_ctx; - let has_raw_token = - ref_expr_parent.as_ref().map(|it| it.raw_token().is_some()).unwrap_or(false); - let has_const_token = - ref_expr_parent.as_ref().map(|it| it.const_token().is_some()).unwrap_or(false); - let has_mut_token = - ref_expr_parent.as_ref().map(|it| it.mut_token().is_some()).unwrap_or(false); + let (has_raw_token, has_const_token, has_mut_token) = ref_expr_parent + .as_ref() + .map(|it| (it.raw_token().is_some(), it.const_token().is_some(), it.mut_token().is_some())) + .unwrap_or((false, false, false)); - let wants_raw_token = ref_expr_parent.is_some() && !has_raw_token; + let wants_raw_token = ref_expr_parent.is_some() && !has_raw_token && after_amp; let wants_const_token = ref_expr_parent.is_some() && has_raw_token && !has_const_token && !has_mut_token; let wants_mut_token = if ref_expr_parent.is_some() { diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 3705e2c73d64..b3b456d556dd 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -146,6 +146,7 @@ pub(crate) struct PathExprCtx { pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, pub(crate) ref_expr_parent: Option, + pub(crate) after_amp: bool, /// The surrounding RecordExpression we are completing a functional update pub(crate) is_func_update: Option, pub(crate) self_param: Option, diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 1a5609baf9c6..3c4d489c0ff8 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -1151,6 +1151,9 @@ fn classify_name_ref( let after_if_expr = after_if_expr(it.clone()); let ref_expr_parent = path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast); + let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev) + .map(|it| it.kind() == SyntaxKind::AMP) + .unwrap_or(false); let (innermost_ret_ty, self_param) = { let find_ret_ty = |it: SyntaxNode| { if let Some(item) = ast::Item::cast(it.clone()) { @@ -1220,6 +1223,7 @@ fn classify_name_ref( after_if_expr, in_condition, ref_expr_parent, + after_amp, is_func_update, innermost_ret_ty, self_param, diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index 693787473405..e117dbf4bdf0 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -522,6 +522,26 @@ fn completes_after_ref_expr() { kw while kw while let "#]], + ); + check( + r#"fn main() { let _ = &mut $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], ) }