about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-01-16 14:24:53 +0000
committerGitHub <noreply@github.com>2025-01-16 14:24:53 +0000
commit99c701307094b6bad58b8df796fa00de0fe0935b (patch)
treec813239b57c80f0f1e868a8ccf1bae625dfc6189
parent8d784becaef21198d1b816855bc49e98228255ab (diff)
parent1f32c2a9ec0655941c68ff5c77bee2a03acf61fb (diff)
downloadrust-99c701307094b6bad58b8df796fa00de0fe0935b.tar.gz
rust-99c701307094b6bad58b8df796fa00de0fe0935b.zip
Merge pull request #18952 from lh123/add-raw-keyword-complete
feat: complete raw, const keyword
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs109
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast19
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs1
8 files changed, 168 insertions, 8 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index d7e28da644a..1327bb3ab59 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index c2e5eefe101..db18b531d7c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/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,8 +70,23 @@ 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, 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 && 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() {
+        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 +370,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/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 461b1dc036c..3a2a4a23a19 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/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<ast::RefExpr>,
+    pub(crate) after_amp: bool,
     /// The surrounding RecordExpression we are completing a functional update
     pub(crate) is_func_update: Option<ast::RecordExpr>,
     pub(crate) self_param: Option<hir::SelfParam>,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 1a5609baf9c..3c4d489c0ff 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index d0dc6206f4d..e117dbf4bdf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/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
@@ -437,6 +438,114 @@ 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
+        "#]],
+    );
+    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
+        "#]],
+    )
+}
+
+#[test]
 fn struct_initializer_field_expr() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
index 3b3f11be130..03439b784d3 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast
index 108b0802c33..8dc916e5cc5 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs
index c5262f4469b..31a2485b439 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs
+++ b/src/tools/rust-analyzer/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;
 }