diff options
42 files changed, 850 insertions, 352 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 2c1192f07..3f52f31f8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -39,7 +39,6 @@ jobs: | |||
39 | with: | 39 | with: |
40 | toolchain: stable | 40 | toolchain: stable |
41 | profile: minimal | 41 | profile: minimal |
42 | target: x86_64-unknown-linux-musl | ||
43 | override: true | 42 | override: true |
44 | 43 | ||
45 | - name: Install Nodejs | 44 | - name: Install Nodejs |
diff --git a/.vscode/launch.json b/.vscode/launch.json index 3f74d7566..6a2fff906 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json | |||
@@ -41,7 +41,7 @@ | |||
41 | "outFiles": [ | 41 | "outFiles": [ |
42 | "${workspaceFolder}/editors/code/out/**/*.js" | 42 | "${workspaceFolder}/editors/code/out/**/*.js" |
43 | ], | 43 | ], |
44 | "preLaunchTask": "Build Extension", | 44 | "preLaunchTask": "Build Server and Extension", |
45 | "skipFiles": [ | 45 | "skipFiles": [ |
46 | "<node_internals>/**/*.js" | 46 | "<node_internals>/**/*.js" |
47 | ], | 47 | ], |
@@ -62,7 +62,7 @@ | |||
62 | "outFiles": [ | 62 | "outFiles": [ |
63 | "${workspaceFolder}/editors/code/out/**/*.js" | 63 | "${workspaceFolder}/editors/code/out/**/*.js" |
64 | ], | 64 | ], |
65 | "preLaunchTask": "Build Extension", | 65 | "preLaunchTask": "Build Server (Release) and Extension", |
66 | "skipFiles": [ | 66 | "skipFiles": [ |
67 | "<node_internals>/**/*.js" | 67 | "<node_internals>/**/*.js" |
68 | ], | 68 | ], |
diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4037e7cce..0969ce89a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json | |||
@@ -4,7 +4,7 @@ | |||
4 | "version": "2.0.0", | 4 | "version": "2.0.0", |
5 | "tasks": [ | 5 | "tasks": [ |
6 | { | 6 | { |
7 | "label": "Build Extension", | 7 | "label": "Build Extension in Background", |
8 | "group": "build", | 8 | "group": "build", |
9 | "type": "npm", | 9 | "type": "npm", |
10 | "script": "watch", | 10 | "script": "watch", |
@@ -16,11 +16,40 @@ | |||
16 | "isBackground": true, | 16 | "isBackground": true, |
17 | }, | 17 | }, |
18 | { | 18 | { |
19 | "label": "Build Extension", | ||
20 | "group": "build", | ||
21 | "type": "npm", | ||
22 | "script": "build", | ||
23 | "path": "editors/code/", | ||
24 | "problemMatcher": { | ||
25 | "base": "$tsc", | ||
26 | "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] | ||
27 | }, | ||
28 | }, | ||
29 | { | ||
19 | "label": "Build Server", | 30 | "label": "Build Server", |
20 | "group": "build", | 31 | "group": "build", |
21 | "type": "shell", | 32 | "type": "shell", |
22 | "command": "cargo build --package rust-analyzer", | 33 | "command": "cargo build --package rust-analyzer", |
23 | "problemMatcher": "$rustc" | 34 | "problemMatcher": "$rustc" |
24 | }, | 35 | }, |
36 | { | ||
37 | "label": "Build Server (Release)", | ||
38 | "group": "build", | ||
39 | "type": "shell", | ||
40 | "command": "cargo build --release --package rust-analyzer", | ||
41 | "problemMatcher": "$rustc" | ||
42 | }, | ||
43 | |||
44 | { | ||
45 | "label": "Build Server and Extension", | ||
46 | "dependsOn": ["Build Server", "Build Extension"], | ||
47 | "problemMatcher": "$rustc" | ||
48 | }, | ||
49 | { | ||
50 | "label": "Build Server (Release) and Extension", | ||
51 | "dependsOn": ["Build Server (Release)", "Build Extension"], | ||
52 | "problemMatcher": "$rustc" | ||
53 | } | ||
25 | ] | 54 | ] |
26 | } | 55 | } |
diff --git a/Cargo.lock b/Cargo.lock index 367ff3f82..e933598fb 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -68,9 +68,9 @@ dependencies = [ | |||
68 | 68 | ||
69 | [[package]] | 69 | [[package]] |
70 | name = "base64" | 70 | name = "base64" |
71 | version = "0.11.0" | 71 | version = "0.12.0" |
72 | source = "registry+https://github.com/rust-lang/crates.io-index" | 72 | source = "registry+https://github.com/rust-lang/crates.io-index" |
73 | checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" | 73 | checksum = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3" |
74 | 74 | ||
75 | [[package]] | 75 | [[package]] |
76 | name = "bitflags" | 76 | name = "bitflags" |
@@ -645,9 +645,9 @@ dependencies = [ | |||
645 | 645 | ||
646 | [[package]] | 646 | [[package]] |
647 | name = "lsp-types" | 647 | name = "lsp-types" |
648 | version = "0.73.0" | 648 | version = "0.74.0" |
649 | source = "registry+https://github.com/rust-lang/crates.io-index" | 649 | source = "registry+https://github.com/rust-lang/crates.io-index" |
650 | checksum = "93d0cf64ea141b43d9e055f6b9df13f0bce32b103d84237509ce0a571ab9b159" | 650 | checksum = "820f746e5716ab9a2d664794636188bd003023b72e55404ee27105dc22869922" |
651 | dependencies = [ | 651 | dependencies = [ |
652 | "base64", | 652 | "base64", |
653 | "bitflags", | 653 | "bitflags", |
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs index 03806724a..49deb6701 100644 --- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | |||
@@ -1,11 +1,12 @@ | |||
1 | use ra_ide_db::RootDatabase; | ||
1 | use ra_syntax::{ | 2 | use ra_syntax::{ |
2 | ast::{self, AstNode, NameOwner}, | 3 | ast::{self, AstNode, NameOwner}, |
3 | TextSize, | 4 | TextSize, |
4 | }; | 5 | }; |
5 | use stdx::format_to; | 6 | use stdx::format_to; |
6 | 7 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId}; |
8 | use ra_ide_db::RootDatabase; | 9 | use test_utils::tested_by; |
9 | 10 | ||
10 | // Assist add_from_impl_for_enum | 11 | // Assist add_from_impl_for_enum |
11 | // | 12 | // |
@@ -41,7 +42,8 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> { | |||
41 | _ => return None, | 42 | _ => return None, |
42 | }; | 43 | }; |
43 | 44 | ||
44 | if already_has_from_impl(ctx.sema, &variant) { | 45 | if existing_from_impl(ctx.sema, &variant).is_some() { |
46 | tested_by!(test_add_from_impl_already_exists); | ||
45 | return None; | 47 | return None; |
46 | } | 48 | } |
47 | 49 | ||
@@ -70,41 +72,33 @@ impl From<{0}> for {1} {{ | |||
70 | ) | 72 | ) |
71 | } | 73 | } |
72 | 74 | ||
73 | fn already_has_from_impl( | 75 | fn existing_from_impl( |
74 | sema: &'_ hir::Semantics<'_, RootDatabase>, | 76 | sema: &'_ hir::Semantics<'_, RootDatabase>, |
75 | variant: &ast::EnumVariant, | 77 | variant: &ast::EnumVariant, |
76 | ) -> bool { | 78 | ) -> Option<()> { |
77 | let scope = sema.scope(&variant.syntax()); | 79 | let variant = sema.to_def(variant)?; |
80 | let enum_ = variant.parent_enum(sema.db); | ||
81 | let krate = enum_.module(sema.db).krate(); | ||
78 | 82 | ||
79 | let from_path = ast::make::path_from_text("From"); | 83 | let from_trait = FamousDefs(sema, krate).core_convert_From()?; |
80 | let from_hir_path = match hir::Path::from_ast(from_path) { | ||
81 | Some(p) => p, | ||
82 | None => return false, | ||
83 | }; | ||
84 | let from_trait = match scope.resolve_hir_path(&from_hir_path) { | ||
85 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(t))) => t, | ||
86 | _ => return false, | ||
87 | }; | ||
88 | 84 | ||
89 | let e: hir::Enum = match sema.to_def(&variant.parent_enum()) { | 85 | let enum_type = enum_.ty(sema.db); |
90 | Some(e) => e, | ||
91 | None => return false, | ||
92 | }; | ||
93 | let e_ty = e.ty(sema.db); | ||
94 | 86 | ||
95 | let hir_enum_var: hir::EnumVariant = match sema.to_def(variant) { | 87 | let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db); |
96 | Some(ev) => ev, | ||
97 | None => return false, | ||
98 | }; | ||
99 | let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db); | ||
100 | 88 | ||
101 | e_ty.impls_trait(sema.db, from_trait, &[var_ty]) | 89 | if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) { |
90 | Some(()) | ||
91 | } else { | ||
92 | None | ||
93 | } | ||
102 | } | 94 | } |
103 | 95 | ||
104 | #[cfg(test)] | 96 | #[cfg(test)] |
105 | mod tests { | 97 | mod tests { |
106 | use super::*; | 98 | use super::*; |
99 | |||
107 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 100 | use crate::helpers::{check_assist, check_assist_not_applicable}; |
101 | use test_utils::covers; | ||
108 | 102 | ||
109 | #[test] | 103 | #[test] |
110 | fn test_add_from_impl_for_enum() { | 104 | fn test_add_from_impl_for_enum() { |
@@ -136,36 +130,40 @@ mod tests { | |||
136 | ); | 130 | ); |
137 | } | 131 | } |
138 | 132 | ||
133 | fn check_not_applicable(ra_fixture: &str) { | ||
134 | let fixture = | ||
135 | format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
136 | check_assist_not_applicable(add_from_impl_for_enum, &fixture) | ||
137 | } | ||
138 | |||
139 | #[test] | 139 | #[test] |
140 | fn test_add_from_impl_no_element() { | 140 | fn test_add_from_impl_no_element() { |
141 | check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One }"); | 141 | check_not_applicable("enum A { <|>One }"); |
142 | } | 142 | } |
143 | 143 | ||
144 | #[test] | 144 | #[test] |
145 | fn test_add_from_impl_more_than_one_element_in_tuple() { | 145 | fn test_add_from_impl_more_than_one_element_in_tuple() { |
146 | check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One(u32, String) }"); | 146 | check_not_applicable("enum A { <|>One(u32, String) }"); |
147 | } | 147 | } |
148 | 148 | ||
149 | #[test] | 149 | #[test] |
150 | fn test_add_from_impl_struct_variant() { | 150 | fn test_add_from_impl_struct_variant() { |
151 | check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One { x: u32 } }"); | 151 | check_not_applicable("enum A { <|>One { x: u32 } }"); |
152 | } | 152 | } |
153 | 153 | ||
154 | #[test] | 154 | #[test] |
155 | fn test_add_from_impl_already_exists() { | 155 | fn test_add_from_impl_already_exists() { |
156 | check_assist_not_applicable( | 156 | covers!(test_add_from_impl_already_exists); |
157 | add_from_impl_for_enum, | 157 | check_not_applicable( |
158 | r#"enum A { <|>One(u32), } | 158 | r#" |
159 | enum A { <|>One(u32), } | ||
159 | 160 | ||
160 | impl From<u32> for A { | 161 | impl From<u32> for A { |
161 | fn from(v: u32) -> Self { | 162 | fn from(v: u32) -> Self { |
162 | A::One(v) | 163 | A::One(v) |
163 | } | 164 | } |
164 | } | 165 | } |
165 | 166 | "#, | |
166 | pub trait From<T> { | ||
167 | fn from(T) -> Self; | ||
168 | }"#, | ||
169 | ); | 167 | ); |
170 | } | 168 | } |
171 | 169 | ||
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index 0a0a88f3d..9841f6980 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -1,11 +1,10 @@ | |||
1 | use ra_fmt::unwrap_trivial_block; | 1 | use ra_fmt::unwrap_trivial_block; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, make}, | 3 | ast::{self, edit::IndentLevel, make}, |
4 | AstNode, | 4 | AstNode, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; |
8 | use ast::edit::IndentLevel; | ||
9 | 8 | ||
10 | // Assist: replace_if_let_with_match | 9 | // Assist: replace_if_let_with_match |
11 | // | 10 | // |
@@ -44,15 +43,21 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
44 | ast::ElseBranch::IfExpr(_) => return None, | 43 | ast::ElseBranch::IfExpr(_) => return None, |
45 | }; | 44 | }; |
46 | 45 | ||
47 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| { | 46 | let sema = ctx.sema; |
47 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", move |edit| { | ||
48 | let match_expr = { | 48 | let match_expr = { |
49 | let then_arm = { | 49 | let then_arm = { |
50 | let then_expr = unwrap_trivial_block(then_block); | 50 | let then_expr = unwrap_trivial_block(then_block); |
51 | make::match_arm(vec![pat], then_expr) | 51 | make::match_arm(vec![pat.clone()], then_expr) |
52 | }; | 52 | }; |
53 | let else_arm = { | 53 | let else_arm = { |
54 | let pattern = sema | ||
55 | .type_of_pat(&pat) | ||
56 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) | ||
57 | .map(|it| it.sad_pattern()) | ||
58 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
54 | let else_expr = unwrap_trivial_block(else_block); | 59 | let else_expr = unwrap_trivial_block(else_block); |
55 | make::match_arm(vec![make::placeholder_pat().into()], else_expr) | 60 | make::match_arm(vec![pattern], else_expr) |
56 | }; | 61 | }; |
57 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | 62 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) |
58 | }; | 63 | }; |
@@ -68,6 +73,7 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
68 | #[cfg(test)] | 73 | #[cfg(test)] |
69 | mod tests { | 74 | mod tests { |
70 | use super::*; | 75 | use super::*; |
76 | |||
71 | use crate::helpers::{check_assist, check_assist_target}; | 77 | use crate::helpers::{check_assist, check_assist_target}; |
72 | 78 | ||
73 | #[test] | 79 | #[test] |
@@ -145,4 +151,64 @@ impl VariantData { | |||
145 | }", | 151 | }", |
146 | ); | 152 | ); |
147 | } | 153 | } |
154 | |||
155 | #[test] | ||
156 | fn special_case_option() { | ||
157 | check_assist( | ||
158 | replace_if_let_with_match, | ||
159 | r#" | ||
160 | enum Option<T> { Some(T), None } | ||
161 | use Option::*; | ||
162 | |||
163 | fn foo(x: Option<i32>) { | ||
164 | <|>if let Some(x) = x { | ||
165 | println!("{}", x) | ||
166 | } else { | ||
167 | println!("none") | ||
168 | } | ||
169 | } | ||
170 | "#, | ||
171 | r#" | ||
172 | enum Option<T> { Some(T), None } | ||
173 | use Option::*; | ||
174 | |||
175 | fn foo(x: Option<i32>) { | ||
176 | <|>match x { | ||
177 | Some(x) => println!("{}", x), | ||
178 | None => println!("none"), | ||
179 | } | ||
180 | } | ||
181 | "#, | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn special_case_result() { | ||
187 | check_assist( | ||
188 | replace_if_let_with_match, | ||
189 | r#" | ||
190 | enum Result<T, E> { Ok(T), Err(E) } | ||
191 | use Result::*; | ||
192 | |||
193 | fn foo(x: Result<i32, ()>) { | ||
194 | <|>if let Ok(x) = x { | ||
195 | println!("{}", x) | ||
196 | } else { | ||
197 | println!("none") | ||
198 | } | ||
199 | } | ||
200 | "#, | ||
201 | r#" | ||
202 | enum Result<T, E> { Ok(T), Err(E) } | ||
203 | use Result::*; | ||
204 | |||
205 | fn foo(x: Result<i32, ()>) { | ||
206 | <|>match x { | ||
207 | Ok(x) => println!("{}", x), | ||
208 | Err(_) => println!("none"), | ||
209 | } | ||
210 | } | ||
211 | "#, | ||
212 | ); | ||
213 | } | ||
148 | } | 214 | } |
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs index bdbaae389..0cf23b754 100644 --- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use std::iter::once; | 1 | use std::iter::once; |
2 | 2 | ||
3 | use hir::Adt; | ||
4 | use ra_syntax::{ | 3 | use ra_syntax::{ |
5 | ast::{ | 4 | ast::{ |
6 | self, | 5 | self, |
@@ -12,6 +11,7 @@ use ra_syntax::{ | |||
12 | 11 | ||
13 | use crate::{ | 12 | use crate::{ |
14 | assist_ctx::{Assist, AssistCtx}, | 13 | assist_ctx::{Assist, AssistCtx}, |
14 | utils::TryEnum, | ||
15 | AssistId, | 15 | AssistId, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -45,20 +45,10 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { | |||
45 | let init = let_stmt.initializer()?; | 45 | let init = let_stmt.initializer()?; |
46 | let original_pat = let_stmt.pat()?; | 46 | let original_pat = let_stmt.pat()?; |
47 | let ty = ctx.sema.type_of_expr(&init)?; | 47 | let ty = ctx.sema.type_of_expr(&init)?; |
48 | let enum_ = match ty.as_adt() { | 48 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); |
49 | Some(Adt::Enum(it)) => it, | ||
50 | _ => return None, | ||
51 | }; | ||
52 | let happy_case = | ||
53 | [("Result", "Ok"), ("Option", "Some")].iter().find_map(|(known_type, happy_case)| { | ||
54 | if &enum_.name(ctx.db).to_string() == known_type { | ||
55 | return Some(happy_case); | ||
56 | } | ||
57 | None | ||
58 | }); | ||
59 | 49 | ||
60 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| { | 50 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| { |
61 | let with_placeholder: ast::Pat = match happy_case { | 51 | let with_placeholder: ast::Pat = match happy_variant { |
62 | None => make::placeholder_pat().into(), | 52 | None => make::placeholder_pat().into(), |
63 | Some(var_name) => make::tuple_struct_pat( | 53 | Some(var_name) => make::tuple_struct_pat( |
64 | make::path_unqualified(make::path_segment(make::name_ref(var_name))), | 54 | make::path_unqualified(make::path_segment(make::name_ref(var_name))), |
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs index 62cb7a763..62d4ea522 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, make}, | 4 | ast::{self, edit::IndentLevel, make}, |
5 | AstNode, | 5 | AstNode, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; |
9 | use ast::edit::IndentLevel; | ||
10 | 9 | ||
11 | // Assist: replace_unwrap_with_match | 10 | // Assist: replace_unwrap_with_match |
12 | // | 11 | // |
@@ -38,42 +37,27 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
38 | } | 37 | } |
39 | let caller = method_call.expr()?; | 38 | let caller = method_call.expr()?; |
40 | let ty = ctx.sema.type_of_expr(&caller)?; | 39 | let ty = ctx.sema.type_of_expr(&caller)?; |
40 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case(); | ||
41 | 41 | ||
42 | let type_name = ty.as_adt()?.name(ctx.sema.db).to_string(); | 42 | ctx.add_assist(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", |edit| { |
43 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | ||
44 | let it = make::bind_pat(make::name("a")).into(); | ||
45 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
43 | 46 | ||
44 | for (unwrap_type, variant_name) in [("Result", "Ok"), ("Option", "Some")].iter() { | 47 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); |
45 | if &type_name == unwrap_type { | 48 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
46 | return ctx.add_assist( | ||
47 | AssistId("replace_unwrap_with_match"), | ||
48 | "Replace unwrap with match", | ||
49 | |edit| { | ||
50 | let ok_path = | ||
51 | make::path_unqualified(make::path_segment(make::name_ref(variant_name))); | ||
52 | let it = make::bind_pat(make::name("a")).into(); | ||
53 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
54 | 49 | ||
55 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 50 | let unreachable_call = make::unreachable_macro_call().into(); |
56 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 51 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); |
57 | 52 | ||
58 | let unreachable_call = make::unreachable_macro_call().into(); | 53 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |
59 | let err_arm = make::match_arm( | 54 | let match_expr = make::expr_match(caller.clone(), match_arm_list); |
60 | iter::once(make::placeholder_pat().into()), | 55 | let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); |
61 | unreachable_call, | ||
62 | ); | ||
63 | 56 | ||
64 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 57 | edit.target(method_call.syntax().text_range()); |
65 | let match_expr = make::expr_match(caller.clone(), match_arm_list); | 58 | edit.set_cursor(caller.syntax().text_range().start()); |
66 | let match_expr = | 59 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); |
67 | IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); | 60 | }) |
68 | |||
69 | edit.target(method_call.syntax().text_range()); | ||
70 | edit.set_cursor(caller.syntax().text_range().start()); | ||
71 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); | ||
72 | }, | ||
73 | ); | ||
74 | } | ||
75 | } | ||
76 | None | ||
77 | } | 61 | } |
78 | 62 | ||
79 | #[cfg(test)] | 63 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs index 6c2a2b8b6..8d910205f 100644 --- a/crates/ra_assists/src/marks.rs +++ b/crates/ra_assists/src/marks.rs | |||
@@ -8,4 +8,5 @@ test_utils::marks![ | |||
8 | test_not_inline_mut_variable | 8 | test_not_inline_mut_variable |
9 | test_not_applicable_if_variable_unused | 9 | test_not_applicable_if_variable_unused |
10 | change_visibility_field_false_positive | 10 | change_visibility_field_false_positive |
11 | test_add_from_impl_already_exists | ||
11 | ]; | 12 | ]; |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 3d6c59bda..efd988697 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -1,7 +1,9 @@ | |||
1 | //! Assorted functions shared by several assists. | 1 | //! Assorted functions shared by several assists. |
2 | pub(crate) mod insert_use; | 2 | pub(crate) mod insert_use; |
3 | 3 | ||
4 | use hir::Semantics; | 4 | use std::iter; |
5 | |||
6 | use hir::{Adt, Crate, Semantics, Trait, Type}; | ||
5 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 8 | use ra_syntax::{ |
7 | ast::{self, make, NameOwner}, | 9 | ast::{self, make, NameOwner}, |
@@ -99,3 +101,109 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | |||
99 | _ => None, | 101 | _ => None, |
100 | } | 102 | } |
101 | } | 103 | } |
104 | |||
105 | #[derive(Clone, Copy)] | ||
106 | pub(crate) enum TryEnum { | ||
107 | Result, | ||
108 | Option, | ||
109 | } | ||
110 | |||
111 | impl TryEnum { | ||
112 | const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; | ||
113 | |||
114 | pub(crate) fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> { | ||
115 | let enum_ = match ty.as_adt() { | ||
116 | Some(Adt::Enum(it)) => it, | ||
117 | _ => return None, | ||
118 | }; | ||
119 | TryEnum::ALL.iter().find_map(|&var| { | ||
120 | if &enum_.name(sema.db).to_string() == var.type_name() { | ||
121 | return Some(var); | ||
122 | } | ||
123 | None | ||
124 | }) | ||
125 | } | ||
126 | |||
127 | pub(crate) fn happy_case(self) -> &'static str { | ||
128 | match self { | ||
129 | TryEnum::Result => "Ok", | ||
130 | TryEnum::Option => "Some", | ||
131 | } | ||
132 | } | ||
133 | |||
134 | pub(crate) fn sad_pattern(self) -> ast::Pat { | ||
135 | match self { | ||
136 | TryEnum::Result => make::tuple_struct_pat( | ||
137 | make::path_unqualified(make::path_segment(make::name_ref("Err"))), | ||
138 | iter::once(make::placeholder_pat().into()), | ||
139 | ) | ||
140 | .into(), | ||
141 | TryEnum::Option => make::bind_pat(make::name("None")).into(), | ||
142 | } | ||
143 | } | ||
144 | |||
145 | fn type_name(self) -> &'static str { | ||
146 | match self { | ||
147 | TryEnum::Result => "Result", | ||
148 | TryEnum::Option => "Option", | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /// Helps with finding well-know things inside the standard library. This is | ||
154 | /// somewhat similar to the known paths infra inside hir, but it different; We | ||
155 | /// want to make sure that IDE specific paths don't become interesting inside | ||
156 | /// the compiler itself as well. | ||
157 | pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate); | ||
158 | |||
159 | #[allow(non_snake_case)] | ||
160 | impl FamousDefs<'_, '_> { | ||
161 | #[cfg(test)] | ||
162 | pub(crate) const FIXTURE: &'static str = r#" | ||
163 | //- /libcore.rs crate:core | ||
164 | pub mod convert{ | ||
165 | pub trait From<T> { | ||
166 | fn from(T) -> Self; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | pub mod prelude { pub use crate::convert::From } | ||
171 | #[prelude_import] | ||
172 | pub use prelude::*; | ||
173 | "#; | ||
174 | |||
175 | pub(crate) fn core_convert_From(&self) -> Option<Trait> { | ||
176 | self.find_trait("core:convert:From") | ||
177 | } | ||
178 | |||
179 | fn find_trait(&self, path: &str) -> Option<Trait> { | ||
180 | let db = self.0.db; | ||
181 | let mut path = path.split(':'); | ||
182 | let trait_ = path.next_back()?; | ||
183 | let std_crate = path.next()?; | ||
184 | let std_crate = self | ||
185 | .1 | ||
186 | .dependencies(db) | ||
187 | .into_iter() | ||
188 | .find(|dep| &dep.name.to_string() == std_crate)? | ||
189 | .krate; | ||
190 | |||
191 | let mut module = std_crate.root_module(db)?; | ||
192 | for segment in path { | ||
193 | module = module.children(db).find_map(|child| { | ||
194 | let name = child.name(db)?; | ||
195 | if &name.to_string() == segment { | ||
196 | Some(child) | ||
197 | } else { | ||
198 | None | ||
199 | } | ||
200 | })?; | ||
201 | } | ||
202 | let def = | ||
203 | module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; | ||
204 | match def { | ||
205 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), | ||
206 | _ => None, | ||
207 | } | ||
208 | } | ||
209 | } | ||
diff --git a/crates/ra_flycheck/Cargo.toml b/crates/ra_flycheck/Cargo.toml index 76e5cada4..324c33d9d 100644 --- a/crates/ra_flycheck/Cargo.toml +++ b/crates/ra_flycheck/Cargo.toml | |||
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"] | |||
6 | 6 | ||
7 | [dependencies] | 7 | [dependencies] |
8 | crossbeam-channel = "0.4.0" | 8 | crossbeam-channel = "0.4.0" |
9 | lsp-types = { version = "0.73.0", features = ["proposed"] } | 9 | lsp-types = { version = "0.74.0", features = ["proposed"] } |
10 | log = "0.4.8" | 10 | log = "0.4.8" |
11 | cargo_metadata = "0.9.1" | 11 | cargo_metadata = "0.9.1" |
12 | serde_json = "1.0.48" | 12 | serde_json = "1.0.48" |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index fb788736d..3fb419571 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1157,18 +1157,21 @@ impl Type { | |||
1157 | 1157 | ||
1158 | pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { | 1158 | pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { |
1159 | if let Ty::Apply(a_ty) = &self.ty.value { | 1159 | if let Ty::Apply(a_ty) = &self.ty.value { |
1160 | if let TypeCtor::Adt(AdtId::StructId(s)) = a_ty.ctor { | 1160 | let variant_id = match a_ty.ctor { |
1161 | let var_def = s.into(); | 1161 | TypeCtor::Adt(AdtId::StructId(s)) => s.into(), |
1162 | return db | 1162 | TypeCtor::Adt(AdtId::UnionId(u)) => u.into(), |
1163 | .field_types(var_def) | 1163 | _ => return Vec::new(), |
1164 | .iter() | 1164 | }; |
1165 | .map(|(local_id, ty)| { | 1165 | |
1166 | let def = Field { parent: var_def.into(), id: local_id }; | 1166 | return db |
1167 | let ty = ty.clone().subst(&a_ty.parameters); | 1167 | .field_types(variant_id) |
1168 | (def, self.derived(ty)) | 1168 | .iter() |
1169 | }) | 1169 | .map(|(local_id, ty)| { |
1170 | .collect(); | 1170 | let def = Field { parent: variant_id.into(), id: local_id }; |
1171 | } | 1171 | let ty = ty.clone().subst(&a_ty.parameters); |
1172 | (def, self.derived(ty)) | ||
1173 | }) | ||
1174 | .collect(); | ||
1172 | }; | 1175 | }; |
1173 | Vec::new() | 1176 | Vec::new() |
1174 | } | 1177 | } |
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index bb45b0f1d..e60f879a3 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::db::AstDatabase; | 11 | use crate::db::AstDatabase; |
12 | use crate::{name, quote, LazyMacroId, MacroDefId, MacroDefKind}; | 12 | use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; |
13 | 13 | ||
14 | macro_rules! register_builtin { | 14 | macro_rules! register_builtin { |
15 | ( $($trait:ident => $expand:ident),* ) => { | 15 | ( $($trait:ident => $expand:ident),* ) => { |
@@ -153,76 +153,113 @@ fn expand_simple_derive( | |||
153 | Ok(expanded) | 153 | Ok(expanded) |
154 | } | 154 | } |
155 | 155 | ||
156 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { | ||
157 | // FIXME: make hygiene works for builtin derive macro | ||
158 | // such that $crate can be used here. | ||
159 | |||
160 | let m: MacroCallId = id.into(); | ||
161 | let file_id = m.as_file().original_file(db); | ||
162 | let cg = db.crate_graph(); | ||
163 | let krates = db.relevant_crates(file_id); | ||
164 | let krate = match krates.get(0) { | ||
165 | Some(krate) => krate, | ||
166 | None => { | ||
167 | let tt = quote! { core }; | ||
168 | return tt.token_trees[0].clone(); | ||
169 | } | ||
170 | }; | ||
171 | |||
172 | // XXX | ||
173 | // All crates except core itself should have a dependency on core, | ||
174 | // We detect `core` by seeing whether it doesn't have such a dependency. | ||
175 | let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") { | ||
176 | quote! { core } | ||
177 | } else { | ||
178 | quote! { crate } | ||
179 | }; | ||
180 | |||
181 | tt.token_trees[0].clone() | ||
182 | } | ||
183 | |||
156 | fn copy_expand( | 184 | fn copy_expand( |
157 | _db: &dyn AstDatabase, | 185 | db: &dyn AstDatabase, |
158 | _id: LazyMacroId, | 186 | id: LazyMacroId, |
159 | tt: &tt::Subtree, | 187 | tt: &tt::Subtree, |
160 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 188 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
161 | expand_simple_derive(tt, quote! { std::marker::Copy }) | 189 | let krate = find_builtin_crate(db, id); |
190 | expand_simple_derive(tt, quote! { #krate::marker::Copy }) | ||
162 | } | 191 | } |
163 | 192 | ||
164 | fn clone_expand( | 193 | fn clone_expand( |
165 | _db: &dyn AstDatabase, | 194 | db: &dyn AstDatabase, |
166 | _id: LazyMacroId, | 195 | id: LazyMacroId, |
167 | tt: &tt::Subtree, | 196 | tt: &tt::Subtree, |
168 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 197 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
169 | expand_simple_derive(tt, quote! { std::clone::Clone }) | 198 | let krate = find_builtin_crate(db, id); |
199 | expand_simple_derive(tt, quote! { #krate::clone::Clone }) | ||
170 | } | 200 | } |
171 | 201 | ||
172 | fn default_expand( | 202 | fn default_expand( |
173 | _db: &dyn AstDatabase, | 203 | db: &dyn AstDatabase, |
174 | _id: LazyMacroId, | 204 | id: LazyMacroId, |
175 | tt: &tt::Subtree, | 205 | tt: &tt::Subtree, |
176 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 206 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
177 | expand_simple_derive(tt, quote! { std::default::Default }) | 207 | let krate = find_builtin_crate(db, id); |
208 | expand_simple_derive(tt, quote! { #krate::default::Default }) | ||
178 | } | 209 | } |
179 | 210 | ||
180 | fn debug_expand( | 211 | fn debug_expand( |
181 | _db: &dyn AstDatabase, | 212 | db: &dyn AstDatabase, |
182 | _id: LazyMacroId, | 213 | id: LazyMacroId, |
183 | tt: &tt::Subtree, | 214 | tt: &tt::Subtree, |
184 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 215 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
185 | expand_simple_derive(tt, quote! { std::fmt::Debug }) | 216 | let krate = find_builtin_crate(db, id); |
217 | expand_simple_derive(tt, quote! { #krate::fmt::Debug }) | ||
186 | } | 218 | } |
187 | 219 | ||
188 | fn hash_expand( | 220 | fn hash_expand( |
189 | _db: &dyn AstDatabase, | 221 | db: &dyn AstDatabase, |
190 | _id: LazyMacroId, | 222 | id: LazyMacroId, |
191 | tt: &tt::Subtree, | 223 | tt: &tt::Subtree, |
192 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 224 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
193 | expand_simple_derive(tt, quote! { std::hash::Hash }) | 225 | let krate = find_builtin_crate(db, id); |
226 | expand_simple_derive(tt, quote! { #krate::hash::Hash }) | ||
194 | } | 227 | } |
195 | 228 | ||
196 | fn eq_expand( | 229 | fn eq_expand( |
197 | _db: &dyn AstDatabase, | 230 | db: &dyn AstDatabase, |
198 | _id: LazyMacroId, | 231 | id: LazyMacroId, |
199 | tt: &tt::Subtree, | 232 | tt: &tt::Subtree, |
200 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 233 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
201 | expand_simple_derive(tt, quote! { std::cmp::Eq }) | 234 | let krate = find_builtin_crate(db, id); |
235 | expand_simple_derive(tt, quote! { #krate::cmp::Eq }) | ||
202 | } | 236 | } |
203 | 237 | ||
204 | fn partial_eq_expand( | 238 | fn partial_eq_expand( |
205 | _db: &dyn AstDatabase, | 239 | db: &dyn AstDatabase, |
206 | _id: LazyMacroId, | 240 | id: LazyMacroId, |
207 | tt: &tt::Subtree, | 241 | tt: &tt::Subtree, |
208 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 242 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
209 | expand_simple_derive(tt, quote! { std::cmp::PartialEq }) | 243 | let krate = find_builtin_crate(db, id); |
244 | expand_simple_derive(tt, quote! { #krate::cmp::PartialEq }) | ||
210 | } | 245 | } |
211 | 246 | ||
212 | fn ord_expand( | 247 | fn ord_expand( |
213 | _db: &dyn AstDatabase, | 248 | db: &dyn AstDatabase, |
214 | _id: LazyMacroId, | 249 | id: LazyMacroId, |
215 | tt: &tt::Subtree, | 250 | tt: &tt::Subtree, |
216 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 251 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
217 | expand_simple_derive(tt, quote! { std::cmp::Ord }) | 252 | let krate = find_builtin_crate(db, id); |
253 | expand_simple_derive(tt, quote! { #krate::cmp::Ord }) | ||
218 | } | 254 | } |
219 | 255 | ||
220 | fn partial_ord_expand( | 256 | fn partial_ord_expand( |
221 | _db: &dyn AstDatabase, | 257 | db: &dyn AstDatabase, |
222 | _id: LazyMacroId, | 258 | id: LazyMacroId, |
223 | tt: &tt::Subtree, | 259 | tt: &tt::Subtree, |
224 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 260 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
225 | expand_simple_derive(tt, quote! { std::cmp::PartialOrd }) | 261 | let krate = find_builtin_crate(db, id); |
262 | expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd }) | ||
226 | } | 263 | } |
227 | 264 | ||
228 | #[cfg(test)] | 265 | #[cfg(test)] |
@@ -234,8 +271,18 @@ mod tests { | |||
234 | 271 | ||
235 | fn expand_builtin_derive(s: &str, name: Name) -> String { | 272 | fn expand_builtin_derive(s: &str, name: Name) -> String { |
236 | let def = find_builtin_derive(&name).unwrap(); | 273 | let def = find_builtin_derive(&name).unwrap(); |
274 | let fixture = format!( | ||
275 | r#"//- /main.rs crate:main deps:core | ||
276 | <|> | ||
277 | {} | ||
278 | //- /lib.rs crate:core | ||
279 | // empty | ||
280 | "#, | ||
281 | s | ||
282 | ); | ||
237 | 283 | ||
238 | let (db, file_id) = TestDB::with_single_file(&s); | 284 | let (db, file_pos) = TestDB::with_position(&fixture); |
285 | let file_id = file_pos.file_id; | ||
239 | let parsed = db.parse(file_id); | 286 | let parsed = db.parse(file_id); |
240 | let items: Vec<_> = | 287 | let items: Vec<_> = |
241 | parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect(); | 288 | parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect(); |
@@ -264,7 +311,7 @@ mod tests { | |||
264 | known::Copy, | 311 | known::Copy, |
265 | ); | 312 | ); |
266 | 313 | ||
267 | assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}"); | 314 | assert_eq!(expanded, "impl< >core::marker::CopyforFoo< >{}"); |
268 | } | 315 | } |
269 | 316 | ||
270 | #[test] | 317 | #[test] |
@@ -279,7 +326,7 @@ mod tests { | |||
279 | 326 | ||
280 | assert_eq!( | 327 | assert_eq!( |
281 | expanded, | 328 | expanded, |
282 | "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}" | 329 | "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}" |
283 | ); | 330 | ); |
284 | } | 331 | } |
285 | 332 | ||
@@ -297,7 +344,7 @@ mod tests { | |||
297 | 344 | ||
298 | assert_eq!( | 345 | assert_eq!( |
299 | expanded, | 346 | expanded, |
300 | "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}" | 347 | "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}" |
301 | ); | 348 | ); |
302 | } | 349 | } |
303 | 350 | ||
@@ -313,7 +360,7 @@ mod tests { | |||
313 | 360 | ||
314 | assert_eq!( | 361 | assert_eq!( |
315 | expanded, | 362 | expanded, |
316 | "impl<T0:std::clone::Clone,T1:std::clone::Clone>std::clone::CloneforFoo<T0,T1>{}" | 363 | "impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}" |
317 | ); | 364 | ); |
318 | } | 365 | } |
319 | } | 366 | } |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 279c06d65..a8ef32ec5 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -487,6 +487,18 @@ impl<T> Binders<T> { | |||
487 | pub fn new(num_binders: usize, value: T) -> Self { | 487 | pub fn new(num_binders: usize, value: T) -> Self { |
488 | Self { num_binders, value } | 488 | Self { num_binders, value } |
489 | } | 489 | } |
490 | |||
491 | pub fn as_ref(&self) -> Binders<&T> { | ||
492 | Binders { num_binders: self.num_binders, value: &self.value } | ||
493 | } | ||
494 | |||
495 | pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> { | ||
496 | Binders { num_binders: self.num_binders, value: f(self.value) } | ||
497 | } | ||
498 | |||
499 | pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> { | ||
500 | Some(Binders { num_binders: self.num_binders, value: f(self.value)? }) | ||
501 | } | ||
490 | } | 502 | } |
491 | 503 | ||
492 | impl<T: Clone> Binders<&T> { | 504 | impl<T: Clone> Binders<&T> { |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index b57214296..a6f893037 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -28,11 +28,11 @@ use crate::{ | |||
28 | db::HirDatabase, | 28 | db::HirDatabase, |
29 | primitive::{FloatTy, IntTy}, | 29 | primitive::{FloatTy, IntTy}, |
30 | utils::{ | 30 | utils::{ |
31 | all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, | 31 | all_super_trait_refs, associated_type_by_name_including_super_traits, generics, |
32 | variant_data, | 32 | make_mut_slice, variant_data, |
33 | }, | 33 | }, |
34 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, | 34 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, |
35 | ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, | 35 | ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | #[derive(Debug)] | 38 | #[derive(Debug)] |
@@ -256,7 +256,7 @@ impl Ty { | |||
256 | if remaining_segments.len() == 1 { | 256 | if remaining_segments.len() == 1 { |
257 | // resolve unselected assoc types | 257 | // resolve unselected assoc types |
258 | let segment = remaining_segments.first().unwrap(); | 258 | let segment = remaining_segments.first().unwrap(); |
259 | (Ty::select_associated_type(ctx, ty, res, segment), None) | 259 | (Ty::select_associated_type(ctx, res, segment), None) |
260 | } else if remaining_segments.len() > 1 { | 260 | } else if remaining_segments.len() > 1 { |
261 | // FIXME report error (ambiguous associated type) | 261 | // FIXME report error (ambiguous associated type) |
262 | (Ty::Unknown, None) | 262 | (Ty::Unknown, None) |
@@ -380,21 +380,20 @@ impl Ty { | |||
380 | 380 | ||
381 | fn select_associated_type( | 381 | fn select_associated_type( |
382 | ctx: &TyLoweringContext<'_>, | 382 | ctx: &TyLoweringContext<'_>, |
383 | self_ty: Ty, | ||
384 | res: Option<TypeNs>, | 383 | res: Option<TypeNs>, |
385 | segment: PathSegment<'_>, | 384 | segment: PathSegment<'_>, |
386 | ) -> Ty { | 385 | ) -> Ty { |
387 | let traits_from_env: Vec<_> = match res { | 386 | let traits_from_env: Vec<_> = match res { |
388 | Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { | 387 | Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { |
389 | None => return Ty::Unknown, | 388 | None => return Ty::Unknown, |
390 | Some(trait_ref) => vec![trait_ref.value.trait_], | 389 | Some(trait_ref) => vec![trait_ref.value], |
391 | }, | 390 | }, |
392 | Some(TypeNs::GenericParam(param_id)) => { | 391 | Some(TypeNs::GenericParam(param_id)) => { |
393 | let predicates = ctx.db.generic_predicates_for_param(param_id); | 392 | let predicates = ctx.db.generic_predicates_for_param(param_id); |
394 | let mut traits_: Vec<_> = predicates | 393 | let mut traits_: Vec<_> = predicates |
395 | .iter() | 394 | .iter() |
396 | .filter_map(|pred| match &pred.value { | 395 | .filter_map(|pred| match &pred.value { |
397 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | 396 | GenericPredicate::Implemented(tr) => Some(tr.clone()), |
398 | _ => None, | 397 | _ => None, |
399 | }) | 398 | }) |
400 | .collect(); | 399 | .collect(); |
@@ -404,20 +403,37 @@ impl Ty { | |||
404 | if generics.params.types[param_id.local_id].provenance | 403 | if generics.params.types[param_id.local_id].provenance |
405 | == TypeParamProvenance::TraitSelf | 404 | == TypeParamProvenance::TraitSelf |
406 | { | 405 | { |
407 | traits_.push(trait_id); | 406 | let trait_ref = TraitRef { |
407 | trait_: trait_id, | ||
408 | substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST), | ||
409 | }; | ||
410 | traits_.push(trait_ref); | ||
408 | } | 411 | } |
409 | } | 412 | } |
410 | traits_ | 413 | traits_ |
411 | } | 414 | } |
412 | _ => return Ty::Unknown, | 415 | _ => return Ty::Unknown, |
413 | }; | 416 | }; |
414 | let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db.upcast(), t)); | 417 | let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t)); |
415 | for t in traits { | 418 | for t in traits { |
416 | if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) | 419 | if let Some(associated_ty) = |
420 | ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name) | ||
417 | { | 421 | { |
418 | let substs = | 422 | let substs = match ctx.type_param_mode { |
419 | Substs::build_for_def(ctx.db, t).push(self_ty).fill_with_unknown().build(); | 423 | TypeParamLoweringMode::Placeholder => { |
420 | // FIXME handle type parameters on the segment | 424 | // if we're lowering to placeholders, we have to put |
425 | // them in now | ||
426 | let s = Substs::type_params( | ||
427 | ctx.db, | ||
428 | ctx.resolver | ||
429 | .generic_def() | ||
430 | .expect("there should be generics if there's a generic param"), | ||
431 | ); | ||
432 | t.substs.subst_bound_vars(&s) | ||
433 | } | ||
434 | TypeParamLoweringMode::Variable => t.substs, | ||
435 | }; | ||
436 | // FIXME handle (forbid) type parameters on the segment | ||
421 | return Ty::Projection(ProjectionTy { associated_ty, parameters: substs }); | 437 | return Ty::Projection(ProjectionTy { associated_ty, parameters: substs }); |
422 | } | 438 | } |
423 | } | 439 | } |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 6b5267232..5ddecbdc6 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -622,14 +622,14 @@ fn main() { | |||
622 | fn infer_derive_clone_simple() { | 622 | fn infer_derive_clone_simple() { |
623 | let (db, pos) = TestDB::with_position( | 623 | let (db, pos) = TestDB::with_position( |
624 | r#" | 624 | r#" |
625 | //- /main.rs crate:main deps:std | 625 | //- /main.rs crate:main deps:core |
626 | #[derive(Clone)] | 626 | #[derive(Clone)] |
627 | struct S; | 627 | struct S; |
628 | fn test() { | 628 | fn test() { |
629 | S.clone()<|>; | 629 | S.clone()<|>; |
630 | } | 630 | } |
631 | 631 | ||
632 | //- /lib.rs crate:std | 632 | //- /lib.rs crate:core |
633 | #[prelude_import] | 633 | #[prelude_import] |
634 | use clone::*; | 634 | use clone::*; |
635 | mod clone { | 635 | mod clone { |
@@ -643,10 +643,35 @@ mod clone { | |||
643 | } | 643 | } |
644 | 644 | ||
645 | #[test] | 645 | #[test] |
646 | fn infer_derive_clone_in_core() { | ||
647 | let (db, pos) = TestDB::with_position( | ||
648 | r#" | ||
649 | //- /lib.rs crate:core | ||
650 | #[prelude_import] | ||
651 | use clone::*; | ||
652 | mod clone { | ||
653 | trait Clone { | ||
654 | fn clone(&self) -> Self; | ||
655 | } | ||
656 | } | ||
657 | #[derive(Clone)] | ||
658 | pub struct S; | ||
659 | |||
660 | //- /main.rs crate:main deps:core | ||
661 | use core::S; | ||
662 | fn test() { | ||
663 | S.clone()<|>; | ||
664 | } | ||
665 | "#, | ||
666 | ); | ||
667 | assert_eq!("S", type_at_pos(&db, pos)); | ||
668 | } | ||
669 | |||
670 | #[test] | ||
646 | fn infer_derive_clone_with_params() { | 671 | fn infer_derive_clone_with_params() { |
647 | let (db, pos) = TestDB::with_position( | 672 | let (db, pos) = TestDB::with_position( |
648 | r#" | 673 | r#" |
649 | //- /main.rs crate:main deps:std | 674 | //- /main.rs crate:main deps:core |
650 | #[derive(Clone)] | 675 | #[derive(Clone)] |
651 | struct S; | 676 | struct S; |
652 | #[derive(Clone)] | 677 | #[derive(Clone)] |
@@ -656,7 +681,7 @@ fn test() { | |||
656 | (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; | 681 | (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; |
657 | } | 682 | } |
658 | 683 | ||
659 | //- /lib.rs crate:std | 684 | //- /lib.rs crate:core |
660 | #[prelude_import] | 685 | #[prelude_import] |
661 | use clone::*; | 686 | use clone::*; |
662 | mod clone { | 687 | mod clone { |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index f51cdd496..e555c879a 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -1898,6 +1898,36 @@ fn test() { | |||
1898 | } | 1898 | } |
1899 | 1899 | ||
1900 | #[test] | 1900 | #[test] |
1901 | fn unselected_projection_chalk_fold() { | ||
1902 | let t = type_at( | ||
1903 | r#" | ||
1904 | //- /main.rs | ||
1905 | trait Interner {} | ||
1906 | trait Fold<I: Interner, TI = I> { | ||
1907 | type Result; | ||
1908 | } | ||
1909 | |||
1910 | struct Ty<I: Interner> {} | ||
1911 | impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> { | ||
1912 | type Result = Ty<TI>; | ||
1913 | } | ||
1914 | |||
1915 | fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result | ||
1916 | where | ||
1917 | T: Fold<I, I>, | ||
1918 | { | ||
1919 | loop {} | ||
1920 | } | ||
1921 | |||
1922 | fn foo<I: Interner>(interner: &I, t: Ty<I>) { | ||
1923 | fold(interner, t)<|>; | ||
1924 | } | ||
1925 | "#, | ||
1926 | ); | ||
1927 | assert_eq!(t, "Ty<I>"); | ||
1928 | } | ||
1929 | |||
1930 | #[test] | ||
1901 | fn trait_impl_self_ty() { | 1931 | fn trait_impl_self_ty() { |
1902 | let t = type_at( | 1932 | let t = type_at( |
1903 | r#" | 1933 | r#" |
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 1e5022fa4..f98350bf9 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs | |||
@@ -14,6 +14,8 @@ use hir_def::{ | |||
14 | }; | 14 | }; |
15 | use hir_expand::name::{name, Name}; | 15 | use hir_expand::name::{name, Name}; |
16 | 16 | ||
17 | use crate::{db::HirDatabase, GenericPredicate, TraitRef}; | ||
18 | |||
17 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 19 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
18 | let resolver = trait_.resolver(db); | 20 | let resolver = trait_.resolver(db); |
19 | // returning the iterator directly doesn't easily work because of | 21 | // returning the iterator directly doesn't easily work because of |
@@ -41,6 +43,28 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
41 | .collect() | 43 | .collect() |
42 | } | 44 | } |
43 | 45 | ||
46 | fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> { | ||
47 | // returning the iterator directly doesn't easily work because of | ||
48 | // lifetime problems, but since there usually shouldn't be more than a | ||
49 | // few direct traits this should be fine (we could even use some kind of | ||
50 | // SmallVec if performance is a concern) | ||
51 | let generic_params = db.generic_params(trait_ref.trait_.into()); | ||
52 | let trait_self = match generic_params.find_trait_self_param() { | ||
53 | Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p }, | ||
54 | None => return Vec::new(), | ||
55 | }; | ||
56 | db.generic_predicates_for_param(trait_self) | ||
57 | .iter() | ||
58 | .filter_map(|pred| { | ||
59 | pred.as_ref().filter_map(|pred| match pred { | ||
60 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
61 | _ => None, | ||
62 | }) | ||
63 | }) | ||
64 | .map(|pred| pred.subst(&trait_ref.substs)) | ||
65 | .collect() | ||
66 | } | ||
67 | |||
44 | /// Returns an iterator over the whole super trait hierarchy (including the | 68 | /// Returns an iterator over the whole super trait hierarchy (including the |
45 | /// trait itself). | 69 | /// trait itself). |
46 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 70 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
@@ -62,6 +86,30 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra | |||
62 | result | 86 | result |
63 | } | 87 | } |
64 | 88 | ||
89 | /// Given a trait ref (`Self: Trait`), builds all the implied trait refs for | ||
90 | /// super traits. The original trait ref will be included. So the difference to | ||
91 | /// `all_super_traits` is that we keep track of type parameters; for example if | ||
92 | /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get | ||
93 | /// `Self: OtherTrait<i32>`. | ||
94 | pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> { | ||
95 | // we need to take care a bit here to avoid infinite loops in case of cycles | ||
96 | // (i.e. if we have `trait A: B; trait B: A;`) | ||
97 | let mut result = vec![trait_ref]; | ||
98 | let mut i = 0; | ||
99 | while i < result.len() { | ||
100 | let t = &result[i]; | ||
101 | // yeah this is quadratic, but trait hierarchies should be flat | ||
102 | // enough that this doesn't matter | ||
103 | for tt in direct_super_trait_refs(db, t) { | ||
104 | if !result.iter().any(|tr| tr.trait_ == tt.trait_) { | ||
105 | result.push(tt); | ||
106 | } | ||
107 | } | ||
108 | i += 1; | ||
109 | } | ||
110 | result | ||
111 | } | ||
112 | |||
65 | /// Finds a path from a trait to one of its super traits. Returns an empty | 113 | /// Finds a path from a trait to one of its super traits. Returns an empty |
66 | /// vector if there is no path. | 114 | /// vector if there is no path. |
67 | pub(super) fn find_super_trait_path( | 115 | pub(super) fn find_super_trait_path( |
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 814354ffa..05f825c6f 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -250,6 +250,44 @@ mod tests { | |||
250 | } | 250 | } |
251 | 251 | ||
252 | #[test] | 252 | #[test] |
253 | fn test_union_field_completion() { | ||
254 | assert_debug_snapshot!( | ||
255 | do_ref_completion( | ||
256 | r" | ||
257 | union Un { | ||
258 | field: u8, | ||
259 | other: u16, | ||
260 | } | ||
261 | |||
262 | fn foo(u: Un) { | ||
263 | u.<|> | ||
264 | } | ||
265 | ", | ||
266 | ), | ||
267 | @r###" | ||
268 | [ | ||
269 | CompletionItem { | ||
270 | label: "field", | ||
271 | source_range: 140..140, | ||
272 | delete: 140..140, | ||
273 | insert: "field", | ||
274 | kind: Field, | ||
275 | detail: "u8", | ||
276 | }, | ||
277 | CompletionItem { | ||
278 | label: "other", | ||
279 | source_range: 140..140, | ||
280 | delete: 140..140, | ||
281 | insert: "other", | ||
282 | kind: Field, | ||
283 | detail: "u16", | ||
284 | }, | ||
285 | ] | ||
286 | "### | ||
287 | ); | ||
288 | } | ||
289 | |||
290 | #[test] | ||
253 | fn test_method_completion() { | 291 | fn test_method_completion() { |
254 | assert_debug_snapshot!( | 292 | assert_debug_snapshot!( |
255 | do_ref_completion( | 293 | do_ref_completion( |
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index f559f2b97..a6a5568de 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -53,7 +53,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
53 | // Variants with trivial paths are already added by the existing completion logic, | 53 | // Variants with trivial paths are already added by the existing completion logic, |
54 | // so we should avoid adding these twice | 54 | // so we should avoid adding these twice |
55 | if path.segments.len() > 1 { | 55 | if path.segments.len() > 1 { |
56 | acc.add_enum_variant(ctx, variant, Some(path.to_string())); | 56 | acc.add_qualified_enum_variant(ctx, variant, path); |
57 | } | 57 | } |
58 | } | 58 | } |
59 | } | 59 | } |
@@ -1173,6 +1173,7 @@ mod tests { | |||
1173 | delete: 248..250, | 1173 | delete: 248..250, |
1174 | insert: "Foo::Bar", | 1174 | insert: "Foo::Bar", |
1175 | kind: EnumVariant, | 1175 | kind: EnumVariant, |
1176 | lookup: "Bar", | ||
1176 | detail: "()", | 1177 | detail: "()", |
1177 | }, | 1178 | }, |
1178 | CompletionItem { | 1179 | CompletionItem { |
@@ -1181,6 +1182,7 @@ mod tests { | |||
1181 | delete: 248..250, | 1182 | delete: 248..250, |
1182 | insert: "Foo::Baz", | 1183 | insert: "Foo::Baz", |
1183 | kind: EnumVariant, | 1184 | kind: EnumVariant, |
1185 | lookup: "Baz", | ||
1184 | detail: "()", | 1186 | detail: "()", |
1185 | }, | 1187 | }, |
1186 | CompletionItem { | 1188 | CompletionItem { |
@@ -1189,6 +1191,7 @@ mod tests { | |||
1189 | delete: 248..250, | 1191 | delete: 248..250, |
1190 | insert: "Foo::Quux", | 1192 | insert: "Foo::Quux", |
1191 | kind: EnumVariant, | 1193 | kind: EnumVariant, |
1194 | lookup: "Quux", | ||
1192 | detail: "()", | 1195 | detail: "()", |
1193 | }, | 1196 | }, |
1194 | ] | 1197 | ] |
@@ -1231,6 +1234,7 @@ mod tests { | |||
1231 | delete: 219..221, | 1234 | delete: 219..221, |
1232 | insert: "Foo::Bar", | 1235 | insert: "Foo::Bar", |
1233 | kind: EnumVariant, | 1236 | kind: EnumVariant, |
1237 | lookup: "Bar", | ||
1234 | detail: "()", | 1238 | detail: "()", |
1235 | }, | 1239 | }, |
1236 | CompletionItem { | 1240 | CompletionItem { |
@@ -1239,6 +1243,7 @@ mod tests { | |||
1239 | delete: 219..221, | 1243 | delete: 219..221, |
1240 | insert: "Foo::Baz", | 1244 | insert: "Foo::Baz", |
1241 | kind: EnumVariant, | 1245 | kind: EnumVariant, |
1246 | lookup: "Baz", | ||
1242 | detail: "()", | 1247 | detail: "()", |
1243 | }, | 1248 | }, |
1244 | CompletionItem { | 1249 | CompletionItem { |
@@ -1247,6 +1252,7 @@ mod tests { | |||
1247 | delete: 219..221, | 1252 | delete: 219..221, |
1248 | insert: "Foo::Quux", | 1253 | insert: "Foo::Quux", |
1249 | kind: EnumVariant, | 1254 | kind: EnumVariant, |
1255 | lookup: "Quux", | ||
1250 | detail: "()", | 1256 | detail: "()", |
1251 | }, | 1257 | }, |
1252 | ] | 1258 | ] |
@@ -1285,6 +1291,7 @@ mod tests { | |||
1285 | delete: 185..186, | 1291 | delete: 185..186, |
1286 | insert: "Foo::Bar", | 1292 | insert: "Foo::Bar", |
1287 | kind: EnumVariant, | 1293 | kind: EnumVariant, |
1294 | lookup: "Bar", | ||
1288 | detail: "()", | 1295 | detail: "()", |
1289 | }, | 1296 | }, |
1290 | CompletionItem { | 1297 | CompletionItem { |
@@ -1293,6 +1300,7 @@ mod tests { | |||
1293 | delete: 185..186, | 1300 | delete: 185..186, |
1294 | insert: "Foo::Baz", | 1301 | insert: "Foo::Baz", |
1295 | kind: EnumVariant, | 1302 | kind: EnumVariant, |
1303 | lookup: "Baz", | ||
1296 | detail: "()", | 1304 | detail: "()", |
1297 | }, | 1305 | }, |
1298 | CompletionItem { | 1306 | CompletionItem { |
@@ -1301,6 +1309,7 @@ mod tests { | |||
1301 | delete: 185..186, | 1309 | delete: 185..186, |
1302 | insert: "Foo::Quux", | 1310 | insert: "Foo::Quux", |
1303 | kind: EnumVariant, | 1311 | kind: EnumVariant, |
1312 | lookup: "Quux", | ||
1304 | detail: "()", | 1313 | detail: "()", |
1305 | }, | 1314 | }, |
1306 | CompletionItem { | 1315 | CompletionItem { |
@@ -1353,6 +1362,7 @@ mod tests { | |||
1353 | delete: 98..99, | 1362 | delete: 98..99, |
1354 | insert: "m::E::V", | 1363 | insert: "m::E::V", |
1355 | kind: EnumVariant, | 1364 | kind: EnumVariant, |
1365 | lookup: "V", | ||
1356 | detail: "()", | 1366 | detail: "()", |
1357 | }, | 1367 | }, |
1358 | ] | 1368 | ] |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 77d354376..2edb130cf 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | 2 | ||
3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; | 3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; |
4 | use ra_syntax::ast::NameOwner; | 4 | use ra_syntax::ast::NameOwner; |
5 | use stdx::SepBy; | 5 | use stdx::SepBy; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -246,14 +246,37 @@ impl Completions { | |||
246 | .add_to(self); | 246 | .add_to(self); |
247 | } | 247 | } |
248 | 248 | ||
249 | pub(crate) fn add_qualified_enum_variant( | ||
250 | &mut self, | ||
251 | ctx: &CompletionContext, | ||
252 | variant: hir::EnumVariant, | ||
253 | path: ModPath, | ||
254 | ) { | ||
255 | self.add_enum_variant_impl(ctx, variant, None, Some(path)) | ||
256 | } | ||
257 | |||
249 | pub(crate) fn add_enum_variant( | 258 | pub(crate) fn add_enum_variant( |
250 | &mut self, | 259 | &mut self, |
251 | ctx: &CompletionContext, | 260 | ctx: &CompletionContext, |
252 | variant: hir::EnumVariant, | 261 | variant: hir::EnumVariant, |
253 | local_name: Option<String>, | 262 | local_name: Option<String>, |
254 | ) { | 263 | ) { |
264 | self.add_enum_variant_impl(ctx, variant, local_name, None) | ||
265 | } | ||
266 | |||
267 | fn add_enum_variant_impl( | ||
268 | &mut self, | ||
269 | ctx: &CompletionContext, | ||
270 | variant: hir::EnumVariant, | ||
271 | local_name: Option<String>, | ||
272 | path: Option<ModPath>, | ||
273 | ) { | ||
255 | let is_deprecated = is_deprecated(variant, ctx.db); | 274 | let is_deprecated = is_deprecated(variant, ctx.db); |
256 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string()); | 275 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string()); |
276 | let qualified_name = match &path { | ||
277 | Some(it) => it.to_string(), | ||
278 | None => name.to_string(), | ||
279 | }; | ||
257 | let detail_types = variant | 280 | let detail_types = variant |
258 | .fields(ctx.db) | 281 | .fields(ctx.db) |
259 | .into_iter() | 282 | .into_iter() |
@@ -271,16 +294,23 @@ impl Completions { | |||
271 | .surround_with("{ ", " }") | 294 | .surround_with("{ ", " }") |
272 | .to_string(), | 295 | .to_string(), |
273 | }; | 296 | }; |
274 | let mut res = | 297 | let mut res = CompletionItem::new( |
275 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) | 298 | CompletionKind::Reference, |
276 | .kind(CompletionItemKind::EnumVariant) | 299 | ctx.source_range(), |
277 | .set_documentation(variant.docs(ctx.db)) | 300 | qualified_name.clone(), |
278 | .set_deprecated(is_deprecated) | 301 | ) |
279 | .detail(detail); | 302 | .kind(CompletionItemKind::EnumVariant) |
303 | .set_documentation(variant.docs(ctx.db)) | ||
304 | .set_deprecated(is_deprecated) | ||
305 | .detail(detail); | ||
306 | |||
307 | if path.is_some() { | ||
308 | res = res.lookup_by(name); | ||
309 | } | ||
280 | 310 | ||
281 | if variant_kind == StructKind::Tuple { | 311 | if variant_kind == StructKind::Tuple { |
282 | let params = Params::Anonymous(variant.fields(ctx.db).len()); | 312 | let params = Params::Anonymous(variant.fields(ctx.db).len()); |
283 | res = res.add_call_parens(ctx, name, params) | 313 | res = res.add_call_parens(ctx, qualified_name, params) |
284 | } | 314 | } |
285 | 315 | ||
286 | res.add_to(self); | 316 | res.add_to(self); |
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html index 6ec13bd80..ea026d7a0 100644 --- a/crates/ra_ide/src/snapshots/highlight_injection.html +++ b/crates/ra_ide/src/snapshots/highlight_injection.html | |||
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
20 | .macro { color: #94BFF3; } | 20 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 21 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 22 | .variable { color: #DCDCCC; } |
23 | .format_specifier { color: #CC696B; } | ||
23 | .mutable { text-decoration: underline; } | 24 | .mutable { text-decoration: underline; } |
24 | 25 | ||
25 | .keyword { color: #F0DFAF; font-weight: bold; } | 26 | .keyword { color: #F0DFAF; font-weight: bold; } |
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index 433f2e0c5..de06daf72 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html | |||
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
20 | .macro { color: #94BFF3; } | 20 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 21 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 22 | .variable { color: #DCDCCC; } |
23 | .format_specifier { color: #CC696B; } | ||
23 | .mutable { text-decoration: underline; } | 24 | .mutable { text-decoration: underline; } |
24 | 25 | ||
25 | .keyword { color: #F0DFAF; font-weight: bold; } | 26 | .keyword { color: #F0DFAF; font-weight: bold; } |
@@ -40,43 +41,43 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
40 | <span class="keyword">fn</span> <span class="function declaration">main</span>() { | 41 | <span class="keyword">fn</span> <span class="function declaration">main</span>() { |
41 | <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> | 42 | <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> |
42 | <span class="macro">println!</span>(<span class="string_literal">"Hello"</span>); <span class="comment">// => "Hello"</span> | 43 | <span class="macro">println!</span>(<span class="string_literal">"Hello"</span>); <span class="comment">// => "Hello"</span> |
43 | <span class="macro">println!</span>(<span class="string_literal">"Hello, </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); <span class="comment">// => "Hello, world!"</span> | 44 | <span class="macro">println!</span>(<span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); <span class="comment">// => "Hello, world!"</span> |
44 | <span class="macro">println!</span>(<span class="string_literal">"The number is </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>); <span class="comment">// => "The number is 1"</span> | 45 | <span class="macro">println!</span>(<span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>); <span class="comment">// => "The number is 1"</span> |
45 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">?</span><span class="attribute">}</span><span class="string_literal">"</span>, (<span class="numeric_literal">3</span>, <span class="numeric_literal">4</span>)); <span class="comment">// => "(3, 4)"</span> | 46 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span>, (<span class="numeric_literal">3</span>, <span class="numeric_literal">4</span>)); <span class="comment">// => "(3, 4)"</span> |
46 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">value</span><span class="attribute">}</span><span class="string_literal">"</span>, value=<span class="numeric_literal">4</span>); <span class="comment">// => "4"</span> | 47 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span>, value=<span class="numeric_literal">4</span>); <span class="comment">// => "4"</span> |
47 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// => "1 2"</span> | 48 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// => "1 2"</span> |
48 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">42</span>); <span class="comment">// => "0042" with leading zerosV</span> | 49 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">42</span>); <span class="comment">// => "0042" with leading zerosV</span> |
49 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="numeric_literal">0</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// => "2 1 1 2"</span> | 50 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// => "2 1 1 2"</span> |
50 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">argument</span><span class="attribute">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// => "test"</span> | 51 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// => "test"</span> |
51 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// => "2 1"</span> | 52 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// => "2 1"</span> |
52 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">a</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="variable">c</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="variable">b</span><span class="attribute">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// => "a 3 b"</span> | 53 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// => "a 3 b"</span> |
53 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 54 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
54 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">1</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>); | 55 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>); |
55 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>); | 56 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>); |
56 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="variable">width</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, width = <span class="numeric_literal">5</span>); | 57 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, width = <span class="numeric_literal">5</span>); |
57 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute"><</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 58 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
58 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">-</span><span class="attribute"><</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 59 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
59 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">^</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 60 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
60 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">></span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 61 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
61 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">+</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); | 62 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); |
62 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">#</span><span class="variable">x</span><span class="string_literal">}!"</span>, <span class="numeric_literal">27</span>); | 63 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="string_literal">}!"</span>, <span class="numeric_literal">27</span>); |
63 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); | 64 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); |
64 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>); | 65 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>); |
65 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>); | 66 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>); |
66 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">0</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">:</span><span class="attribute">.</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>); | 67 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>); |
67 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">2</span><span class="attribute">:</span><span class="attribute">.</span><span class="numeric_literal">0</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>); | 68 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>); |
68 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">0</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">2</span><span class="attribute">:</span><span class="attribute">.</span><span class="numeric_literal">1</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); | 69 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); |
69 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); | 70 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); |
70 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">2</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); | 71 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); |
71 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="variable">number</span><span class="attribute">:</span><span class="attribute">.</span><span class="variable">prec</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, prec = <span class="numeric_literal">5</span>, number = <span class="numeric_literal">0.01</span>); | 72 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, prec = <span class="numeric_literal">5</span>, number = <span class="numeric_literal">0.01</span>); |
72 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">, `</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">` has 3 fractional digits"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="numeric_literal">1234.56</span>); | 73 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="numeric_literal">1234.56</span>); |
73 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">, `</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">` has 3 characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>); | 74 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>); |
74 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">, `</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">:</span><span class="attribute">></span><span class="numeric_literal">8</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">` has 3 right-aligned characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>); | 75 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>); |
75 | <span class="macro">println!</span>(<span class="string_literal">"Hello {{}}"</span>); | 76 | <span class="macro">println!</span>(<span class="string_literal">"Hello {{}}"</span>); |
76 | <span class="macro">println!</span>(<span class="string_literal">"{{ Hello"</span>); | 77 | <span class="macro">println!</span>(<span class="string_literal">"{{ Hello"</span>); |
77 | 78 | ||
78 | <span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); | 79 | <span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); |
79 | 80 | ||
80 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">\x41</span><span class="attribute">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>); | 81 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>); |
81 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">ничоси</span><span class="attribute">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>); | 82 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>); |
82 | }</code></pre> \ No newline at end of file | 83 | }</code></pre> \ No newline at end of file |
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index ccb1fc751..4b12fe823 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html | |||
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
20 | .macro { color: #94BFF3; } | 20 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 21 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 22 | .variable { color: #DCDCCC; } |
23 | .format_specifier { color: #CC696B; } | ||
23 | .mutable { text-decoration: underline; } | 24 | .mutable { text-decoration: underline; } |
24 | 25 | ||
25 | .keyword { color: #F0DFAF; font-weight: bold; } | 26 | .keyword { color: #F0DFAF; font-weight: bold; } |
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 3df82c45f..11e1f3e44 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html | |||
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
20 | .macro { color: #94BFF3; } | 20 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 21 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 22 | .variable { color: #DCDCCC; } |
23 | .format_specifier { color: #CC696B; } | ||
23 | .mutable { text-decoration: underline; } | 24 | .mutable { text-decoration: underline; } |
24 | 25 | ||
25 | .keyword { color: #F0DFAF; font-weight: bold; } | 26 | .keyword { color: #F0DFAF; font-weight: bold; } |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index be0f8c827..6658c7bb2 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -290,7 +290,7 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> { | |||
290 | | FormatSpecifier::DollarSign | 290 | | FormatSpecifier::DollarSign |
291 | | FormatSpecifier::Dot | 291 | | FormatSpecifier::Dot |
292 | | FormatSpecifier::Asterisk | 292 | | FormatSpecifier::Asterisk |
293 | | FormatSpecifier::QuestionMark => HighlightTag::Attribute, | 293 | | FormatSpecifier::QuestionMark => HighlightTag::FormatSpecifier, |
294 | FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral, | 294 | FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral, |
295 | FormatSpecifier::Identifier => HighlightTag::Local, | 295 | FormatSpecifier::Identifier => HighlightTag::Local, |
296 | }) | 296 | }) |
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index 010db4017..ff0eeeb52 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs | |||
@@ -79,6 +79,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
79 | .macro { color: #94BFF3; } | 79 | .macro { color: #94BFF3; } |
80 | .module { color: #AFD8AF; } | 80 | .module { color: #AFD8AF; } |
81 | .variable { color: #DCDCCC; } | 81 | .variable { color: #DCDCCC; } |
82 | .format_specifier { color: #CC696B; } | ||
82 | .mutable { text-decoration: underline; } | 83 | .mutable { text-decoration: underline; } |
83 | 84 | ||
84 | .keyword { color: #F0DFAF; font-weight: bold; } | 85 | .keyword { color: #F0DFAF; font-weight: bold; } |
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs index f2c421654..be1a0f12b 100644 --- a/crates/ra_ide/src/syntax_highlighting/tags.rs +++ b/crates/ra_ide/src/syntax_highlighting/tags.rs | |||
@@ -39,6 +39,7 @@ pub enum HighlightTag { | |||
39 | Union, | 39 | Union, |
40 | Local, | 40 | Local, |
41 | UnresolvedReference, | 41 | UnresolvedReference, |
42 | FormatSpecifier, | ||
42 | } | 43 | } |
43 | 44 | ||
44 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 45 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
@@ -81,6 +82,7 @@ impl HighlightTag { | |||
81 | HighlightTag::Union => "union", | 82 | HighlightTag::Union => "union", |
82 | HighlightTag::Local => "variable", | 83 | HighlightTag::Local => "variable", |
83 | HighlightTag::UnresolvedReference => "unresolved_reference", | 84 | HighlightTag::UnresolvedReference => "unresolved_reference", |
85 | HighlightTag::FormatSpecifier => "format_specifier", | ||
84 | } | 86 | } |
85 | } | 87 | } |
86 | } | 88 | } |
diff --git a/crates/ra_prof/src/hprof.rs b/crates/ra_prof/src/hprof.rs index 2b8a90363..a3f5321fb 100644 --- a/crates/ra_prof/src/hprof.rs +++ b/crates/ra_prof/src/hprof.rs | |||
@@ -30,8 +30,9 @@ pub fn init_from(spec: &str) { | |||
30 | pub type Label = &'static str; | 30 | pub type Label = &'static str; |
31 | 31 | ||
32 | /// This function starts a profiling scope in the current execution stack with a given description. | 32 | /// This function starts a profiling scope in the current execution stack with a given description. |
33 | /// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop. | 33 | /// It returns a `Profile` struct that measures elapsed time between this method invocation and `Profile` struct drop. |
34 | /// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output. | 34 | /// It supports nested profiling scopes in case when this function is invoked multiple times at the execution stack. |
35 | /// In this case the profiling information will be nested at the output. | ||
35 | /// Profiling information is being printed in the stderr. | 36 | /// Profiling information is being printed in the stderr. |
36 | /// | 37 | /// |
37 | /// # Example | 38 | /// # Example |
@@ -58,36 +59,35 @@ pub type Label = &'static str; | |||
58 | /// ``` | 59 | /// ``` |
59 | pub fn profile(label: Label) -> Profiler { | 60 | pub fn profile(label: Label) -> Profiler { |
60 | assert!(!label.is_empty()); | 61 | assert!(!label.is_empty()); |
61 | let enabled = PROFILING_ENABLED.load(Ordering::Relaxed) | 62 | |
62 | && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)); | 63 | if PROFILING_ENABLED.load(Ordering::Relaxed) |
63 | let label = if enabled { Some(label) } else { None }; | 64 | && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)) |
64 | Profiler { label, detail: None } | 65 | { |
66 | Profiler(Some(ProfilerImpl { label, detail: None })) | ||
67 | } else { | ||
68 | Profiler(None) | ||
69 | } | ||
65 | } | 70 | } |
66 | 71 | ||
67 | pub struct Profiler { | 72 | pub struct Profiler(Option<ProfilerImpl>); |
68 | label: Option<Label>, | 73 | |
74 | struct ProfilerImpl { | ||
75 | label: Label, | ||
69 | detail: Option<String>, | 76 | detail: Option<String>, |
70 | } | 77 | } |
71 | 78 | ||
72 | impl Profiler { | 79 | impl Profiler { |
73 | pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler { | 80 | pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler { |
74 | if self.label.is_some() { | 81 | if let Some(profiler) = &mut self.0 { |
75 | self.detail = Some(detail()) | 82 | profiler.detail = Some(detail()) |
76 | } | 83 | } |
77 | self | 84 | self |
78 | } | 85 | } |
79 | } | 86 | } |
80 | 87 | ||
81 | impl Drop for Profiler { | 88 | impl Drop for ProfilerImpl { |
82 | fn drop(&mut self) { | 89 | fn drop(&mut self) { |
83 | match self { | 90 | PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take())); |
84 | Profiler { label: Some(label), detail } => { | ||
85 | PROFILE_STACK.with(|stack| { | ||
86 | stack.borrow_mut().pop(label, detail.take()); | ||
87 | }); | ||
88 | } | ||
89 | Profiler { label: None, .. } => (), | ||
90 | } | ||
91 | } | 91 | } |
92 | } | 92 | } |
93 | 93 | ||
@@ -179,21 +179,18 @@ impl ProfileStack { | |||
179 | pub fn pop(&mut self, label: Label, detail: Option<String>) { | 179 | pub fn pop(&mut self, label: Label, detail: Option<String>) { |
180 | let start = self.starts.pop().unwrap(); | 180 | let start = self.starts.pop().unwrap(); |
181 | let duration = start.elapsed(); | 181 | let duration = start.elapsed(); |
182 | let level = self.starts.len(); | ||
183 | self.messages.finish(Message { duration, label, detail }); | 182 | self.messages.finish(Message { duration, label, detail }); |
184 | if level == 0 { | 183 | if self.starts.is_empty() { |
185 | let longer_than = self.filter.longer_than; | 184 | let longer_than = self.filter.longer_than; |
186 | // Convert to millis for comparison to avoid problems with rounding | 185 | // Convert to millis for comparison to avoid problems with rounding |
187 | // (otherwise we could print `0ms` despite user's `>0` filter when | 186 | // (otherwise we could print `0ms` despite user's `>0` filter when |
188 | // `duration` is just a few nanos). | 187 | // `duration` is just a few nanos). |
189 | if duration.as_millis() > longer_than.as_millis() { | 188 | if duration.as_millis() > longer_than.as_millis() { |
190 | let stderr = stderr(); | ||
191 | if let Some(root) = self.messages.root() { | 189 | if let Some(root) = self.messages.root() { |
192 | print(&self.messages, root, 0, longer_than, &mut stderr.lock()); | 190 | print(&self.messages, root, 0, longer_than, &mut stderr().lock()); |
193 | } | 191 | } |
194 | } | 192 | } |
195 | self.messages.clear(); | 193 | self.messages.clear(); |
196 | assert!(self.starts.is_empty()) | ||
197 | } | 194 | } |
198 | } | 195 | } |
199 | } | 196 | } |
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 7fca5661e..a716e525b 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -243,6 +243,21 @@ fn test_comments_preserve_trailing_whitespace() { | |||
243 | } | 243 | } |
244 | 244 | ||
245 | #[test] | 245 | #[test] |
246 | fn test_four_slash_line_comment() { | ||
247 | let file = SourceFile::parse( | ||
248 | r#" | ||
249 | //// too many slashes to be a doc comment | ||
250 | /// doc comment | ||
251 | mod foo {} | ||
252 | "#, | ||
253 | ) | ||
254 | .ok() | ||
255 | .unwrap(); | ||
256 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
257 | assert_eq!("doc comment", module.doc_comment_text().unwrap()); | ||
258 | } | ||
259 | |||
260 | #[test] | ||
246 | fn test_where_predicates() { | 261 | fn test_where_predicates() { |
247 | fn assert_bound(text: &str, bound: Option<TypeBound>) { | 262 | fn assert_bound(text: &str, bound: Option<TypeBound>) { |
248 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); | 263 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index ee0f5cc40..492088353 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -22,8 +22,7 @@ pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { | |||
22 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { | 22 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { |
23 | path_from_text(&format!("{}::{}", qual, segment)) | 23 | path_from_text(&format!("{}::{}", qual, segment)) |
24 | } | 24 | } |
25 | 25 | fn path_from_text(text: &str) -> ast::Path { | |
26 | pub fn path_from_text(text: &str) -> ast::Path { | ||
27 | ast_from_text(text) | 26 | ast_from_text(text) |
28 | } | 27 | } |
29 | 28 | ||
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 3865729b8..74906d8a6 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -13,7 +13,12 @@ impl Comment { | |||
13 | } | 13 | } |
14 | 14 | ||
15 | pub fn prefix(&self) -> &'static str { | 15 | pub fn prefix(&self) -> &'static str { |
16 | prefix_by_kind(self.kind()) | 16 | for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { |
17 | if *k == self.kind() && self.text().starts_with(prefix) { | ||
18 | return prefix; | ||
19 | } | ||
20 | } | ||
21 | unreachable!() | ||
17 | } | 22 | } |
18 | } | 23 | } |
19 | 24 | ||
@@ -48,6 +53,7 @@ pub enum CommentPlacement { | |||
48 | const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { | 53 | const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { |
49 | use {CommentPlacement::*, CommentShape::*}; | 54 | use {CommentPlacement::*, CommentShape::*}; |
50 | &[ | 55 | &[ |
56 | ("////", CommentKind { shape: Line, doc: None }), | ||
51 | ("///", CommentKind { shape: Line, doc: Some(Outer) }), | 57 | ("///", CommentKind { shape: Line, doc: Some(Outer) }), |
52 | ("//!", CommentKind { shape: Line, doc: Some(Inner) }), | 58 | ("//!", CommentKind { shape: Line, doc: Some(Inner) }), |
53 | ("/**", CommentKind { shape: Block, doc: Some(Outer) }), | 59 | ("/**", CommentKind { shape: Block, doc: Some(Outer) }), |
@@ -69,15 +75,6 @@ fn kind_by_prefix(text: &str) -> CommentKind { | |||
69 | panic!("bad comment text: {:?}", text) | 75 | panic!("bad comment text: {:?}", text) |
70 | } | 76 | } |
71 | 77 | ||
72 | fn prefix_by_kind(kind: CommentKind) -> &'static str { | ||
73 | for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { | ||
74 | if *k == kind { | ||
75 | return prefix; | ||
76 | } | ||
77 | } | ||
78 | unreachable!() | ||
79 | } | ||
80 | |||
81 | impl Whitespace { | 78 | impl Whitespace { |
82 | pub fn spans_multiple_lines(&self) -> bool { | 79 | pub fn spans_multiple_lines(&self) -> bool { |
83 | let text = self.text(); | 80 | let text = self.text(); |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index cee0248b6..514d6d1a9 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -20,7 +20,7 @@ globset = "0.4.4" | |||
20 | itertools = "0.9.0" | 20 | itertools = "0.9.0" |
21 | jod-thread = "0.1.0" | 21 | jod-thread = "0.1.0" |
22 | log = "0.4.8" | 22 | log = "0.4.8" |
23 | lsp-types = { version = "0.73.0", features = ["proposed"] } | 23 | lsp-types = { version = "0.74.0", features = ["proposed"] } |
24 | parking_lot = "0.10.0" | 24 | parking_lot = "0.10.0" |
25 | pico-args = "0.3.1" | 25 | pico-args = "0.3.1" |
26 | rand = { version = "0.7.3", features = ["small_rng"] } | 26 | rand = { version = "0.7.3", features = ["small_rng"] } |
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs index b0f911f71..7be5ebcdb 100644 --- a/crates/rust-analyzer/src/conv.rs +++ b/crates/rust-analyzer/src/conv.rs | |||
@@ -25,7 +25,8 @@ use crate::{ | |||
25 | Result, | 25 | Result, |
26 | }; | 26 | }; |
27 | use semantic_tokens::{ | 27 | use semantic_tokens::{ |
28 | ATTRIBUTE, BUILTIN_TYPE, ENUM_MEMBER, LIFETIME, TYPE_ALIAS, UNION, UNRESOLVED_REFERENCE, | 28 | ATTRIBUTE, BUILTIN_TYPE, ENUM_MEMBER, FORMAT_SPECIFIER, LIFETIME, TYPE_ALIAS, UNION, |
29 | UNRESOLVED_REFERENCE, | ||
29 | }; | 30 | }; |
30 | 31 | ||
31 | pub trait Conv { | 32 | pub trait Conv { |
@@ -149,7 +150,7 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem { | |||
149 | detail: self.detail().map(|it| it.to_string()), | 150 | detail: self.detail().map(|it| it.to_string()), |
150 | filter_text: Some(self.lookup().to_string()), | 151 | filter_text: Some(self.lookup().to_string()), |
151 | kind: self.kind().map(|it| it.conv()), | 152 | kind: self.kind().map(|it| it.conv()), |
152 | text_edit: Some(text_edit), | 153 | text_edit: Some(text_edit.into()), |
153 | additional_text_edits: Some(additional_text_edits), | 154 | additional_text_edits: Some(additional_text_edits), |
154 | documentation: self.documentation().map(|it| it.conv()), | 155 | documentation: self.documentation().map(|it| it.conv()), |
155 | deprecated: Some(self.deprecated()), | 156 | deprecated: Some(self.deprecated()), |
@@ -381,6 +382,7 @@ impl Conv for Highlight { | |||
381 | HighlightTag::Attribute => ATTRIBUTE, | 382 | HighlightTag::Attribute => ATTRIBUTE, |
382 | HighlightTag::Keyword => SemanticTokenType::KEYWORD, | 383 | HighlightTag::Keyword => SemanticTokenType::KEYWORD, |
383 | HighlightTag::UnresolvedReference => UNRESOLVED_REFERENCE, | 384 | HighlightTag::UnresolvedReference => UNRESOLVED_REFERENCE, |
385 | HighlightTag::FormatSpecifier => FORMAT_SPECIFIER, | ||
384 | }; | 386 | }; |
385 | 387 | ||
386 | for modifier in self.modifiers.iter() { | 388 | for modifier in self.modifiers.iter() { |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 6caaf5f88..8db2dfa0c 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -326,10 +326,10 @@ pub fn handle_workspace_symbol( | |||
326 | 326 | ||
327 | pub fn handle_goto_definition( | 327 | pub fn handle_goto_definition( |
328 | world: WorldSnapshot, | 328 | world: WorldSnapshot, |
329 | params: req::TextDocumentPositionParams, | 329 | params: req::GotoDefinitionParams, |
330 | ) -> Result<Option<req::GotoDefinitionResponse>> { | 330 | ) -> Result<Option<req::GotoDefinitionResponse>> { |
331 | let _p = profile("handle_goto_definition"); | 331 | let _p = profile("handle_goto_definition"); |
332 | let position = params.try_conv_with(&world)?; | 332 | let position = params.text_document_position_params.try_conv_with(&world)?; |
333 | let nav_info = match world.analysis().goto_definition(position)? { | 333 | let nav_info = match world.analysis().goto_definition(position)? { |
334 | None => return Ok(None), | 334 | None => return Ok(None), |
335 | Some(it) => it, | 335 | Some(it) => it, |
@@ -340,10 +340,10 @@ pub fn handle_goto_definition( | |||
340 | 340 | ||
341 | pub fn handle_goto_implementation( | 341 | pub fn handle_goto_implementation( |
342 | world: WorldSnapshot, | 342 | world: WorldSnapshot, |
343 | params: req::TextDocumentPositionParams, | 343 | params: req::GotoImplementationParams, |
344 | ) -> Result<Option<req::GotoImplementationResponse>> { | 344 | ) -> Result<Option<req::GotoImplementationResponse>> { |
345 | let _p = profile("handle_goto_implementation"); | 345 | let _p = profile("handle_goto_implementation"); |
346 | let position = params.try_conv_with(&world)?; | 346 | let position = params.text_document_position_params.try_conv_with(&world)?; |
347 | let nav_info = match world.analysis().goto_implementation(position)? { | 347 | let nav_info = match world.analysis().goto_implementation(position)? { |
348 | None => return Ok(None), | 348 | None => return Ok(None), |
349 | Some(it) => it, | 349 | Some(it) => it, |
@@ -354,10 +354,10 @@ pub fn handle_goto_implementation( | |||
354 | 354 | ||
355 | pub fn handle_goto_type_definition( | 355 | pub fn handle_goto_type_definition( |
356 | world: WorldSnapshot, | 356 | world: WorldSnapshot, |
357 | params: req::TextDocumentPositionParams, | 357 | params: req::GotoTypeDefinitionParams, |
358 | ) -> Result<Option<req::GotoTypeDefinitionResponse>> { | 358 | ) -> Result<Option<req::GotoTypeDefinitionResponse>> { |
359 | let _p = profile("handle_goto_type_definition"); | 359 | let _p = profile("handle_goto_type_definition"); |
360 | let position = params.try_conv_with(&world)?; | 360 | let position = params.text_document_position_params.try_conv_with(&world)?; |
361 | let nav_info = match world.analysis().goto_type_definition(position)? { | 361 | let nav_info = match world.analysis().goto_type_definition(position)? { |
362 | None => return Ok(None), | 362 | None => return Ok(None), |
363 | Some(it) => it, | 363 | Some(it) => it, |
@@ -487,10 +487,10 @@ pub fn handle_folding_range( | |||
487 | 487 | ||
488 | pub fn handle_signature_help( | 488 | pub fn handle_signature_help( |
489 | world: WorldSnapshot, | 489 | world: WorldSnapshot, |
490 | params: req::TextDocumentPositionParams, | 490 | params: req::SignatureHelpParams, |
491 | ) -> Result<Option<req::SignatureHelp>> { | 491 | ) -> Result<Option<req::SignatureHelp>> { |
492 | let _p = profile("handle_signature_help"); | 492 | let _p = profile("handle_signature_help"); |
493 | let position = params.try_conv_with(&world)?; | 493 | let position = params.text_document_position_params.try_conv_with(&world)?; |
494 | if let Some(call_info) = world.analysis().call_info(position)? { | 494 | if let Some(call_info) = world.analysis().call_info(position)? { |
495 | let concise = !world.config.call_info_full; | 495 | let concise = !world.config.call_info_full; |
496 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); | 496 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); |
@@ -509,12 +509,9 @@ pub fn handle_signature_help( | |||
509 | } | 509 | } |
510 | } | 510 | } |
511 | 511 | ||
512 | pub fn handle_hover( | 512 | pub fn handle_hover(world: WorldSnapshot, params: req::HoverParams) -> Result<Option<Hover>> { |
513 | world: WorldSnapshot, | ||
514 | params: req::TextDocumentPositionParams, | ||
515 | ) -> Result<Option<Hover>> { | ||
516 | let _p = profile("handle_hover"); | 513 | let _p = profile("handle_hover"); |
517 | let position = params.try_conv_with(&world)?; | 514 | let position = params.text_document_position_params.try_conv_with(&world)?; |
518 | let info = match world.analysis().hover(position)? { | 515 | let info = match world.analysis().hover(position)? { |
519 | None => return Ok(None), | 516 | None => return Ok(None), |
520 | Some(info) => info, | 517 | Some(info) => info, |
@@ -878,8 +875,14 @@ pub fn handle_code_lens( | |||
878 | .map(|it| { | 875 | .map(|it| { |
879 | let range = it.node_range.conv_with(&line_index); | 876 | let range = it.node_range.conv_with(&line_index); |
880 | let pos = range.start; | 877 | let pos = range.start; |
881 | let lens_params = | 878 | let lens_params = req::GotoImplementationParams { |
882 | req::TextDocumentPositionParams::new(params.text_document.clone(), pos); | 879 | text_document_position_params: req::TextDocumentPositionParams::new( |
880 | params.text_document.clone(), | ||
881 | pos, | ||
882 | ), | ||
883 | work_done_progress_params: Default::default(), | ||
884 | partial_result_params: Default::default(), | ||
885 | }; | ||
883 | CodeLens { | 886 | CodeLens { |
884 | range, | 887 | range, |
885 | command: None, | 888 | command: None, |
@@ -894,7 +897,7 @@ pub fn handle_code_lens( | |||
894 | #[derive(Debug, Serialize, Deserialize)] | 897 | #[derive(Debug, Serialize, Deserialize)] |
895 | #[serde(rename_all = "camelCase")] | 898 | #[serde(rename_all = "camelCase")] |
896 | enum CodeLensResolveData { | 899 | enum CodeLensResolveData { |
897 | Impls(req::TextDocumentPositionParams), | 900 | Impls(req::GotoImplementationParams), |
898 | } | 901 | } |
899 | 902 | ||
900 | pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { | 903 | pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { |
@@ -927,7 +930,7 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re | |||
927 | title, | 930 | title, |
928 | command: "rust-analyzer.showReferences".into(), | 931 | command: "rust-analyzer.showReferences".into(), |
929 | arguments: Some(vec![ | 932 | arguments: Some(vec![ |
930 | to_value(&lens_params.text_document.uri).unwrap(), | 933 | to_value(&lens_params.text_document_position_params.text_document.uri).unwrap(), |
931 | to_value(code_lens.range.start).unwrap(), | 934 | to_value(code_lens.range.start).unwrap(), |
932 | to_value(locations).unwrap(), | 935 | to_value(locations).unwrap(), |
933 | ]), | 936 | ]), |
@@ -944,16 +947,16 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re | |||
944 | 947 | ||
945 | pub fn handle_document_highlight( | 948 | pub fn handle_document_highlight( |
946 | world: WorldSnapshot, | 949 | world: WorldSnapshot, |
947 | params: req::TextDocumentPositionParams, | 950 | params: req::DocumentHighlightParams, |
948 | ) -> Result<Option<Vec<DocumentHighlight>>> { | 951 | ) -> Result<Option<Vec<DocumentHighlight>>> { |
949 | let _p = profile("handle_document_highlight"); | 952 | let _p = profile("handle_document_highlight"); |
950 | let file_id = params.text_document.try_conv_with(&world)?; | 953 | let file_id = params.text_document_position_params.text_document.try_conv_with(&world)?; |
951 | let line_index = world.analysis().file_line_index(file_id)?; | 954 | let line_index = world.analysis().file_line_index(file_id)?; |
952 | 955 | ||
953 | let refs = match world | 956 | let refs = match world.analysis().find_all_refs( |
954 | .analysis() | 957 | params.text_document_position_params.try_conv_with(&world)?, |
955 | .find_all_refs(params.try_conv_with(&world)?, Some(SearchScope::single_file(file_id)))? | 958 | Some(SearchScope::single_file(file_id)), |
956 | { | 959 | )? { |
957 | None => return Ok(None), | 960 | None => return Ok(None), |
958 | Some(refs) => refs, | 961 | Some(refs) => refs, |
959 | }; | 962 | }; |
diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs index ae3448892..0dae6bad4 100644 --- a/crates/rust-analyzer/src/req.rs +++ b/crates/rust-analyzer/src/req.rs | |||
@@ -8,14 +8,15 @@ pub use lsp_types::{ | |||
8 | notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, | 8 | notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, |
9 | CodeLensParams, CompletionParams, CompletionResponse, ConfigurationItem, ConfigurationParams, | 9 | CodeLensParams, CompletionParams, CompletionResponse, ConfigurationItem, ConfigurationParams, |
10 | DiagnosticTag, DidChangeConfigurationParams, DidChangeWatchedFilesParams, | 10 | DiagnosticTag, DidChangeConfigurationParams, DidChangeWatchedFilesParams, |
11 | DidChangeWatchedFilesRegistrationOptions, DocumentOnTypeFormattingParams, DocumentSymbolParams, | 11 | DidChangeWatchedFilesRegistrationOptions, DocumentHighlightParams, |
12 | DocumentSymbolResponse, FileSystemWatcher, Hover, InitializeResult, MessageType, | 12 | DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, |
13 | PartialResultParams, ProgressParams, ProgressParamsValue, ProgressToken, | 13 | FileSystemWatcher, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverParams, |
14 | PublishDiagnosticsParams, ReferenceParams, Registration, RegistrationParams, SelectionRange, | 14 | InitializeResult, MessageType, PartialResultParams, ProgressParams, ProgressParamsValue, |
15 | SelectionRangeParams, SemanticTokensParams, SemanticTokensRangeParams, | 15 | ProgressToken, PublishDiagnosticsParams, ReferenceParams, Registration, RegistrationParams, |
16 | SelectionRange, SelectionRangeParams, SemanticTokensParams, SemanticTokensRangeParams, | ||
16 | SemanticTokensRangeResult, SemanticTokensResult, ServerCapabilities, ShowMessageParams, | 17 | SemanticTokensRangeResult, SemanticTokensResult, ServerCapabilities, ShowMessageParams, |
17 | SignatureHelp, SymbolKind, TextDocumentEdit, TextDocumentPositionParams, TextEdit, | 18 | SignatureHelp, SignatureHelpParams, SymbolKind, TextDocumentEdit, TextDocumentPositionParams, |
18 | WorkDoneProgressParams, WorkspaceEdit, WorkspaceSymbolParams, | 19 | TextEdit, WorkDoneProgressParams, WorkspaceEdit, WorkspaceSymbolParams, |
19 | }; | 20 | }; |
20 | use std::path::PathBuf; | 21 | use std::path::PathBuf; |
21 | 22 | ||
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 10fe696f6..2dc5cb119 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -4,62 +4,69 @@ use std::ops; | |||
4 | 4 | ||
5 | use lsp_types::{Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens}; | 5 | use lsp_types::{Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens}; |
6 | 6 | ||
7 | pub(crate) const ATTRIBUTE: SemanticTokenType = SemanticTokenType::new("attribute"); | 7 | macro_rules! define_semantic_token_types { |
8 | pub(crate) const BUILTIN_TYPE: SemanticTokenType = SemanticTokenType::new("builtinType"); | 8 | ($(($ident:ident, $string:literal)),*$(,)?) => { |
9 | pub(crate) const ENUM_MEMBER: SemanticTokenType = SemanticTokenType::new("enumMember"); | 9 | $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)* |
10 | pub(crate) const LIFETIME: SemanticTokenType = SemanticTokenType::new("lifetime"); | 10 | |
11 | pub(crate) const TYPE_ALIAS: SemanticTokenType = SemanticTokenType::new("typeAlias"); | 11 | pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[ |
12 | pub(crate) const UNION: SemanticTokenType = SemanticTokenType::new("union"); | 12 | SemanticTokenType::COMMENT, |
13 | pub(crate) const UNRESOLVED_REFERENCE: SemanticTokenType = | 13 | SemanticTokenType::KEYWORD, |
14 | SemanticTokenType::new("unresolvedReference"); | 14 | SemanticTokenType::STRING, |
15 | 15 | SemanticTokenType::NUMBER, | |
16 | pub(crate) const CONSTANT: SemanticTokenModifier = SemanticTokenModifier::new("constant"); | 16 | SemanticTokenType::REGEXP, |
17 | pub(crate) const CONTROL_FLOW: SemanticTokenModifier = SemanticTokenModifier::new("controlFlow"); | 17 | SemanticTokenType::OPERATOR, |
18 | pub(crate) const MUTABLE: SemanticTokenModifier = SemanticTokenModifier::new("mutable"); | 18 | SemanticTokenType::NAMESPACE, |
19 | pub(crate) const UNSAFE: SemanticTokenModifier = SemanticTokenModifier::new("unsafe"); | 19 | SemanticTokenType::TYPE, |
20 | 20 | SemanticTokenType::STRUCT, | |
21 | pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[ | 21 | SemanticTokenType::CLASS, |
22 | SemanticTokenType::COMMENT, | 22 | SemanticTokenType::INTERFACE, |
23 | SemanticTokenType::KEYWORD, | 23 | SemanticTokenType::ENUM, |
24 | SemanticTokenType::STRING, | 24 | SemanticTokenType::TYPE_PARAMETER, |
25 | SemanticTokenType::NUMBER, | 25 | SemanticTokenType::FUNCTION, |
26 | SemanticTokenType::REGEXP, | 26 | SemanticTokenType::MEMBER, |
27 | SemanticTokenType::OPERATOR, | 27 | SemanticTokenType::PROPERTY, |
28 | SemanticTokenType::NAMESPACE, | 28 | SemanticTokenType::MACRO, |
29 | SemanticTokenType::TYPE, | 29 | SemanticTokenType::VARIABLE, |
30 | SemanticTokenType::STRUCT, | 30 | SemanticTokenType::PARAMETER, |
31 | SemanticTokenType::CLASS, | 31 | SemanticTokenType::LABEL, |
32 | SemanticTokenType::INTERFACE, | 32 | $($ident),* |
33 | SemanticTokenType::ENUM, | 33 | ]; |
34 | SemanticTokenType::TYPE_PARAMETER, | 34 | }; |
35 | SemanticTokenType::FUNCTION, | 35 | } |
36 | SemanticTokenType::MEMBER, | 36 | |
37 | SemanticTokenType::PROPERTY, | 37 | define_semantic_token_types![ |
38 | SemanticTokenType::MACRO, | 38 | (ATTRIBUTE, "attribute"), |
39 | SemanticTokenType::VARIABLE, | 39 | (BUILTIN_TYPE, "builtinType"), |
40 | SemanticTokenType::PARAMETER, | 40 | (ENUM_MEMBER, "enumMember"), |
41 | SemanticTokenType::LABEL, | 41 | (LIFETIME, "lifetime"), |
42 | ATTRIBUTE, | 42 | (TYPE_ALIAS, "typeAlias"), |
43 | BUILTIN_TYPE, | 43 | (UNION, "union"), |
44 | ENUM_MEMBER, | 44 | (UNRESOLVED_REFERENCE, "unresolvedReference"), |
45 | LIFETIME, | 45 | (FORMAT_SPECIFIER, "formatSpecifier"), |
46 | TYPE_ALIAS, | ||
47 | UNION, | ||
48 | UNRESOLVED_REFERENCE, | ||
49 | ]; | 46 | ]; |
50 | 47 | ||
51 | pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ | 48 | macro_rules! define_semantic_token_modifiers { |
52 | SemanticTokenModifier::DOCUMENTATION, | 49 | ($(($ident:ident, $string:literal)),*$(,)?) => { |
53 | SemanticTokenModifier::DECLARATION, | 50 | $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)* |
54 | SemanticTokenModifier::DEFINITION, | 51 | |
55 | SemanticTokenModifier::STATIC, | 52 | pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ |
56 | SemanticTokenModifier::ABSTRACT, | 53 | SemanticTokenModifier::DOCUMENTATION, |
57 | SemanticTokenModifier::DEPRECATED, | 54 | SemanticTokenModifier::DECLARATION, |
58 | SemanticTokenModifier::READONLY, | 55 | SemanticTokenModifier::DEFINITION, |
59 | CONSTANT, | 56 | SemanticTokenModifier::STATIC, |
60 | MUTABLE, | 57 | SemanticTokenModifier::ABSTRACT, |
61 | UNSAFE, | 58 | SemanticTokenModifier::DEPRECATED, |
62 | CONTROL_FLOW, | 59 | SemanticTokenModifier::READONLY, |
60 | $($ident),* | ||
61 | ]; | ||
62 | }; | ||
63 | } | ||
64 | |||
65 | define_semantic_token_modifiers![ | ||
66 | (CONSTANT, "constant"), | ||
67 | (CONTROL_FLOW, "controlFlow"), | ||
68 | (MUTABLE, "mutable"), | ||
69 | (UNSAFE, "unsafe"), | ||
63 | ]; | 70 | ]; |
64 | 71 | ||
65 | #[derive(Default)] | 72 | #[derive(Default)] |
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index f6245ddd4..07b8114c6 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -4,8 +4,8 @@ use std::{collections::HashMap, path::PathBuf, time::Instant}; | |||
4 | 4 | ||
5 | use lsp_types::{ | 5 | use lsp_types::{ |
6 | CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions, | 6 | CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions, |
7 | PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams, | 7 | GotoDefinitionParams, HoverParams, PartialResultParams, Position, Range, TextDocumentItem, |
8 | WorkDoneProgressParams, | 8 | TextDocumentPositionParams, WorkDoneProgressParams, |
9 | }; | 9 | }; |
10 | use rust_analyzer::req::{ | 10 | use rust_analyzer::req::{ |
11 | CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument, | 11 | CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument, |
@@ -610,10 +610,14 @@ fn main() { message(); } | |||
610 | }) | 610 | }) |
611 | .server(); | 611 | .server(); |
612 | server.wait_until_workspace_is_loaded(); | 612 | server.wait_until_workspace_is_loaded(); |
613 | let res = server.send_request::<GotoDefinition>(TextDocumentPositionParams::new( | 613 | let res = server.send_request::<GotoDefinition>(GotoDefinitionParams { |
614 | server.doc_id("src/main.rs"), | 614 | text_document_position_params: TextDocumentPositionParams::new( |
615 | Position::new(2, 15), | 615 | server.doc_id("src/main.rs"), |
616 | )); | 616 | Position::new(2, 15), |
617 | ), | ||
618 | work_done_progress_params: Default::default(), | ||
619 | partial_result_params: Default::default(), | ||
620 | }); | ||
617 | assert!(format!("{}", res).contains("hello.rs")); | 621 | assert!(format!("{}", res).contains("hello.rs")); |
618 | } | 622 | } |
619 | 623 | ||
@@ -692,10 +696,13 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
692 | .root("bar") | 696 | .root("bar") |
693 | .server(); | 697 | .server(); |
694 | server.wait_until_workspace_is_loaded(); | 698 | server.wait_until_workspace_is_loaded(); |
695 | let res = server.send_request::<HoverRequest>(TextDocumentPositionParams::new( | 699 | let res = server.send_request::<HoverRequest>(HoverParams { |
696 | server.doc_id("foo/src/main.rs"), | 700 | text_document_position_params: TextDocumentPositionParams::new( |
697 | Position::new(7, 9), | 701 | server.doc_id("foo/src/main.rs"), |
698 | )); | 702 | Position::new(7, 9), |
703 | ), | ||
704 | work_done_progress_params: Default::default(), | ||
705 | }); | ||
699 | 706 | ||
700 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); | 707 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); |
701 | assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#) | 708 | assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#) |
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index 0343b6c81..3a337c574 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md | |||
@@ -56,7 +56,7 @@ In particular, `cargo xtask codegen` generates: | |||
56 | 2. [`ast/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/src/ast/generated.rs) | 56 | 2. [`ast/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/src/ast/generated.rs) |
57 | -- AST data structure. | 57 | -- AST data structure. |
58 | 58 | ||
59 | .3 [`doc_tests/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_assists/src/doc_tests/generated.rs), | 59 | 3. [`doc_tests/generated`](https://github.com/rust-analyzer/rust-analyzer/blob/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_assists/src/doc_tests/generated.rs), |
60 | [`test_data/parser/inline`](https://github.com/rust-analyzer/rust-analyzer/tree/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/test_data/parser/inline) | 60 | [`test_data/parser/inline`](https://github.com/rust-analyzer/rust-analyzer/tree/a0be39296d2925972cacd9fbf8b5fb258fad6947/crates/ra_syntax/test_data/parser/inline) |
61 | -- tests for assists and the parser. | 61 | -- tests for assists and the parser. |
62 | 62 | ||
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc index ce5704836..8b80a7df7 100644 --- a/docs/user/readme.adoc +++ b/docs/user/readme.adoc | |||
@@ -23,7 +23,7 @@ https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/readme.adoc | |||
23 | 23 | ||
24 | == Installation | 24 | == Installation |
25 | 25 | ||
26 | In theory, one should be able to just install the server binary and have it automatically work with any editor. | 26 | In theory, one should be able to just install the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> and have it automatically work with any editor. |
27 | We are not there yet, so some editor specific setup is required. | 27 | We are not there yet, so some editor specific setup is required. |
28 | 28 | ||
29 | Additionally, rust-analyzer needs the sources of the standard library. | 29 | Additionally, rust-analyzer needs the sources of the standard library. |
@@ -108,15 +108,26 @@ Here are some useful self-diagnostic commands: | |||
108 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. | 108 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. |
109 | * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. | 109 | * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. |
110 | 110 | ||
111 | === Language Server Binary | 111 | === rust-analyzer Language Server Binary |
112 | 112 | ||
113 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. | 113 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. |
114 | You can download the pre-built binary from the https://github.com/rust-analyzer/rust-analyzer/releases[releases] page. Typically, you then need to rename the binary for your platform, e.g. `rust-analyzer-mac` if you're on Mac OS, to `rust-analzyer` and make it executable in addition to moving it into a directory in your `$PATH`. | 114 | You can download the pre-built binary from the https://github.com/rust-analyzer/rust-analyzer/releases[releases] page. Typically, you then need to rename the binary for your platform, e.g. `rust-analyzer-mac` if you're on Mac OS, to `rust-analzyer` and make it executable in addition to moving it into a directory in your `$PATH`. |
115 | 115 | ||
116 | On Linux to install the `rust-analyzer` binary into `~/.local/bin`, this commands could be used | ||
117 | |||
118 | [source,bash] | ||
119 | ---- | ||
120 | $ curl -L https://github.com/rust-analyzer/rust-analyzer/releases/latest/download/rust-analyzer-linux -o ~/.local/bin/rust-analyzer | ||
121 | $ chmod +x ~/.local/bin/rust-analyzer | ||
122 | ---- | ||
123 | |||
124 | Ensure `~/.local/bin` is listed in the `$PATH` variable. | ||
125 | |||
116 | Alternatively, you can install it from source using the following command: | 126 | Alternatively, you can install it from source using the following command: |
117 | 127 | ||
118 | [source,bash] | 128 | [source,bash] |
119 | ---- | 129 | ---- |
130 | $ git clone https://github.com/rust-analyzer/rust-analyzer.git && cd rust-analyzer | ||
120 | $ cargo xtask install --server | 131 | $ cargo xtask install --server |
121 | ---- | 132 | ---- |
122 | 133 | ||
@@ -139,15 +150,19 @@ $ yay -S rust-analyzer-bin | |||
139 | 150 | ||
140 | === Emacs | 151 | === Emacs |
141 | 152 | ||
142 | Emacs support is maintained https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[upstream]. | 153 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. |
154 | |||
155 | Emacs support is maintained as part of the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP] package in https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[lsp-rust.el]. | ||
143 | 156 | ||
144 | 1. Install the most recent version of `emacs-lsp` package by following the instructions https://github.com/emacs-lsp/lsp-mode[here]. | 157 | 1. Install the most recent version of `emacs-lsp` package by following the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP instructions]. |
145 | 2. Set `lsp-rust-server` to `'rust-analyzer`. | 158 | 2. Set `lsp-rust-server` to `'rust-analyzer`. |
146 | 3. Run `lsp` in a Rust buffer. | 159 | 3. Run `lsp` in a Rust buffer. |
147 | 4. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys. | 160 | 4. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys. |
148 | 161 | ||
149 | === Vim | 162 | === Vim |
150 | 163 | ||
164 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. | ||
165 | |||
151 | The are several LSP client implementations for vim: | 166 | The are several LSP client implementations for vim: |
152 | 167 | ||
153 | ==== coc-rust-analyzer | 168 | ==== coc-rust-analyzer |
@@ -180,7 +195,7 @@ let g:LanguageClient_serverCommands = { | |||
180 | ==== YouCompleteMe | 195 | ==== YouCompleteMe |
181 | 196 | ||
182 | 1. Install YouCompleteMe by following the instructions | 197 | 1. Install YouCompleteMe by following the instructions |
183 | https://ycm-core.github.io/YouCompleteMe/#rust-semantic-completion[here] | 198 | https://github.com/ycm-core/lsp-examples#rust-rust-analyzer[here] |
184 | 199 | ||
185 | 2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists): | 200 | 2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists): |
186 | + | 201 | + |
@@ -197,6 +212,21 @@ let g:ycm_language_server = | |||
197 | \ ] | 212 | \ ] |
198 | ---- | 213 | ---- |
199 | 214 | ||
215 | ==== ALE | ||
216 | |||
217 | To add the LSP server to https://github.com/dense-analysis/ale[ale]: | ||
218 | |||
219 | [source,vim] | ||
220 | ---- | ||
221 | call ale#linter#Define('rust', { | ||
222 | \ 'name': 'rust-analyzer', | ||
223 | \ 'lsp': 'stdio', | ||
224 | \ 'executable': 'rust-analyzer', | ||
225 | \ 'command': '%e', | ||
226 | \ 'project_root': '.', | ||
227 | \}) | ||
228 | ---- | ||
229 | |||
200 | ==== nvim-lsp | 230 | ==== nvim-lsp |
201 | 231 | ||
202 | NeoVim 0.5 (not yet released) has built-in language server support. | 232 | NeoVim 0.5 (not yet released) has built-in language server support. |
@@ -205,7 +235,7 @@ Once `neovim/nvim-lsp` is installed, use `+lua require'nvim_lsp'.rust_analyzer.s | |||
205 | 235 | ||
206 | === Sublime Text 3 | 236 | === Sublime Text 3 |
207 | 237 | ||
208 | Prerequisites: You have installed the <<language-server-binary,`rust-analyzer` binary>>. | 238 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. |
209 | 239 | ||
210 | You also need the `LSP` package. To install it: | 240 | You also need the `LSP` package. To install it: |
211 | 241 | ||
@@ -218,7 +248,7 @@ Finally, with your Rust project open, in the command palette, run `LSP: Enable L | |||
218 | 248 | ||
219 | If it worked, you should see "rust-analzyer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available. | 249 | If it worked, you should see "rust-analzyer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available. |
220 | 250 | ||
221 | If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<language-server-binary,section on installing the language server binary>>. | 251 | If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary. |
222 | 252 | ||
223 | == Usage | 253 | == Usage |
224 | 254 | ||
diff --git a/editors/code/package.json b/editors/code/package.json index b8aaa07d8..c4dfa7e13 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -27,6 +27,7 @@ | |||
27 | "scripts": { | 27 | "scripts": { |
28 | "vscode:prepublish": "tsc && rollup -c", | 28 | "vscode:prepublish": "tsc && rollup -c", |
29 | "package": "vsce package -o rust-analyzer.vsix", | 29 | "package": "vsce package -o rust-analyzer.vsix", |
30 | "build": "tsc", | ||
30 | "watch": "tsc --watch", | 31 | "watch": "tsc --watch", |
31 | "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src", | 32 | "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src", |
32 | "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src --fix" | 33 | "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src --fix" |
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index a56eeef8d..aef68089e 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -50,21 +50,19 @@ fn dist_server(nightly: bool) -> Result<()> { | |||
50 | if cfg!(target_os = "linux") { | 50 | if cfg!(target_os = "linux") { |
51 | std::env::set_var("CC", "clang"); | 51 | std::env::set_var("CC", "clang"); |
52 | run!( | 52 | run!( |
53 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release | 53 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" |
54 | --target x86_64-unknown-linux-musl | ||
55 | " | ||
56 | // We'd want to add, but that requires setting the right linker somehow | 54 | // We'd want to add, but that requires setting the right linker somehow |
57 | // --features=jemalloc | 55 | // --features=jemalloc |
58 | )?; | 56 | )?; |
59 | if !nightly { | 57 | if !nightly { |
60 | run!("strip ./target/x86_64-unknown-linux-musl/release/rust-analyzer")?; | 58 | run!("strip ./target/release/rust-analyzer")?; |
61 | } | 59 | } |
62 | } else { | 60 | } else { |
63 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; | 61 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; |
64 | } | 62 | } |
65 | 63 | ||
66 | let (src, dst) = if cfg!(target_os = "linux") { | 64 | let (src, dst) = if cfg!(target_os = "linux") { |
67 | ("./target/x86_64-unknown-linux-musl/release/rust-analyzer", "./dist/rust-analyzer-linux") | 65 | ("./target/release/rust-analyzer", "./dist/rust-analyzer-linux") |
68 | } else if cfg!(target_os = "windows") { | 66 | } else if cfg!(target_os = "windows") { |
69 | ("./target/release/rust-analyzer.exe", "./dist/rust-analyzer-windows.exe") | 67 | ("./target/release/rust-analyzer.exe", "./dist/rust-analyzer-windows.exe") |
70 | } else if cfg!(target_os = "macos") { | 68 | } else if cfg!(target_os = "macos") { |