diff options
30 files changed, 692 insertions, 448 deletions
diff --git a/Cargo.lock b/Cargo.lock index 99b7ccf69..f393cbfd7 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -99,12 +99,6 @@ dependencies = [ | |||
99 | ] | 99 | ] |
100 | 100 | ||
101 | [[package]] | 101 | [[package]] |
102 | name = "base64" | ||
103 | version = "0.12.3" | ||
104 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
105 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" | ||
106 | |||
107 | [[package]] | ||
108 | name = "base_db" | 102 | name = "base_db" |
109 | version = "0.0.0" | 103 | version = "0.0.0" |
110 | dependencies = [ | 104 | dependencies = [ |
@@ -381,9 +375,9 @@ dependencies = [ | |||
381 | 375 | ||
382 | [[package]] | 376 | [[package]] |
383 | name = "env_logger" | 377 | name = "env_logger" |
384 | version = "0.8.2" | 378 | version = "0.8.3" |
385 | source = "registry+https://github.com/rust-lang/crates.io-index" | 379 | source = "registry+https://github.com/rust-lang/crates.io-index" |
386 | checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" | 380 | checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" |
387 | dependencies = [ | 381 | dependencies = [ |
388 | "log", | 382 | "log", |
389 | ] | 383 | ] |
@@ -406,7 +400,7 @@ checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" | |||
406 | dependencies = [ | 400 | dependencies = [ |
407 | "cfg-if", | 401 | "cfg-if", |
408 | "libc", | 402 | "libc", |
409 | "redox_syscall 0.2.4", | 403 | "redox_syscall", |
410 | "winapi", | 404 | "winapi", |
411 | ] | 405 | ] |
412 | 406 | ||
@@ -840,11 +834,10 @@ dependencies = [ | |||
840 | 834 | ||
841 | [[package]] | 835 | [[package]] |
842 | name = "lsp-types" | 836 | name = "lsp-types" |
843 | version = "0.86.0" | 837 | version = "0.87.0" |
844 | source = "registry+https://github.com/rust-lang/crates.io-index" | 838 | source = "registry+https://github.com/rust-lang/crates.io-index" |
845 | checksum = "f2a5c40d566f2704dac30859bca152217583fc94fd5b178d8baba915e1abd382" | 839 | checksum = "05ee10a6da8f7ca2eb2881258d23ef3576da85cbd19b314da8e9028eb68eedf0" |
846 | dependencies = [ | 840 | dependencies = [ |
847 | "base64", | ||
848 | "bitflags", | 841 | "bitflags", |
849 | "serde", | 842 | "serde", |
850 | "serde_json", | 843 | "serde_json", |
@@ -1034,14 +1027,14 @@ dependencies = [ | |||
1034 | 1027 | ||
1035 | [[package]] | 1028 | [[package]] |
1036 | name = "parking_lot_core" | 1029 | name = "parking_lot_core" |
1037 | version = "0.8.2" | 1030 | version = "0.8.3" |
1038 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1039 | checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" | 1032 | checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" |
1040 | dependencies = [ | 1033 | dependencies = [ |
1041 | "cfg-if", | 1034 | "cfg-if", |
1042 | "instant", | 1035 | "instant", |
1043 | "libc", | 1036 | "libc", |
1044 | "redox_syscall 0.1.57", | 1037 | "redox_syscall", |
1045 | "smallvec", | 1038 | "smallvec", |
1046 | "winapi", | 1039 | "winapi", |
1047 | ] | 1040 | ] |
@@ -1238,9 +1231,9 @@ dependencies = [ | |||
1238 | 1231 | ||
1239 | [[package]] | 1232 | [[package]] |
1240 | name = "quote" | 1233 | name = "quote" |
1241 | version = "1.0.8" | 1234 | version = "1.0.9" |
1242 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1243 | checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" | 1236 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" |
1244 | dependencies = [ | 1237 | dependencies = [ |
1245 | "proc-macro2", | 1238 | "proc-macro2", |
1246 | ] | 1239 | ] |
@@ -1272,15 +1265,9 @@ dependencies = [ | |||
1272 | 1265 | ||
1273 | [[package]] | 1266 | [[package]] |
1274 | name = "redox_syscall" | 1267 | name = "redox_syscall" |
1275 | version = "0.1.57" | 1268 | version = "0.2.5" |
1276 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1277 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" | ||
1278 | |||
1279 | [[package]] | ||
1280 | name = "redox_syscall" | ||
1281 | version = "0.2.4" | ||
1282 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1283 | checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" | 1270 | checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" |
1284 | dependencies = [ | 1271 | dependencies = [ |
1285 | "bitflags", | 1272 | "bitflags", |
1286 | ] | 1273 | ] |
diff --git a/crates/assists/src/handlers/generate_from_impl_for_enum.rs b/crates/assists/src/handlers/generate_from_impl_for_enum.rs index f6febd3aa..d9388a737 100644 --- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs | |||
@@ -1,15 +1,9 @@ | |||
1 | use ast::GenericParamsOwner; | ||
2 | use ide_db::helpers::FamousDefs; | 1 | use ide_db::helpers::FamousDefs; |
3 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
4 | use itertools::Itertools; | 3 | use syntax::ast::{self, AstNode, NameOwner}; |
5 | use stdx::format_to; | ||
6 | use syntax::{ | ||
7 | ast::{self, AstNode, NameOwner}, | ||
8 | SmolStr, | ||
9 | }; | ||
10 | use test_utils::mark; | 4 | use test_utils::mark; |
11 | 5 | ||
12 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; |
13 | 7 | ||
14 | // Assist: generate_from_impl_for_enum | 8 | // Assist: generate_from_impl_for_enum |
15 | // | 9 | // |
@@ -31,8 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
31 | pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
32 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; | 26 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; |
33 | let variant_name = variant.name()?; | 27 | let variant_name = variant.name()?; |
34 | let enum_name = variant.parent_enum().name()?; | 28 | let enum_ = ast::Adt::Enum(variant.parent_enum()); |
35 | let enum_type_params = variant.parent_enum().generic_param_list(); | ||
36 | let (field_name, field_type) = match variant.kind() { | 29 | let (field_name, field_type) = match variant.kind() { |
37 | ast::StructKind::Tuple(field_list) => { | 30 | ast::StructKind::Tuple(field_list) => { |
38 | if field_list.fields().count() != 1 { | 31 | if field_list.fields().count() != 1 { |
@@ -62,49 +55,27 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext | |||
62 | target, | 55 | target, |
63 | |edit| { | 56 | |edit| { |
64 | let start_offset = variant.parent_enum().syntax().text_range().end(); | 57 | let start_offset = variant.parent_enum().syntax().text_range().end(); |
65 | let mut buf = String::from("\n\nimpl"); | 58 | let from_trait = format!("From<{}>", field_type.syntax()); |
66 | if let Some(type_params) = &enum_type_params { | 59 | let impl_code = if let Some(name) = field_name { |
67 | format_to!(buf, "{}", type_params.syntax()); | 60 | format!( |
68 | } | 61 | r#" fn from({0}: {1}) -> Self {{ |
69 | format_to!(buf, " From<{}> for {}", field_type.syntax(), enum_name); | ||
70 | if let Some(type_params) = enum_type_params { | ||
71 | let lifetime_params = type_params | ||
72 | .lifetime_params() | ||
73 | .filter_map(|it| it.lifetime()) | ||
74 | .map(|it| SmolStr::from(it.text())); | ||
75 | let type_params = type_params | ||
76 | .type_params() | ||
77 | .filter_map(|it| it.name()) | ||
78 | .map(|it| SmolStr::from(it.text())); | ||
79 | |||
80 | let generic_params = lifetime_params.chain(type_params).format(", "); | ||
81 | format_to!(buf, "<{}>", generic_params) | ||
82 | } | ||
83 | if let Some(name) = field_name { | ||
84 | format_to!( | ||
85 | buf, | ||
86 | r#" {{ | ||
87 | fn from({0}: {1}) -> Self {{ | ||
88 | Self::{2} {{ {0} }} | 62 | Self::{2} {{ {0} }} |
89 | }} | 63 | }}"#, |
90 | }}"#, | ||
91 | name.text(), | 64 | name.text(), |
92 | field_type.syntax(), | 65 | field_type.syntax(), |
93 | variant_name, | 66 | variant_name, |
94 | ); | 67 | ) |
95 | } else { | 68 | } else { |
96 | format_to!( | 69 | format!( |
97 | buf, | 70 | r#" fn from(v: {}) -> Self {{ |
98 | r#" {{ | ||
99 | fn from(v: {}) -> Self {{ | ||
100 | Self::{}(v) | 71 | Self::{}(v) |
101 | }} | 72 | }}"#, |
102 | }}"#, | ||
103 | field_type.syntax(), | 73 | field_type.syntax(), |
104 | variant_name, | 74 | variant_name, |
105 | ); | 75 | ) |
106 | } | 76 | }; |
107 | edit.insert(start_offset, buf); | 77 | let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code); |
78 | edit.insert(start_offset, from_impl); | ||
108 | }, | 79 | }, |
109 | ) | 80 | ) |
110 | } | 81 | } |
diff --git a/crates/assists/src/handlers/generate_getter.rs b/crates/assists/src/handlers/generate_getter.rs index fbcf8b069..df7d1bb95 100644 --- a/crates/assists/src/handlers/generate_getter.rs +++ b/crates/assists/src/handlers/generate_getter.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | use stdx::{format_to, to_lower_snake_case}; | 1 | use stdx::{format_to, to_lower_snake_case}; |
2 | use syntax::ast::VisibilityOwner; | 2 | use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; |
3 | use syntax::ast::{self, AstNode, NameOwner}; | ||
4 | 3 | ||
5 | use crate::{ | 4 | use crate::{ |
6 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, | 5 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, |
7 | AssistContext, AssistId, AssistKind, Assists, | 6 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, |
8 | }; | 7 | }; |
9 | 8 | ||
10 | // Assist: generate_getter | 9 | // Assist: generate_getter |
@@ -42,7 +41,8 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
42 | let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; | 41 | let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; |
43 | 42 | ||
44 | let target = field.syntax().text_range(); | 43 | let target = field.syntax().text_range(); |
45 | acc.add( | 44 | acc.add_group( |
45 | &GroupLabel("Generate getter/setter".to_owned()), | ||
46 | AssistId("generate_getter", AssistKind::Generate), | 46 | AssistId("generate_getter", AssistKind::Generate), |
47 | "Generate a getter method", | 47 | "Generate a getter method", |
48 | target, | 48 | target, |
diff --git a/crates/assists/src/handlers/generate_getter_mut.rs b/crates/assists/src/handlers/generate_getter_mut.rs index bf0d99881..821c2eed5 100644 --- a/crates/assists/src/handlers/generate_getter_mut.rs +++ b/crates/assists/src/handlers/generate_getter_mut.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | use stdx::{format_to, to_lower_snake_case}; | 1 | use stdx::{format_to, to_lower_snake_case}; |
2 | use syntax::ast::VisibilityOwner; | 2 | use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; |
3 | use syntax::ast::{self, AstNode, NameOwner}; | ||
4 | 3 | ||
5 | use crate::{ | 4 | use crate::{ |
6 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, | 5 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, |
7 | AssistContext, AssistId, AssistKind, Assists, | 6 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, |
8 | }; | 7 | }; |
9 | 8 | ||
10 | // Assist: generate_getter_mut | 9 | // Assist: generate_getter_mut |
@@ -46,7 +45,8 @@ pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
46 | )?; | 45 | )?; |
47 | 46 | ||
48 | let target = field.syntax().text_range(); | 47 | let target = field.syntax().text_range(); |
49 | acc.add( | 48 | acc.add_group( |
49 | &GroupLabel("Generate getter/setter".to_owned()), | ||
50 | AssistId("generate_getter_mut", AssistKind::Generate), | 50 | AssistId("generate_getter_mut", AssistKind::Generate), |
51 | "Generate a mut getter method", | 51 | "Generate a mut getter method", |
52 | target, | 52 | target, |
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs index 61d1bd25c..16a600e6f 100644 --- a/crates/assists/src/handlers/generate_impl.rs +++ b/crates/assists/src/handlers/generate_impl.rs | |||
@@ -1,11 +1,6 @@ | |||
1 | use itertools::Itertools; | 1 | use syntax::ast::{self, AstNode, NameOwner}; |
2 | use stdx::format_to; | ||
3 | use syntax::{ | ||
4 | ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner}, | ||
5 | SmolStr, | ||
6 | }; | ||
7 | 2 | ||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 3 | use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists}; |
9 | 4 | ||
10 | // Assist: generate_impl | 5 | // Assist: generate_impl |
11 | // | 6 | // |
@@ -36,44 +31,15 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
36 | format!("Generate impl for `{}`", name), | 31 | format!("Generate impl for `{}`", name), |
37 | target, | 32 | target, |
38 | |edit| { | 33 | |edit| { |
39 | let type_params = nominal.generic_param_list(); | ||
40 | let start_offset = nominal.syntax().text_range().end(); | 34 | let start_offset = nominal.syntax().text_range().end(); |
41 | let mut buf = String::new(); | ||
42 | buf.push_str("\n\n"); | ||
43 | nominal | ||
44 | .attrs() | ||
45 | .filter(|attr| { | ||
46 | attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false) | ||
47 | }) | ||
48 | .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str())); | ||
49 | |||
50 | buf.push_str("impl"); | ||
51 | if let Some(type_params) = &type_params { | ||
52 | format_to!(buf, "{}", type_params.syntax()); | ||
53 | } | ||
54 | buf.push_str(" "); | ||
55 | buf.push_str(name.text()); | ||
56 | if let Some(type_params) = type_params { | ||
57 | let lifetime_params = type_params | ||
58 | .lifetime_params() | ||
59 | .filter_map(|it| it.lifetime()) | ||
60 | .map(|it| SmolStr::from(it.text())); | ||
61 | let type_params = type_params | ||
62 | .type_params() | ||
63 | .filter_map(|it| it.name()) | ||
64 | .map(|it| SmolStr::from(it.text())); | ||
65 | |||
66 | let generic_params = lifetime_params.chain(type_params).format(", "); | ||
67 | format_to!(buf, "<{}>", generic_params) | ||
68 | } | ||
69 | match ctx.config.snippet_cap { | 35 | match ctx.config.snippet_cap { |
70 | Some(cap) => { | 36 | Some(cap) => { |
71 | buf.push_str(" {\n $0\n}"); | 37 | let snippet = generate_impl_text(&nominal, " $0"); |
72 | edit.insert_snippet(cap, start_offset, buf); | 38 | edit.insert_snippet(cap, start_offset, snippet); |
73 | } | 39 | } |
74 | None => { | 40 | None => { |
75 | buf.push_str(" {\n}"); | 41 | let snippet = generate_impl_text(&nominal, ""); |
76 | edit.insert(start_offset, buf); | 42 | edit.insert(start_offset, snippet); |
77 | } | 43 | } |
78 | } | 44 | } |
79 | }, | 45 | }, |
@@ -132,6 +98,30 @@ mod tests { | |||
132 | $0 | 98 | $0 |
133 | }"#, | 99 | }"#, |
134 | ); | 100 | ); |
101 | |||
102 | check_assist( | ||
103 | generate_impl, | ||
104 | r#" | ||
105 | struct Defaulted<T = i32> {}$0"#, | ||
106 | r#" | ||
107 | struct Defaulted<T = i32> {} | ||
108 | |||
109 | impl<T> Defaulted<T> { | ||
110 | $0 | ||
111 | }"#, | ||
112 | ); | ||
113 | |||
114 | check_assist( | ||
115 | generate_impl, | ||
116 | r#" | ||
117 | struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {}$0"#, | ||
118 | r#" | ||
119 | struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {} | ||
120 | |||
121 | impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b> Defaulted<'a, 'b, T> { | ||
122 | $0 | ||
123 | }"#, | ||
124 | ); | ||
135 | } | 125 | } |
136 | 126 | ||
137 | #[test] | 127 | #[test] |
diff --git a/crates/assists/src/handlers/generate_setter.rs b/crates/assists/src/handlers/generate_setter.rs index b655f9b9c..288cf745d 100644 --- a/crates/assists/src/handlers/generate_setter.rs +++ b/crates/assists/src/handlers/generate_setter.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | use stdx::{format_to, to_lower_snake_case}; | 1 | use stdx::{format_to, to_lower_snake_case}; |
2 | use syntax::ast::VisibilityOwner; | 2 | use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; |
3 | use syntax::ast::{self, AstNode, NameOwner}; | ||
4 | 3 | ||
5 | use crate::{ | 4 | use crate::{ |
6 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, | 5 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, |
7 | AssistContext, AssistId, AssistKind, Assists, | 6 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, |
8 | }; | 7 | }; |
9 | 8 | ||
10 | // Assist: generate_setter | 9 | // Assist: generate_setter |
@@ -46,7 +45,8 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
46 | )?; | 45 | )?; |
47 | 46 | ||
48 | let target = field.syntax().text_range(); | 47 | let target = field.syntax().text_range(); |
49 | acc.add( | 48 | acc.add_group( |
49 | &GroupLabel("Generate getter/setter".to_owned()), | ||
50 | AssistId("generate_setter", AssistKind::Generate), | 50 | AssistId("generate_setter", AssistKind::Generate), |
51 | "Generate a setter method", | 51 | "Generate a setter method", |
52 | target, | 52 | target, |
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs index 8d28431cf..9b228443f 100644 --- a/crates/assists/src/handlers/inline_local_variable.rs +++ b/crates/assists/src/handlers/inline_local_variable.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use std::collections::HashMap; | ||
2 | |||
3 | use ide_db::{defs::Definition, search::FileReference}; | 1 | use ide_db::{defs::Definition, search::FileReference}; |
2 | use rustc_hash::FxHashMap; | ||
4 | use syntax::{ | 3 | use syntax::{ |
5 | ast::{self, AstNode, AstToken}, | 4 | ast::{self, AstNode, AstToken}, |
6 | TextRange, | 5 | TextRange, |
@@ -111,7 +110,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
111 | .collect::<Result<_, _>>() | 110 | .collect::<Result<_, _>>() |
112 | .map(|b| (file_id, b)) | 111 | .map(|b| (file_id, b)) |
113 | }) | 112 | }) |
114 | .collect::<Result<HashMap<_, Vec<_>>, _>>()?; | 113 | .collect::<Result<FxHashMap<_, Vec<_>>, _>>()?; |
115 | 114 | ||
116 | let init_str = initializer_expr.syntax().text().to_string(); | 115 | let init_str = initializer_expr.syntax().text().to_string(); |
117 | let init_in_paren = format!("({})", &init_str); | 116 | let init_in_paren = format!("({})", &init_str); |
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs index 6aa9d2f2c..c69bc5cac 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -2,8 +2,7 @@ use ide_db::helpers::mod_path_to_ast; | |||
2 | use ide_db::imports_locator; | 2 | use ide_db::imports_locator; |
3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
4 | use syntax::{ | 4 | use syntax::{ |
5 | ast::{self, make, AstNode}, | 5 | ast::{self, make, AstNode, NameOwner}, |
6 | Direction, | ||
7 | SyntaxKind::{IDENT, WHITESPACE}, | 6 | SyntaxKind::{IDENT, WHITESPACE}, |
8 | TextSize, | 7 | TextSize, |
9 | }; | 8 | }; |
@@ -11,7 +10,8 @@ use syntax::{ | |||
11 | use crate::{ | 10 | use crate::{ |
12 | assist_context::{AssistBuilder, AssistContext, Assists}, | 11 | assist_context::{AssistBuilder, AssistContext, Assists}, |
13 | utils::{ | 12 | utils::{ |
14 | add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods, | 13 | add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text, |
14 | render_snippet, Cursor, DefaultMethods, | ||
15 | }, | 15 | }, |
16 | AssistId, AssistKind, | 16 | AssistId, AssistKind, |
17 | }; | 17 | }; |
@@ -57,8 +57,9 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
57 | let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; | 57 | let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; |
58 | let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); | 58 | let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); |
59 | 59 | ||
60 | let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?; | 60 | let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; |
61 | let insert_pos = annotated_name.syntax().parent()?.text_range().end(); | 61 | let annotated_name = adt.name()?; |
62 | let insert_pos = adt.syntax().text_range().end(); | ||
62 | 63 | ||
63 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; | 64 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; |
64 | let current_crate = current_module.krate(); | 65 | let current_crate = current_module.krate(); |
@@ -82,10 +83,10 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
82 | 83 | ||
83 | let mut no_traits_found = true; | 84 | let mut no_traits_found = true; |
84 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { | 85 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { |
85 | add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &annotated_name, insert_pos)?; | 86 | add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?; |
86 | } | 87 | } |
87 | if no_traits_found { | 88 | if no_traits_found { |
88 | add_assist(acc, ctx, &attr, &trait_path, None, &annotated_name, insert_pos)?; | 89 | add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?; |
89 | } | 90 | } |
90 | Some(()) | 91 | Some(()) |
91 | } | 92 | } |
@@ -96,6 +97,7 @@ fn add_assist( | |||
96 | attr: &ast::Attr, | 97 | attr: &ast::Attr, |
97 | trait_path: &ast::Path, | 98 | trait_path: &ast::Path, |
98 | trait_: Option<hir::Trait>, | 99 | trait_: Option<hir::Trait>, |
100 | adt: &ast::Adt, | ||
99 | annotated_name: &ast::Name, | 101 | annotated_name: &ast::Name, |
100 | insert_pos: TextSize, | 102 | insert_pos: TextSize, |
101 | ) -> Option<()> { | 103 | ) -> Option<()> { |
@@ -112,15 +114,15 @@ fn add_assist( | |||
112 | let impl_def_with_items = | 114 | let impl_def_with_items = |
113 | impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); | 115 | impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); |
114 | update_attribute(builder, &input, &trait_name, &attr); | 116 | update_attribute(builder, &input, &trait_name, &attr); |
117 | let trait_path = format!("{}", trait_path); | ||
115 | match (ctx.config.snippet_cap, impl_def_with_items) { | 118 | match (ctx.config.snippet_cap, impl_def_with_items) { |
116 | (None, _) => builder.insert( | 119 | (None, _) => { |
117 | insert_pos, | 120 | builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, "")) |
118 | format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name), | 121 | } |
119 | ), | ||
120 | (Some(cap), None) => builder.insert_snippet( | 122 | (Some(cap), None) => builder.insert_snippet( |
121 | cap, | 123 | cap, |
122 | insert_pos, | 124 | insert_pos, |
123 | format!("\n\nimpl {} for {} {{\n $0\n}}", trait_path, annotated_name), | 125 | generate_trait_impl_text(adt, &trait_path, " $0"), |
124 | ), | 126 | ), |
125 | (Some(cap), Some((impl_def, first_assoc_item))) => { | 127 | (Some(cap), Some((impl_def, first_assoc_item))) => { |
126 | let mut cursor = Cursor::Before(first_assoc_item.syntax()); | 128 | let mut cursor = Cursor::Before(first_assoc_item.syntax()); |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 5dd32aef1..8418e6e12 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::ops; | 3 | use std::ops; |
4 | 4 | ||
5 | use ast::TypeBoundsOwner; | ||
5 | use hir::{Adt, HasSource}; | 6 | use hir::{Adt, HasSource}; |
6 | use ide_db::{helpers::SnippetCap, RootDatabase}; | 7 | use ide_db::{helpers::SnippetCap, RootDatabase}; |
7 | use itertools::Itertools; | 8 | use itertools::Itertools; |
@@ -367,21 +368,56 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti | |||
367 | // Generates the surrounding `impl Type { <code> }` including type and lifetime | 368 | // Generates the surrounding `impl Type { <code> }` including type and lifetime |
368 | // parameters | 369 | // parameters |
369 | pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { | 370 | pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { |
370 | let type_params = adt.generic_param_list(); | 371 | generate_impl_text_inner(adt, None, code) |
372 | } | ||
373 | |||
374 | // Generates the surrounding `impl <trait> for Type { <code> }` including type | ||
375 | // and lifetime parameters | ||
376 | pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String { | ||
377 | generate_impl_text_inner(adt, Some(trait_text), code) | ||
378 | } | ||
379 | |||
380 | fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String { | ||
381 | let generic_params = adt.generic_param_list(); | ||
371 | let mut buf = String::with_capacity(code.len()); | 382 | let mut buf = String::with_capacity(code.len()); |
372 | buf.push_str("\n\nimpl"); | 383 | buf.push_str("\n\n"); |
373 | if let Some(type_params) = &type_params { | 384 | adt.attrs() |
374 | format_to!(buf, "{}", type_params.syntax()); | 385 | .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false)) |
386 | .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str())); | ||
387 | buf.push_str("impl"); | ||
388 | if let Some(generic_params) = &generic_params { | ||
389 | let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax())); | ||
390 | let type_params = generic_params.type_params().map(|type_param| { | ||
391 | let mut buf = String::new(); | ||
392 | if let Some(it) = type_param.name() { | ||
393 | format_to!(buf, "{}", it.syntax()); | ||
394 | } | ||
395 | if let Some(it) = type_param.colon_token() { | ||
396 | format_to!(buf, "{} ", it); | ||
397 | } | ||
398 | if let Some(it) = type_param.type_bound_list() { | ||
399 | format_to!(buf, "{}", it.syntax()); | ||
400 | } | ||
401 | buf | ||
402 | }); | ||
403 | let generics = lifetimes.chain(type_params).format(", "); | ||
404 | format_to!(buf, "<{}>", generics); | ||
375 | } | 405 | } |
376 | buf.push(' '); | 406 | buf.push(' '); |
407 | if let Some(trait_text) = trait_text { | ||
408 | buf.push_str(trait_text); | ||
409 | buf.push_str(" for "); | ||
410 | } | ||
377 | buf.push_str(adt.name().unwrap().text()); | 411 | buf.push_str(adt.name().unwrap().text()); |
378 | if let Some(type_params) = type_params { | 412 | if let Some(generic_params) = generic_params { |
379 | let lifetime_params = type_params | 413 | let lifetime_params = generic_params |
380 | .lifetime_params() | 414 | .lifetime_params() |
381 | .filter_map(|it| it.lifetime()) | 415 | .filter_map(|it| it.lifetime()) |
382 | .map(|it| SmolStr::from(it.text())); | 416 | .map(|it| SmolStr::from(it.text())); |
383 | let type_params = | 417 | let type_params = generic_params |
384 | type_params.type_params().filter_map(|it| it.name()).map(|it| SmolStr::from(it.text())); | 418 | .type_params() |
419 | .filter_map(|it| it.name()) | ||
420 | .map(|it| SmolStr::from(it.text())); | ||
385 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) | 421 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) |
386 | } | 422 | } |
387 | 423 | ||
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 414a60bed..2e8e82b70 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs | |||
@@ -57,19 +57,19 @@ pub(crate) fn annotations( | |||
57 | let action = runnable.action(); | 57 | let action = runnable.action(); |
58 | let range = runnable.nav.full_range; | 58 | let range = runnable.nav.full_range; |
59 | 59 | ||
60 | if action.debugee && config.debug { | 60 | if config.run { |
61 | annotations.push(Annotation { | 61 | annotations.push(Annotation { |
62 | range, | 62 | range, |
63 | 63 | ||
64 | // FIXME: This one allocates without reason if run is enabled, but debug is disabled | 64 | // FIXME: This one allocates without reason if run is enabled, but debug is disabled |
65 | kind: AnnotationKind::Runnable { debug: true, runnable: runnable.clone() }, | 65 | kind: AnnotationKind::Runnable { debug: false, runnable: runnable.clone() }, |
66 | }); | 66 | }); |
67 | } | 67 | } |
68 | 68 | ||
69 | if config.run { | 69 | if action.debugee && config.debug { |
70 | annotations.push(Annotation { | 70 | annotations.push(Annotation { |
71 | range, | 71 | range, |
72 | kind: AnnotationKind::Runnable { debug: false, runnable }, | 72 | kind: AnnotationKind::Runnable { debug: true, runnable }, |
73 | }); | 73 | }); |
74 | } | 74 | } |
75 | } | 75 | } |
@@ -199,7 +199,7 @@ fn main() { | |||
199 | Annotation { | 199 | Annotation { |
200 | range: 50..85, | 200 | range: 50..85, |
201 | kind: Runnable { | 201 | kind: Runnable { |
202 | debug: true, | 202 | debug: false, |
203 | runnable: Runnable { | 203 | runnable: Runnable { |
204 | nav: NavigationTarget { | 204 | nav: NavigationTarget { |
205 | file_id: FileId( | 205 | file_id: FileId( |
@@ -218,7 +218,7 @@ fn main() { | |||
218 | Annotation { | 218 | Annotation { |
219 | range: 50..85, | 219 | range: 50..85, |
220 | kind: Runnable { | 220 | kind: Runnable { |
221 | debug: false, | 221 | debug: true, |
222 | runnable: Runnable { | 222 | runnable: Runnable { |
223 | nav: NavigationTarget { | 223 | nav: NavigationTarget { |
224 | file_id: FileId( | 224 | file_id: FileId( |
@@ -303,7 +303,7 @@ fn main() { | |||
303 | Annotation { | 303 | Annotation { |
304 | range: 14..48, | 304 | range: 14..48, |
305 | kind: Runnable { | 305 | kind: Runnable { |
306 | debug: true, | 306 | debug: false, |
307 | runnable: Runnable { | 307 | runnable: Runnable { |
308 | nav: NavigationTarget { | 308 | nav: NavigationTarget { |
309 | file_id: FileId( | 309 | file_id: FileId( |
@@ -322,7 +322,7 @@ fn main() { | |||
322 | Annotation { | 322 | Annotation { |
323 | range: 14..48, | 323 | range: 14..48, |
324 | kind: Runnable { | 324 | kind: Runnable { |
325 | debug: false, | 325 | debug: true, |
326 | runnable: Runnable { | 326 | runnable: Runnable { |
327 | nav: NavigationTarget { | 327 | nav: NavigationTarget { |
328 | file_id: FileId( | 328 | file_id: FileId( |
@@ -411,7 +411,7 @@ fn main() { | |||
411 | Annotation { | 411 | Annotation { |
412 | range: 66..100, | 412 | range: 66..100, |
413 | kind: Runnable { | 413 | kind: Runnable { |
414 | debug: true, | 414 | debug: false, |
415 | runnable: Runnable { | 415 | runnable: Runnable { |
416 | nav: NavigationTarget { | 416 | nav: NavigationTarget { |
417 | file_id: FileId( | 417 | file_id: FileId( |
@@ -430,7 +430,7 @@ fn main() { | |||
430 | Annotation { | 430 | Annotation { |
431 | range: 66..100, | 431 | range: 66..100, |
432 | kind: Runnable { | 432 | kind: Runnable { |
433 | debug: false, | 433 | debug: true, |
434 | runnable: Runnable { | 434 | runnable: Runnable { |
435 | nav: NavigationTarget { | 435 | nav: NavigationTarget { |
436 | file_id: FileId( | 436 | file_id: FileId( |
@@ -572,7 +572,7 @@ fn main() {} | |||
572 | Annotation { | 572 | Annotation { |
573 | range: 0..12, | 573 | range: 0..12, |
574 | kind: Runnable { | 574 | kind: Runnable { |
575 | debug: true, | 575 | debug: false, |
576 | runnable: Runnable { | 576 | runnable: Runnable { |
577 | nav: NavigationTarget { | 577 | nav: NavigationTarget { |
578 | file_id: FileId( | 578 | file_id: FileId( |
@@ -591,7 +591,7 @@ fn main() {} | |||
591 | Annotation { | 591 | Annotation { |
592 | range: 0..12, | 592 | range: 0..12, |
593 | kind: Runnable { | 593 | kind: Runnable { |
594 | debug: false, | 594 | debug: true, |
595 | runnable: Runnable { | 595 | runnable: Runnable { |
596 | nav: NavigationTarget { | 596 | nav: NavigationTarget { |
597 | file_id: FileId( | 597 | file_id: FileId( |
@@ -645,7 +645,7 @@ fn main() { | |||
645 | Annotation { | 645 | Annotation { |
646 | range: 58..95, | 646 | range: 58..95, |
647 | kind: Runnable { | 647 | kind: Runnable { |
648 | debug: true, | 648 | debug: false, |
649 | runnable: Runnable { | 649 | runnable: Runnable { |
650 | nav: NavigationTarget { | 650 | nav: NavigationTarget { |
651 | file_id: FileId( | 651 | file_id: FileId( |
@@ -664,7 +664,7 @@ fn main() { | |||
664 | Annotation { | 664 | Annotation { |
665 | range: 58..95, | 665 | range: 58..95, |
666 | kind: Runnable { | 666 | kind: Runnable { |
667 | debug: false, | 667 | debug: true, |
668 | runnable: Runnable { | 668 | runnable: Runnable { |
669 | nav: NavigationTarget { | 669 | nav: NavigationTarget { |
670 | file_id: FileId( | 670 | file_id: FileId( |
@@ -787,7 +787,7 @@ mod tests { | |||
787 | Annotation { | 787 | Annotation { |
788 | range: 0..12, | 788 | range: 0..12, |
789 | kind: Runnable { | 789 | kind: Runnable { |
790 | debug: true, | 790 | debug: false, |
791 | runnable: Runnable { | 791 | runnable: Runnable { |
792 | nav: NavigationTarget { | 792 | nav: NavigationTarget { |
793 | file_id: FileId( | 793 | file_id: FileId( |
@@ -806,7 +806,7 @@ mod tests { | |||
806 | Annotation { | 806 | Annotation { |
807 | range: 0..12, | 807 | range: 0..12, |
808 | kind: Runnable { | 808 | kind: Runnable { |
809 | debug: false, | 809 | debug: true, |
810 | runnable: Runnable { | 810 | runnable: Runnable { |
811 | nav: NavigationTarget { | 811 | nav: NavigationTarget { |
812 | file_id: FileId( | 812 | file_id: FileId( |
@@ -825,7 +825,7 @@ mod tests { | |||
825 | Annotation { | 825 | Annotation { |
826 | range: 14..64, | 826 | range: 14..64, |
827 | kind: Runnable { | 827 | kind: Runnable { |
828 | debug: true, | 828 | debug: false, |
829 | runnable: Runnable { | 829 | runnable: Runnable { |
830 | nav: NavigationTarget { | 830 | nav: NavigationTarget { |
831 | file_id: FileId( | 831 | file_id: FileId( |
@@ -846,7 +846,7 @@ mod tests { | |||
846 | Annotation { | 846 | Annotation { |
847 | range: 14..64, | 847 | range: 14..64, |
848 | kind: Runnable { | 848 | kind: Runnable { |
849 | debug: false, | 849 | debug: true, |
850 | runnable: Runnable { | 850 | runnable: Runnable { |
851 | nav: NavigationTarget { | 851 | nav: NavigationTarget { |
852 | file_id: FileId( | 852 | file_id: FileId( |
@@ -867,7 +867,7 @@ mod tests { | |||
867 | Annotation { | 867 | Annotation { |
868 | range: 30..62, | 868 | range: 30..62, |
869 | kind: Runnable { | 869 | kind: Runnable { |
870 | debug: true, | 870 | debug: false, |
871 | runnable: Runnable { | 871 | runnable: Runnable { |
872 | nav: NavigationTarget { | 872 | nav: NavigationTarget { |
873 | file_id: FileId( | 873 | file_id: FileId( |
@@ -893,7 +893,7 @@ mod tests { | |||
893 | Annotation { | 893 | Annotation { |
894 | range: 30..62, | 894 | range: 30..62, |
895 | kind: Runnable { | 895 | kind: Runnable { |
896 | debug: false, | 896 | debug: true, |
897 | runnable: Runnable { | 897 | runnable: Runnable { |
898 | nav: NavigationTarget { | 898 | nav: NavigationTarget { |
899 | file_id: FileId( | 899 | file_id: FileId( |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index c7cefb3b6..a83b82f1b 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | pub(crate) mod rename; | 12 | pub(crate) mod rename; |
13 | 13 | ||
14 | use hir::Semantics; | 14 | use hir::{PathResolution, Semantics}; |
15 | use ide_db::{ | 15 | use ide_db::{ |
16 | base_db::FileId, | 16 | base_db::FileId, |
17 | defs::{Definition, NameClass, NameRefClass}, | 17 | defs::{Definition, NameClass, NameRefClass}, |
@@ -22,7 +22,7 @@ use rustc_hash::FxHashMap; | |||
22 | use syntax::{ | 22 | use syntax::{ |
23 | algo::find_node_at_offset, | 23 | algo::find_node_at_offset, |
24 | ast::{self, NameOwner}, | 24 | ast::{self, NameOwner}, |
25 | AstNode, SyntaxNode, TextRange, TokenAtOffset, T, | 25 | match_ast, AstNode, SyntaxNode, TextRange, T, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | use crate::{display::TryToNav, FilePosition, NavigationTarget}; | 28 | use crate::{display::TryToNav, FilePosition, NavigationTarget}; |
@@ -47,29 +47,40 @@ pub(crate) fn find_all_refs( | |||
47 | let _p = profile::span("find_all_refs"); | 47 | let _p = profile::span("find_all_refs"); |
48 | let syntax = sema.parse(position.file_id).syntax().clone(); | 48 | let syntax = sema.parse(position.file_id).syntax().clone(); |
49 | 49 | ||
50 | let (opt_name, ctor_filter): (_, Option<fn(&_) -> bool>) = if let Some(name) = | 50 | let (def, is_literal_search) = |
51 | get_struct_def_name_for_struct_literal_search(&sema, &syntax, position) | 51 | if let Some(name) = get_name_of_item_declaration(&syntax, position) { |
52 | { | 52 | (NameClass::classify(sema, &name)?.referenced_or_defined(sema.db), true) |
53 | ( | 53 | } else { |
54 | Some(name), | 54 | (find_def(&sema, &syntax, position)?, false) |
55 | Some(|name_ref| is_record_lit_name_ref(name_ref) || is_call_expr_name_ref(name_ref)), | 55 | }; |
56 | ) | ||
57 | } else if let Some(name) = get_enum_def_name_for_struct_literal_search(&sema, &syntax, position) | ||
58 | { | ||
59 | (Some(name), Some(is_enum_lit_name_ref)) | ||
60 | } else { | ||
61 | (sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset), None) | ||
62 | }; | ||
63 | |||
64 | let def = find_def(&sema, &syntax, position, opt_name)?; | ||
65 | 56 | ||
66 | let mut usages = def.usages(sema).set_scope(search_scope).all(); | 57 | let mut usages = def.usages(sema).set_scope(search_scope).all(); |
67 | if let Some(ctor_filter) = ctor_filter { | 58 | if is_literal_search { |
68 | // filter for constructor-literals | 59 | // filter for constructor-literals |
69 | usages.references.values_mut().for_each(|it| { | 60 | let refs = usages.references.values_mut(); |
70 | it.retain(|reference| reference.name.as_name_ref().map_or(false, ctor_filter)); | 61 | match def { |
71 | }); | 62 | Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(enum_))) => { |
72 | usages.references.retain(|_, it| !it.is_empty()); | 63 | refs.for_each(|it| { |
64 | it.retain(|reference| { | ||
65 | reference | ||
66 | .name | ||
67 | .as_name_ref() | ||
68 | .map_or(false, |name_ref| is_enum_lit_name_ref(sema, enum_, name_ref)) | ||
69 | }) | ||
70 | }); | ||
71 | usages.references.retain(|_, it| !it.is_empty()); | ||
72 | } | ||
73 | Definition::ModuleDef(hir::ModuleDef::Adt(_)) | ||
74 | | Definition::ModuleDef(hir::ModuleDef::Variant(_)) => { | ||
75 | refs.for_each(|it| { | ||
76 | it.retain(|reference| { | ||
77 | reference.name.as_name_ref().map_or(false, is_lit_name_ref) | ||
78 | }) | ||
79 | }); | ||
80 | usages.references.retain(|_, it| !it.is_empty()); | ||
81 | } | ||
82 | _ => {} | ||
83 | } | ||
73 | } | 84 | } |
74 | let nav = def.try_to_nav(sema.db)?; | 85 | let nav = def.try_to_nav(sema.db)?; |
75 | let decl_range = nav.focus_or_full_range(); | 86 | let decl_range = nav.focus_or_full_range(); |
@@ -89,9 +100,9 @@ fn find_def( | |||
89 | sema: &Semantics<RootDatabase>, | 100 | sema: &Semantics<RootDatabase>, |
90 | syntax: &SyntaxNode, | 101 | syntax: &SyntaxNode, |
91 | position: FilePosition, | 102 | position: FilePosition, |
92 | opt_name: Option<ast::Name>, | ||
93 | ) -> Option<Definition> { | 103 | ) -> Option<Definition> { |
94 | if let Some(name) = opt_name { | 104 | if let Some(name) = sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset) |
105 | { | ||
95 | let class = NameClass::classify(sema, &name)?; | 106 | let class = NameClass::classify(sema, &name)?; |
96 | Some(class.referenced_or_defined(sema.db)) | 107 | Some(class.referenced_or_defined(sema.db)) |
97 | } else if let Some(lifetime) = | 108 | } else if let Some(lifetime) = |
@@ -134,95 +145,85 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio | |||
134 | None | 145 | None |
135 | } | 146 | } |
136 | 147 | ||
137 | fn get_struct_def_name_for_struct_literal_search( | 148 | fn get_name_of_item_declaration(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> { |
138 | sema: &Semantics<RootDatabase>, | 149 | let token = syntax.token_at_offset(position.offset).right_biased()?; |
139 | syntax: &SyntaxNode, | 150 | let kind = token.kind(); |
140 | position: FilePosition, | 151 | if kind == T![;] { |
141 | ) -> Option<ast::Name> { | 152 | ast::Struct::cast(token.parent()) |
142 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { | 153 | .filter(|struct_| struct_.field_list().is_none()) |
143 | if right.kind() != T!['{'] && right.kind() != T!['('] { | 154 | .and_then(|struct_| struct_.name()) |
144 | return None; | 155 | } else if kind == T!['{'] { |
145 | } | 156 | match_ast! { |
146 | if let Some(name) = | 157 | match (token.parent()) { |
147 | sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start()) | 158 | ast::RecordFieldList(rfl) => match_ast! { |
148 | { | 159 | match (rfl.syntax().parent()?) { |
149 | return name.syntax().ancestors().find_map(ast::Struct::cast).and_then(|l| l.name()); | 160 | ast::Variant(it) => it.name(), |
161 | ast::Struct(it) => it.name(), | ||
162 | ast::Union(it) => it.name(), | ||
163 | _ => None, | ||
164 | } | ||
165 | }, | ||
166 | ast::VariantList(vl) => ast::Enum::cast(vl.syntax().parent()?)?.name(), | ||
167 | _ => None, | ||
168 | } | ||
150 | } | 169 | } |
151 | if sema | 170 | } else if kind == T!['('] { |
152 | .find_node_at_offset_with_descend::<ast::GenericParamList>( | 171 | let tfl = ast::TupleFieldList::cast(token.parent())?; |
153 | &syntax, | 172 | match_ast! { |
154 | left.text_range().start(), | 173 | match (tfl.syntax().parent()?) { |
155 | ) | 174 | ast::Variant(it) => it.name(), |
156 | .is_some() | 175 | ast::Struct(it) => it.name(), |
157 | { | 176 | _ => None, |
158 | return left.ancestors().find_map(ast::Struct::cast).and_then(|l| l.name()); | 177 | } |
159 | } | 178 | } |
179 | } else { | ||
180 | None | ||
160 | } | 181 | } |
161 | None | ||
162 | } | 182 | } |
163 | 183 | ||
164 | fn get_enum_def_name_for_struct_literal_search( | 184 | fn is_enum_lit_name_ref( |
165 | sema: &Semantics<RootDatabase>, | 185 | sema: &Semantics<RootDatabase>, |
166 | syntax: &SyntaxNode, | 186 | enum_: hir::Enum, |
167 | position: FilePosition, | 187 | name_ref: &ast::NameRef, |
168 | ) -> Option<ast::Name> { | 188 | ) -> bool { |
169 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { | 189 | let path_is_variant_of_enum = |path: ast::Path| { |
170 | if right.kind() != T!['{'] && right.kind() != T!['('] { | 190 | matches!( |
171 | return None; | 191 | sema.resolve_path(&path), |
172 | } | 192 | Some(PathResolution::Def(hir::ModuleDef::Variant(variant))) |
173 | if let Some(name) = | 193 | if variant.parent_enum(sema.db) == enum_ |
174 | sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start()) | 194 | ) |
175 | { | 195 | }; |
176 | return name.syntax().ancestors().find_map(ast::Enum::cast).and_then(|l| l.name()); | ||
177 | } | ||
178 | if sema | ||
179 | .find_node_at_offset_with_descend::<ast::GenericParamList>( | ||
180 | &syntax, | ||
181 | left.text_range().start(), | ||
182 | ) | ||
183 | .is_some() | ||
184 | { | ||
185 | return left.ancestors().find_map(ast::Enum::cast).and_then(|l| l.name()); | ||
186 | } | ||
187 | } | ||
188 | None | ||
189 | } | ||
190 | |||
191 | fn is_call_expr_name_ref(name_ref: &ast::NameRef) -> bool { | ||
192 | name_ref | 196 | name_ref |
193 | .syntax() | 197 | .syntax() |
194 | .ancestors() | 198 | .ancestors() |
195 | .find_map(ast::CallExpr::cast) | 199 | .find_map(|ancestor| { |
196 | .and_then(|c| match c.expr()? { | 200 | match_ast! { |
197 | ast::Expr::PathExpr(p) => { | 201 | match ancestor { |
198 | Some(p.path()?.segment()?.name_ref().as_ref() == Some(name_ref)) | 202 | ast::PathExpr(path_expr) => path_expr.path().map(path_is_variant_of_enum), |
203 | ast::RecordExpr(record_expr) => record_expr.path().map(path_is_variant_of_enum), | ||
204 | _ => None, | ||
205 | } | ||
199 | } | 206 | } |
200 | _ => None, | ||
201 | }) | 207 | }) |
202 | .unwrap_or(false) | 208 | .unwrap_or(false) |
203 | } | 209 | } |
204 | 210 | ||
205 | fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool { | 211 | fn path_ends_with(path: Option<ast::Path>, name_ref: &ast::NameRef) -> bool { |
206 | name_ref | 212 | path.and_then(|path| path.segment()) |
207 | .syntax() | 213 | .and_then(|segment| segment.name_ref()) |
208 | .ancestors() | 214 | .map_or(false, |segment| segment == *name_ref) |
209 | .find_map(ast::RecordExpr::cast) | ||
210 | .and_then(|l| l.path()) | ||
211 | .and_then(|p| p.segment()) | ||
212 | .map(|p| p.name_ref().as_ref() == Some(name_ref)) | ||
213 | .unwrap_or(false) | ||
214 | } | 215 | } |
215 | 216 | ||
216 | fn is_enum_lit_name_ref(name_ref: &ast::NameRef) -> bool { | 217 | fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool { |
217 | name_ref | 218 | name_ref.syntax().ancestors().find_map(|ancestor| { |
218 | .syntax() | 219 | match_ast! { |
219 | .ancestors() | 220 | match ancestor { |
220 | .find_map(ast::PathExpr::cast) | 221 | ast::PathExpr(path_expr) => Some(path_ends_with(path_expr.path(), name_ref)), |
221 | .and_then(|p| p.path()) | 222 | ast::RecordExpr(record_expr) => Some(path_ends_with(record_expr.path(), name_ref)), |
222 | .and_then(|p| p.qualifier()) | 223 | _ => None, |
223 | .and_then(|p| p.segment()) | 224 | } |
224 | .map(|p| p.name_ref().as_ref() == Some(name_ref)) | 225 | } |
225 | .unwrap_or(false) | 226 | }).unwrap_or(false) |
226 | } | 227 | } |
227 | 228 | ||
228 | #[cfg(test)] | 229 | #[cfg(test)] |
@@ -313,22 +314,91 @@ fn main() { | |||
313 | } | 314 | } |
314 | 315 | ||
315 | #[test] | 316 | #[test] |
317 | fn test_struct_literal_for_union() { | ||
318 | check( | ||
319 | r#" | ||
320 | union Foo $0{ | ||
321 | x: u32 | ||
322 | } | ||
323 | |||
324 | fn main() { | ||
325 | let f: Foo; | ||
326 | f = Foo { x: 1 }; | ||
327 | } | ||
328 | "#, | ||
329 | expect![[r#" | ||
330 | Foo Union FileId(0) 0..24 6..9 | ||
331 | |||
332 | FileId(0) 62..65 | ||
333 | "#]], | ||
334 | ); | ||
335 | } | ||
336 | |||
337 | #[test] | ||
316 | fn test_enum_after_space() { | 338 | fn test_enum_after_space() { |
317 | check( | 339 | check( |
318 | r#" | 340 | r#" |
319 | enum Foo $0{ | 341 | enum Foo $0{ |
320 | A, | 342 | A, |
321 | B, | 343 | B(), |
344 | C{}, | ||
322 | } | 345 | } |
323 | fn main() { | 346 | fn main() { |
324 | let f: Foo; | 347 | let f: Foo; |
325 | f = Foo::A; | 348 | f = Foo::A; |
349 | f = Foo::B(); | ||
350 | f = Foo::C{}; | ||
326 | } | 351 | } |
327 | "#, | 352 | "#, |
328 | expect![[r#" | 353 | expect![[r#" |
329 | Foo Enum FileId(0) 0..26 5..8 | 354 | Foo Enum FileId(0) 0..37 5..8 |
330 | 355 | ||
331 | FileId(0) 63..66 | 356 | FileId(0) 74..77 |
357 | FileId(0) 90..93 | ||
358 | FileId(0) 108..111 | ||
359 | "#]], | ||
360 | ); | ||
361 | } | ||
362 | |||
363 | #[test] | ||
364 | fn test_variant_record_after_space() { | ||
365 | check( | ||
366 | r#" | ||
367 | enum Foo { | ||
368 | A $0{ n: i32 }, | ||
369 | B, | ||
370 | } | ||
371 | fn main() { | ||
372 | let f: Foo; | ||
373 | f = Foo::B; | ||
374 | f = Foo::A { n: 92 }; | ||
375 | } | ||
376 | "#, | ||
377 | expect![[r#" | ||
378 | A Variant FileId(0) 15..27 15..16 | ||
379 | |||
380 | FileId(0) 95..96 | ||
381 | "#]], | ||
382 | ); | ||
383 | } | ||
384 | #[test] | ||
385 | fn test_variant_tuple_before_paren() { | ||
386 | check( | ||
387 | r#" | ||
388 | enum Foo { | ||
389 | A$0(i32), | ||
390 | B, | ||
391 | } | ||
392 | fn main() { | ||
393 | let f: Foo; | ||
394 | f = Foo::B; | ||
395 | f = Foo::A(92); | ||
396 | } | ||
397 | "#, | ||
398 | expect![[r#" | ||
399 | A Variant FileId(0) 15..21 15..16 | ||
400 | |||
401 | FileId(0) 89..90 | ||
332 | "#]], | 402 | "#]], |
333 | ); | 403 | ); |
334 | } | 404 | } |
@@ -1127,4 +1197,39 @@ impl Foo { | |||
1127 | "#]], | 1197 | "#]], |
1128 | ); | 1198 | ); |
1129 | } | 1199 | } |
1200 | |||
1201 | #[test] | ||
1202 | fn test_attr_differs_from_fn_with_same_name() { | ||
1203 | check( | ||
1204 | r#" | ||
1205 | #[test] | ||
1206 | fn test$0() { | ||
1207 | test(); | ||
1208 | } | ||
1209 | "#, | ||
1210 | expect![[r#" | ||
1211 | test Function FileId(0) 0..33 11..15 | ||
1212 | |||
1213 | FileId(0) 24..28 | ||
1214 | "#]], | ||
1215 | ); | ||
1216 | } | ||
1217 | |||
1218 | #[test] | ||
1219 | fn test_attr_matches_proc_macro_fn() { | ||
1220 | check( | ||
1221 | r#" | ||
1222 | #[proc_macro_attribute] | ||
1223 | fn my_proc_macro() {} | ||
1224 | |||
1225 | #[my_proc_macro$0] | ||
1226 | fn test() {} | ||
1227 | "#, | ||
1228 | expect![[r#" | ||
1229 | my_proc_macro Function FileId(0) 0..45 27..40 | ||
1230 | |||
1231 | FileId(0) 49..62 | ||
1232 | "#]], | ||
1233 | ); | ||
1234 | } | ||
1130 | } | 1235 | } |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index b04214291..08f16b54d 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -75,8 +75,7 @@ pub(crate) fn rename_with_semantics( | |||
75 | let source_file = sema.parse(position.file_id); | 75 | let source_file = sema.parse(position.file_id); |
76 | let syntax = source_file.syntax(); | 76 | let syntax = source_file.syntax(); |
77 | 77 | ||
78 | let def = find_definition(sema, syntax, position) | 78 | let def = find_definition(sema, syntax, position)?; |
79 | .ok_or_else(|| format_err!("No references found at position"))?; | ||
80 | match def { | 79 | match def { |
81 | Definition::ModuleDef(ModuleDef::Module(module)) => rename_mod(&sema, module, new_name), | 80 | Definition::ModuleDef(ModuleDef::Module(module)) => rename_mod(&sema, module, new_name), |
82 | def => rename_reference(sema, def, new_name), | 81 | def => rename_reference(sema, def, new_name), |
@@ -149,18 +148,30 @@ fn find_definition( | |||
149 | sema: &Semantics<RootDatabase>, | 148 | sema: &Semantics<RootDatabase>, |
150 | syntax: &SyntaxNode, | 149 | syntax: &SyntaxNode, |
151 | position: FilePosition, | 150 | position: FilePosition, |
152 | ) -> Option<Definition> { | 151 | ) -> RenameResult<Definition> { |
153 | let def = match find_name_like(sema, syntax, position)? { | 152 | match find_name_like(sema, syntax, position) |
154 | NameLike::Name(name) => NameClass::classify(sema, &name)?.referenced_or_defined(sema.db), | 153 | .ok_or_else(|| format_err!("No references found at position"))? |
155 | NameLike::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), | 154 | { |
155 | // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet | ||
156 | NameLike::Name(name) | ||
157 | if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => | ||
158 | { | ||
159 | bail!("Renaming aliases is currently unsupported") | ||
160 | } | ||
161 | NameLike::Name(name) => { | ||
162 | NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db)) | ||
163 | } | ||
164 | NameLike::NameRef(name_ref) => { | ||
165 | NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db)) | ||
166 | } | ||
156 | NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) | 167 | NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) |
157 | .map(|class| NameRefClass::referenced(class, sema.db)) | 168 | .map(|class| NameRefClass::referenced(class, sema.db)) |
158 | .or_else(|| { | 169 | .or_else(|| { |
159 | NameClass::classify_lifetime(sema, &lifetime) | 170 | NameClass::classify_lifetime(sema, &lifetime) |
160 | .map(|it| it.referenced_or_defined(sema.db)) | 171 | .map(|it| it.referenced_or_defined(sema.db)) |
161 | })?, | 172 | }), |
162 | }; | 173 | } |
163 | Some(def) | 174 | .ok_or_else(|| format_err!("No references found at position")) |
164 | } | 175 | } |
165 | 176 | ||
166 | fn source_edit_from_references( | 177 | fn source_edit_from_references( |
@@ -173,21 +184,40 @@ fn source_edit_from_references( | |||
173 | let mut edit = TextEdit::builder(); | 184 | let mut edit = TextEdit::builder(); |
174 | for reference in references { | 185 | for reference in references { |
175 | let (range, replacement) = match &reference.name { | 186 | let (range, replacement) = match &reference.name { |
176 | NameLike::Name(_) => (None, format!("{}", new_name)), | 187 | // if the ranges differ then the node is inside a macro call, we can't really attempt |
177 | NameLike::NameRef(name_ref) => source_edit_from_name_ref(name_ref, new_name, def), | 188 | // to make special rewrites like shorthand syntax and such, so just rename the node in |
178 | NameLike::Lifetime(_) => (None, format!("{}", new_name)), | 189 | // the macro input |
179 | }; | 190 | NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == reference.range => { |
180 | // FIXME: Some(range) will be incorrect when we are inside macros | 191 | source_edit_from_name_ref(name_ref, new_name, def) |
181 | edit.replace(range.unwrap_or(reference.range), replacement); | 192 | } |
193 | NameLike::Name(name) if name.syntax().text_range() == reference.range => { | ||
194 | source_edit_from_name(name, new_name) | ||
195 | } | ||
196 | _ => None, | ||
197 | } | ||
198 | .unwrap_or_else(|| (reference.range, new_name.to_string())); | ||
199 | edit.replace(range, replacement); | ||
182 | } | 200 | } |
183 | (file_id, edit.finish()) | 201 | (file_id, edit.finish()) |
184 | } | 202 | } |
185 | 203 | ||
204 | fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> { | ||
205 | if let Some(_) = ast::RecordPatField::for_field_name(name) { | ||
206 | if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { | ||
207 | return Some(( | ||
208 | TextRange::empty(ident_pat.syntax().text_range().start()), | ||
209 | format!("{}: ", new_name), | ||
210 | )); | ||
211 | } | ||
212 | } | ||
213 | None | ||
214 | } | ||
215 | |||
186 | fn source_edit_from_name_ref( | 216 | fn source_edit_from_name_ref( |
187 | name_ref: &ast::NameRef, | 217 | name_ref: &ast::NameRef, |
188 | new_name: &str, | 218 | new_name: &str, |
189 | def: Definition, | 219 | def: Definition, |
190 | ) -> (Option<TextRange>, String) { | 220 | ) -> Option<(TextRange, String)> { |
191 | if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) { | 221 | if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) { |
192 | let rcf_name_ref = record_field.name_ref(); | 222 | let rcf_name_ref = record_field.name_ref(); |
193 | let rcf_expr = record_field.expr(); | 223 | let rcf_expr = record_field.expr(); |
@@ -197,45 +227,40 @@ fn source_edit_from_name_ref( | |||
197 | if field_name == *name_ref { | 227 | if field_name == *name_ref { |
198 | if init.text() == new_name { | 228 | if init.text() == new_name { |
199 | mark::hit!(test_rename_field_put_init_shorthand); | 229 | mark::hit!(test_rename_field_put_init_shorthand); |
200 | // same names, we can use a shorthand here instead | 230 | // same names, we can use a shorthand here instead. |
201 | // we do not want to erase attributes hence this range start | 231 | // we do not want to erase attributes hence this range start |
202 | let s = field_name.syntax().text_range().start(); | 232 | let s = field_name.syntax().text_range().start(); |
203 | let e = record_field.syntax().text_range().end(); | 233 | let e = record_field.syntax().text_range().end(); |
204 | return (Some(TextRange::new(s, e)), format!("{}", new_name)); | 234 | return Some((TextRange::new(s, e), new_name.to_owned())); |
205 | } | 235 | } |
206 | } else if init == *name_ref { | 236 | } else if init == *name_ref { |
207 | if field_name.text() == new_name { | 237 | if field_name.text() == new_name { |
208 | mark::hit!(test_rename_local_put_init_shorthand); | 238 | mark::hit!(test_rename_local_put_init_shorthand); |
209 | // same names, we can use a shorthand here instead | 239 | // same names, we can use a shorthand here instead. |
210 | // we do not want to erase attributes hence this range start | 240 | // we do not want to erase attributes hence this range start |
211 | let s = field_name.syntax().text_range().start(); | 241 | let s = field_name.syntax().text_range().start(); |
212 | let e = record_field.syntax().text_range().end(); | 242 | let e = record_field.syntax().text_range().end(); |
213 | return (Some(TextRange::new(s, e)), format!("{}", new_name)); | 243 | return Some((TextRange::new(s, e), new_name.to_owned())); |
214 | } | 244 | } |
215 | } | 245 | } |
246 | None | ||
216 | } | 247 | } |
217 | // init shorthand | 248 | // init shorthand |
218 | (None, Some(_)) => { | 249 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the |
219 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the | 250 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 |
220 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 | 251 | (None, Some(_)) if matches!(def, Definition::Field(_)) => { |
221 | match def { | 252 | mark::hit!(test_rename_field_in_field_shorthand); |
222 | Definition::Field(_) => { | 253 | let s = name_ref.syntax().text_range().start(); |
223 | mark::hit!(test_rename_field_in_field_shorthand); | 254 | Some((TextRange::empty(s), format!("{}: ", new_name))) |
224 | let s = name_ref.syntax().text_range().start(); | ||
225 | return (Some(TextRange::empty(s)), format!("{}: ", new_name)); | ||
226 | } | ||
227 | Definition::Local(_) => { | ||
228 | mark::hit!(test_rename_local_in_field_shorthand); | ||
229 | let s = name_ref.syntax().text_range().end(); | ||
230 | return (Some(TextRange::empty(s)), format!(": {}", new_name)); | ||
231 | } | ||
232 | _ => {} | ||
233 | } | ||
234 | } | 255 | } |
235 | _ => {} | 256 | (None, Some(_)) if matches!(def, Definition::Local(_)) => { |
257 | mark::hit!(test_rename_local_in_field_shorthand); | ||
258 | let s = name_ref.syntax().text_range().end(); | ||
259 | Some((TextRange::empty(s), format!(": {}", new_name))) | ||
260 | } | ||
261 | _ => None, | ||
236 | } | 262 | } |
237 | } | 263 | } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) { |
238 | if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) { | ||
239 | let rcf_name_ref = record_field.name_ref(); | 264 | let rcf_name_ref = record_field.name_ref(); |
240 | let rcf_pat = record_field.pat(); | 265 | let rcf_pat = record_field.pat(); |
241 | match (rcf_name_ref, rcf_pat) { | 266 | match (rcf_name_ref, rcf_pat) { |
@@ -244,17 +269,20 @@ fn source_edit_from_name_ref( | |||
244 | // field name is being renamed | 269 | // field name is being renamed |
245 | if pat.name().map_or(false, |it| it.text() == new_name) { | 270 | if pat.name().map_or(false, |it| it.text() == new_name) { |
246 | mark::hit!(test_rename_field_put_init_shorthand_pat); | 271 | mark::hit!(test_rename_field_put_init_shorthand_pat); |
247 | // same names, we can use a shorthand here instead | 272 | // same names, we can use a shorthand here instead/ |
248 | // we do not want to erase attributes hence this range start | 273 | // we do not want to erase attributes hence this range start |
249 | let s = field_name.syntax().text_range().start(); | 274 | let s = field_name.syntax().text_range().start(); |
250 | let e = record_field.syntax().text_range().end(); | 275 | let e = record_field.syntax().text_range().end(); |
251 | return (Some(TextRange::new(s, e)), format!("{}", new_name)); | 276 | Some((TextRange::new(s, e), pat.to_string())) |
277 | } else { | ||
278 | None | ||
252 | } | 279 | } |
253 | } | 280 | } |
254 | _ => {} | 281 | _ => None, |
255 | } | 282 | } |
283 | } else { | ||
284 | None | ||
256 | } | 285 | } |
257 | (None, format!("{}", new_name)) | ||
258 | } | 286 | } |
259 | 287 | ||
260 | fn rename_mod( | 288 | fn rename_mod( |
@@ -1477,7 +1505,7 @@ fn foo(i: i32) -> Foo { | |||
1477 | } | 1505 | } |
1478 | 1506 | ||
1479 | #[test] | 1507 | #[test] |
1480 | fn test_struct_field_destructure_into_shorthand() { | 1508 | fn test_struct_field_pat_into_shorthand() { |
1481 | mark::check!(test_rename_field_put_init_shorthand_pat); | 1509 | mark::check!(test_rename_field_put_init_shorthand_pat); |
1482 | check( | 1510 | check( |
1483 | "baz", | 1511 | "baz", |
@@ -1485,16 +1513,16 @@ fn foo(i: i32) -> Foo { | |||
1485 | struct Foo { i$0: i32 } | 1513 | struct Foo { i$0: i32 } |
1486 | 1514 | ||
1487 | fn foo(foo: Foo) { | 1515 | fn foo(foo: Foo) { |
1488 | let Foo { i: baz } = foo; | 1516 | let Foo { i: ref baz @ qux } = foo; |
1489 | let _ = baz; | 1517 | let _ = qux; |
1490 | } | 1518 | } |
1491 | "#, | 1519 | "#, |
1492 | r#" | 1520 | r#" |
1493 | struct Foo { baz: i32 } | 1521 | struct Foo { baz: i32 } |
1494 | 1522 | ||
1495 | fn foo(foo: Foo) { | 1523 | fn foo(foo: Foo) { |
1496 | let Foo { baz } = foo; | 1524 | let Foo { ref baz @ qux } = foo; |
1497 | let _ = baz; | 1525 | let _ = qux; |
1498 | } | 1526 | } |
1499 | "#, | 1527 | "#, |
1500 | ); | 1528 | ); |
@@ -1568,6 +1596,27 @@ fn foo(Foo { i: bar }: foo) -> i32 { | |||
1568 | } | 1596 | } |
1569 | 1597 | ||
1570 | #[test] | 1598 | #[test] |
1599 | fn test_struct_field_complex_ident_pat() { | ||
1600 | check( | ||
1601 | "baz", | ||
1602 | r#" | ||
1603 | struct Foo { i$0: i32 } | ||
1604 | |||
1605 | fn foo(foo: Foo) { | ||
1606 | let Foo { ref i } = foo; | ||
1607 | } | ||
1608 | "#, | ||
1609 | r#" | ||
1610 | struct Foo { baz: i32 } | ||
1611 | |||
1612 | fn foo(foo: Foo) { | ||
1613 | let Foo { baz: ref i } = foo; | ||
1614 | } | ||
1615 | "#, | ||
1616 | ); | ||
1617 | } | ||
1618 | |||
1619 | #[test] | ||
1571 | fn test_rename_lifetimes() { | 1620 | fn test_rename_lifetimes() { |
1572 | mark::check!(rename_lifetime); | 1621 | mark::check!(rename_lifetime); |
1573 | check( | 1622 | check( |
@@ -1674,4 +1723,38 @@ impl Foo { | |||
1674 | "#, | 1723 | "#, |
1675 | ) | 1724 | ) |
1676 | } | 1725 | } |
1726 | |||
1727 | #[test] | ||
1728 | fn test_rename_field_in_pat_in_macro_doesnt_shorthand() { | ||
1729 | // ideally we would be able to make this emit a short hand, but I doubt this is easily possible | ||
1730 | check( | ||
1731 | "baz", | ||
1732 | r#" | ||
1733 | macro_rules! foo { | ||
1734 | ($pattern:pat) => { | ||
1735 | let $pattern = loop {}; | ||
1736 | }; | ||
1737 | } | ||
1738 | struct Foo { | ||
1739 | bar$0: u32, | ||
1740 | } | ||
1741 | fn foo() { | ||
1742 | foo!(Foo { bar: baz }); | ||
1743 | } | ||
1744 | "#, | ||
1745 | r#" | ||
1746 | macro_rules! foo { | ||
1747 | ($pattern:pat) => { | ||
1748 | let $pattern = loop {}; | ||
1749 | }; | ||
1750 | } | ||
1751 | struct Foo { | ||
1752 | baz: u32, | ||
1753 | } | ||
1754 | fn foo() { | ||
1755 | foo!(Foo { baz: baz }); | ||
1756 | } | ||
1757 | "#, | ||
1758 | ) | ||
1759 | } | ||
1677 | } | 1760 | } |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index a8091dbee..ff612b7d0 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -6,8 +6,8 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | db::HirDatabase, Crate, Field, GenericParam, HasVisibility, Impl, Label, Local, MacroDef, | 9 | db::HirDatabase, Crate, Field, GenericParam, HasAttrs, HasVisibility, Impl, Label, Local, |
10 | Module, ModuleDef, Name, PathResolution, Semantics, Visibility, | 10 | MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, Visibility, |
11 | }; | 11 | }; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode, PathSegmentKind}, | 13 | ast::{self, AstNode, PathSegmentKind}, |
@@ -366,7 +366,15 @@ impl NameRefClass { | |||
366 | 366 | ||
367 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { | 367 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { |
368 | if let Some(resolved) = sema.resolve_path(&path) { | 368 | if let Some(resolved) = sema.resolve_path(&path) { |
369 | return Some(NameRefClass::Definition(resolved.into())); | 369 | if path.syntax().parent().and_then(ast::Attr::cast).is_some() { |
370 | if let PathResolution::Def(ModuleDef::Function(func)) = resolved { | ||
371 | if func.attrs(sema.db).by_key("proc_macro_attribute").exists() { | ||
372 | return Some(NameRefClass::Definition(resolved.into())); | ||
373 | } | ||
374 | } | ||
375 | } else { | ||
376 | return Some(NameRefClass::Definition(resolved.into())); | ||
377 | } | ||
370 | } | 378 | } |
371 | } | 379 | } |
372 | 380 | ||
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index f47898b9b..1d8d34a0b 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -44,6 +44,15 @@ impl ops::Index<Target> for CargoWorkspace { | |||
44 | } | 44 | } |
45 | } | 45 | } |
46 | 46 | ||
47 | /// Describes how to set the rustc source directory. | ||
48 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
49 | pub enum RustcSource { | ||
50 | /// Explicit path for the rustc source directory. | ||
51 | Path(AbsPathBuf), | ||
52 | /// Try to automatically detect where the rustc source directory is. | ||
53 | Discover, | ||
54 | } | ||
55 | |||
47 | #[derive(Default, Clone, Debug, PartialEq, Eq)] | 56 | #[derive(Default, Clone, Debug, PartialEq, Eq)] |
48 | pub struct CargoConfig { | 57 | pub struct CargoConfig { |
49 | /// Do not activate the `default` feature. | 58 | /// Do not activate the `default` feature. |
@@ -64,7 +73,7 @@ pub struct CargoConfig { | |||
64 | pub no_sysroot: bool, | 73 | pub no_sysroot: bool, |
65 | 74 | ||
66 | /// rustc private crate source | 75 | /// rustc private crate source |
67 | pub rustc_source: Option<AbsPathBuf>, | 76 | pub rustc_source: Option<RustcSource>, |
68 | } | 77 | } |
69 | 78 | ||
70 | pub type Package = Idx<PackageData>; | 79 | pub type Package = Idx<PackageData>; |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index d712095a6..a5b35ed95 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -21,8 +21,8 @@ use rustc_hash::FxHashSet; | |||
21 | pub use crate::{ | 21 | pub use crate::{ |
22 | build_data::{BuildDataCollector, BuildDataResult}, | 22 | build_data::{BuildDataCollector, BuildDataResult}, |
23 | cargo_workspace::{ | 23 | cargo_workspace::{ |
24 | CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, Target, TargetData, | 24 | CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target, |
25 | TargetKind, | 25 | TargetData, TargetKind, |
26 | }, | 26 | }, |
27 | project_json::{ProjectJson, ProjectJsonData}, | 27 | project_json::{ProjectJson, ProjectJsonData}, |
28 | sysroot::Sysroot, | 28 | sysroot::Sysroot, |
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs index ff44dae4a..3b0ff506d 100644 --- a/crates/project_model/src/sysroot.rs +++ b/crates/project_model/src/sysroot.rs | |||
@@ -51,11 +51,18 @@ impl Sysroot { | |||
51 | pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> { | 51 | pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> { |
52 | log::debug!("Discovering sysroot for {}", cargo_toml.display()); | 52 | log::debug!("Discovering sysroot for {}", cargo_toml.display()); |
53 | let current_dir = cargo_toml.parent().unwrap(); | 53 | let current_dir = cargo_toml.parent().unwrap(); |
54 | let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?; | 54 | let sysroot_dir = discover_sysroot_dir(current_dir)?; |
55 | let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, current_dir)?; | ||
55 | let res = Sysroot::load(&sysroot_src_dir)?; | 56 | let res = Sysroot::load(&sysroot_src_dir)?; |
56 | Ok(res) | 57 | Ok(res) |
57 | } | 58 | } |
58 | 59 | ||
60 | pub fn discover_rustc(cargo_toml: &AbsPath) -> Option<AbsPathBuf> { | ||
61 | log::debug!("Discovering rustc source for {}", cargo_toml.display()); | ||
62 | let current_dir = cargo_toml.parent().unwrap(); | ||
63 | discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir)) | ||
64 | } | ||
65 | |||
59 | pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { | 66 | pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { |
60 | let mut sysroot = Sysroot { crates: Arena::default() }; | 67 | let mut sysroot = Sysroot { crates: Arena::default() }; |
61 | 68 | ||
@@ -110,7 +117,18 @@ impl Sysroot { | |||
110 | } | 117 | } |
111 | } | 118 | } |
112 | 119 | ||
113 | fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> { | 120 | fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> { |
121 | let mut rustc = Command::new(toolchain::rustc()); | ||
122 | rustc.current_dir(current_dir).args(&["--print", "sysroot"]); | ||
123 | log::debug!("Discovering sysroot by {:?}", rustc); | ||
124 | let stdout = utf8_stdout(rustc)?; | ||
125 | Ok(AbsPathBuf::assert(PathBuf::from(stdout))) | ||
126 | } | ||
127 | |||
128 | fn discover_sysroot_src_dir( | ||
129 | sysroot_path: &AbsPathBuf, | ||
130 | current_dir: &AbsPath, | ||
131 | ) -> Result<AbsPathBuf> { | ||
114 | if let Ok(path) = env::var("RUST_SRC_PATH") { | 132 | if let Ok(path) = env::var("RUST_SRC_PATH") { |
115 | let path = AbsPathBuf::try_from(path.as_str()) | 133 | let path = AbsPathBuf::try_from(path.as_str()) |
116 | .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?; | 134 | .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?; |
@@ -122,14 +140,6 @@ fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> { | |||
122 | log::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core); | 140 | log::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core); |
123 | } | 141 | } |
124 | 142 | ||
125 | let sysroot_path = { | ||
126 | let mut rustc = Command::new(toolchain::rustc()); | ||
127 | rustc.current_dir(current_dir).args(&["--print", "sysroot"]); | ||
128 | log::debug!("Discovering sysroot by {:?}", rustc); | ||
129 | let stdout = utf8_stdout(rustc)?; | ||
130 | AbsPathBuf::assert(PathBuf::from(stdout)) | ||
131 | }; | ||
132 | |||
133 | get_rust_src(&sysroot_path) | 143 | get_rust_src(&sysroot_path) |
134 | .or_else(|| { | 144 | .or_else(|| { |
135 | let mut rustup = Command::new(toolchain::rustup()); | 145 | let mut rustup = Command::new(toolchain::rustup()); |
@@ -149,6 +159,16 @@ try installing the Rust source the same way you installed rustc", | |||
149 | }) | 159 | }) |
150 | } | 160 | } |
151 | 161 | ||
162 | fn get_rustc_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> { | ||
163 | let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml"); | ||
164 | log::debug!("Checking for rustc source code: {}", rustc_src.display()); | ||
165 | if rustc_src.exists() { | ||
166 | Some(rustc_src) | ||
167 | } else { | ||
168 | None | ||
169 | } | ||
170 | } | ||
171 | |||
152 | fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> { | 172 | fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> { |
153 | // Try the new path first since the old one still exists. | 173 | // Try the new path first since the old one still exists. |
154 | let rust_src = sysroot_path.join("lib/rustlib/src/rust"); | 174 | let rust_src = sysroot_path.join("lib/rustlib/src/rust"); |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index c30861976..0220efdb4 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -114,6 +114,7 @@ impl ProjectWorkspace { | |||
114 | cargo_version | 114 | cargo_version |
115 | ) | 115 | ) |
116 | })?; | 116 | })?; |
117 | |||
117 | let sysroot = if config.no_sysroot { | 118 | let sysroot = if config.no_sysroot { |
118 | Sysroot::default() | 119 | Sysroot::default() |
119 | } else { | 120 | } else { |
@@ -125,7 +126,17 @@ impl ProjectWorkspace { | |||
125 | })? | 126 | })? |
126 | }; | 127 | }; |
127 | 128 | ||
128 | let rustc = if let Some(rustc_dir) = &config.rustc_source { | 129 | let rustc_dir = if let Some(rustc_source) = &config.rustc_source { |
130 | use cargo_workspace::RustcSource; | ||
131 | match rustc_source { | ||
132 | RustcSource::Path(path) => Some(path.clone()), | ||
133 | RustcSource::Discover => Sysroot::discover_rustc(&cargo_toml), | ||
134 | } | ||
135 | } else { | ||
136 | None | ||
137 | }; | ||
138 | |||
139 | let rustc = if let Some(rustc_dir) = rustc_dir { | ||
129 | Some( | 140 | Some( |
130 | CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress) | 141 | CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress) |
131 | .with_context(|| { | 142 | .with_context(|| { |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 82ea76666..746b4cdaa 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -22,7 +22,7 @@ env_logger = { version = "0.8.1", default-features = false } | |||
22 | itertools = "0.10.0" | 22 | itertools = "0.10.0" |
23 | jod-thread = "0.1.0" | 23 | jod-thread = "0.1.0" |
24 | log = "0.4.8" | 24 | log = "0.4.8" |
25 | lsp-types = { version = "0.86.0", features = ["proposed"] } | 25 | lsp-types = { version = "0.87.0", features = ["proposed"] } |
26 | parking_lot = "0.11.0" | 26 | parking_lot = "0.11.0" |
27 | pico-args = "0.4.0" | 27 | pico-args = "0.4.0" |
28 | oorandom = "11.1.2" | 28 | oorandom = "11.1.2" |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 088b17b03..93d0ad4ec 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -127,6 +127,7 @@ fn run_server() -> Result<()> { | |||
127 | name: String::from("rust-analyzer"), | 127 | name: String::from("rust-analyzer"), |
128 | version: Some(String::from(env!("REV"))), | 128 | version: Some(String::from(env!("REV"))), |
129 | }), | 129 | }), |
130 | offset_encoding: None, | ||
130 | }; | 131 | }; |
131 | 132 | ||
132 | let initialize_result = serde_json::to_value(initialize_result).unwrap(); | 133 | let initialize_result = serde_json::to_value(initialize_result).unwrap(); |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index f148521a2..aa48c455c 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -34,6 +34,8 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
34 | completion_provider: Some(CompletionOptions { | 34 | completion_provider: Some(CompletionOptions { |
35 | resolve_provider: completions_resolve_provider(client_caps), | 35 | resolve_provider: completions_resolve_provider(client_caps), |
36 | trigger_characters: Some(vec![":".to_string(), ".".to_string()]), | 36 | trigger_characters: Some(vec![":".to_string(), ".".to_string()]), |
37 | all_commit_characters: None, | ||
38 | completion_item: None, | ||
37 | work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, | 39 | work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, |
38 | }), | 40 | }), |
39 | signature_help_provider: Some(SignatureHelpOptions { | 41 | signature_help_provider: Some(SignatureHelpOptions { |
@@ -58,7 +60,6 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
58 | more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), | 60 | more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), |
59 | }), | 61 | }), |
60 | selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), | 62 | selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), |
61 | semantic_highlighting: None, | ||
62 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), | 63 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), |
63 | rename_provider: Some(OneOf::Right(RenameOptions { | 64 | rename_provider: Some(OneOf::Right(RenameOptions { |
64 | prepare_provider: Some(true), | 65 | prepare_provider: Some(true), |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index cc0b22bff..f9098968a 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -18,7 +18,7 @@ use ide_db::helpers::{ | |||
18 | }; | 18 | }; |
19 | use itertools::Itertools; | 19 | use itertools::Itertools; |
20 | use lsp_types::{ClientCapabilities, MarkupKind}; | 20 | use lsp_types::{ClientCapabilities, MarkupKind}; |
21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource}; |
22 | use rustc_hash::FxHashSet; | 22 | use rustc_hash::FxHashSet; |
23 | use serde::{de::DeserializeOwned, Deserialize}; | 23 | use serde::{de::DeserializeOwned, Deserialize}; |
24 | use vfs::AbsPathBuf; | 24 | use vfs::AbsPathBuf; |
@@ -177,8 +177,9 @@ config_data! { | |||
177 | /// tests or binaries.\nFor example, it may be `--release`. | 177 | /// tests or binaries.\nFor example, it may be `--release`. |
178 | runnables_cargoExtraArgs: Vec<String> = "[]", | 178 | runnables_cargoExtraArgs: Vec<String> = "[]", |
179 | 179 | ||
180 | /// Path to the rust compiler sources, for usage in rustc_private projects. | 180 | /// Path to the rust compiler sources, for usage in rustc_private projects, or "discover" |
181 | rustcSource : Option<PathBuf> = "null", | 181 | /// to try to automatically find it. |
182 | rustcSource : Option<String> = "null", | ||
182 | 183 | ||
183 | /// Additional arguments to `rustfmt`. | 184 | /// Additional arguments to `rustfmt`. |
184 | rustfmt_extraArgs: Vec<String> = "[]", | 185 | rustfmt_extraArgs: Vec<String> = "[]", |
@@ -473,7 +474,13 @@ impl Config { | |||
473 | self.data.cargo_loadOutDirsFromCheck | 474 | self.data.cargo_loadOutDirsFromCheck |
474 | } | 475 | } |
475 | pub fn cargo(&self) -> CargoConfig { | 476 | pub fn cargo(&self) -> CargoConfig { |
476 | let rustc_source = self.data.rustcSource.as_ref().map(|it| self.root_path.join(&it)); | 477 | let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| { |
478 | if rustc_src == "discover" { | ||
479 | RustcSource::Discover | ||
480 | } else { | ||
481 | RustcSource::Path(self.root_path.join(rustc_src)) | ||
482 | } | ||
483 | }); | ||
477 | 484 | ||
478 | CargoConfig { | 485 | CargoConfig { |
479 | no_default_features: self.data.cargo_noDefaultFeatures, | 486 | no_default_features: self.data.cargo_noDefaultFeatures, |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index b051c8f6c..2d697c75f 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -10,8 +10,7 @@ use std::{ | |||
10 | 10 | ||
11 | use ide::{ | 11 | use ide::{ |
12 | AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, | 12 | AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, |
13 | NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, | 13 | Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit, |
14 | TextEdit, | ||
15 | }; | 14 | }; |
16 | use ide_db::SymbolKind; | 15 | use ide_db::SymbolKind; |
17 | use itertools::Itertools; | 16 | use itertools::Itertools; |
@@ -19,12 +18,12 @@ use lsp_server::ErrorCode; | |||
19 | use lsp_types::{ | 18 | use lsp_types::{ |
20 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 19 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
21 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, | 20 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, |
22 | CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag, | 21 | CodeActionKind, CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams, |
23 | DocumentFormattingParams, DocumentHighlight, FoldingRange, FoldingRangeParams, HoverContents, | 22 | DocumentHighlight, FoldingRange, FoldingRangeParams, HoverContents, Location, NumberOrString, |
24 | Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams, | 23 | Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensDeltaParams, |
25 | SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, | 24 | SemanticTokensFullDeltaResult, SemanticTokensParams, SemanticTokensRangeParams, |
26 | SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, | 25 | SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, SymbolTag, |
27 | SymbolTag, TextDocumentIdentifier, TextDocumentPositionParams, Url, WorkspaceEdit, | 26 | TextDocumentIdentifier, TextDocumentPositionParams, Url, WorkspaceEdit, |
28 | }; | 27 | }; |
29 | use project_model::TargetKind; | 28 | use project_model::TargetKind; |
30 | use serde::{Deserialize, Serialize}; | 29 | use serde::{Deserialize, Serialize}; |
@@ -1422,40 +1421,7 @@ pub(crate) fn handle_open_cargo_toml( | |||
1422 | Ok(Some(res)) | 1421 | Ok(Some(res)) |
1423 | } | 1422 | } |
1424 | 1423 | ||
1425 | fn run_single_command(runnable: &lsp_ext::Runnable, title: &str) -> Command { | 1424 | fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink { |
1426 | Command { | ||
1427 | title: title.to_string(), | ||
1428 | command: "rust-analyzer.runSingle".into(), | ||
1429 | arguments: Some(vec![to_value(runnable).unwrap()]), | ||
1430 | } | ||
1431 | } | ||
1432 | |||
1433 | fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command { | ||
1434 | Command { | ||
1435 | title: "Debug".into(), | ||
1436 | command: "rust-analyzer.debugSingle".into(), | ||
1437 | arguments: Some(vec![to_value(runnable).unwrap()]), | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> { | ||
1442 | let value = if snap.config.location_link() { | ||
1443 | let link = to_proto::location_link(snap, None, nav.clone()).ok()?; | ||
1444 | to_value(link).ok()? | ||
1445 | } else { | ||
1446 | let range = FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }; | ||
1447 | let location = to_proto::location(snap, range).ok()?; | ||
1448 | to_value(location).ok()? | ||
1449 | }; | ||
1450 | |||
1451 | Some(Command { | ||
1452 | title: nav.name.to_string(), | ||
1453 | command: "rust-analyzer.gotoLocation".into(), | ||
1454 | arguments: Some(vec![value]), | ||
1455 | }) | ||
1456 | } | ||
1457 | |||
1458 | fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { | ||
1459 | lsp_ext::CommandLink { tooltip: Some(tooltip), command } | 1425 | lsp_ext::CommandLink { tooltip: Some(tooltip), command } |
1460 | } | 1426 | } |
1461 | 1427 | ||
@@ -1474,7 +1440,7 @@ fn show_impl_command_link( | |||
1474 | .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok()) | 1440 | .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok()) |
1475 | .collect(); | 1441 | .collect(); |
1476 | let title = to_proto::implementation_title(locations.len()); | 1442 | let title = to_proto::implementation_title(locations.len()); |
1477 | let command = to_proto::show_references_command(title, &uri, position, locations); | 1443 | let command = to_proto::command::show_references(title, &uri, position, locations); |
1478 | 1444 | ||
1479 | return Some(lsp_ext::CommandLinkGroup { | 1445 | return Some(lsp_ext::CommandLinkGroup { |
1480 | commands: vec![to_command_link(command, "Go to implementations".into())], | 1446 | commands: vec![to_command_link(command, "Go to implementations".into())], |
@@ -1501,12 +1467,12 @@ fn runnable_action_links( | |||
1501 | let mut group = lsp_ext::CommandLinkGroup::default(); | 1467 | let mut group = lsp_ext::CommandLinkGroup::default(); |
1502 | 1468 | ||
1503 | if hover_config.run { | 1469 | if hover_config.run { |
1504 | let run_command = run_single_command(&r, action.run_title); | 1470 | let run_command = to_proto::command::run_single(&r, action.run_title); |
1505 | group.commands.push(to_command_link(run_command, r.label.clone())); | 1471 | group.commands.push(to_command_link(run_command, r.label.clone())); |
1506 | } | 1472 | } |
1507 | 1473 | ||
1508 | if hover_config.debug { | 1474 | if hover_config.debug { |
1509 | let dbg_command = debug_single_command(&r); | 1475 | let dbg_command = to_proto::command::debug_single(&r); |
1510 | group.commands.push(to_command_link(dbg_command, r.label)); | 1476 | group.commands.push(to_command_link(dbg_command, r.label)); |
1511 | } | 1477 | } |
1512 | 1478 | ||
@@ -1527,7 +1493,7 @@ fn goto_type_action_links( | |||
1527 | commands: nav_targets | 1493 | commands: nav_targets |
1528 | .iter() | 1494 | .iter() |
1529 | .filter_map(|it| { | 1495 | .filter_map(|it| { |
1530 | goto_location_command(snap, &it.nav) | 1496 | to_proto::command::goto_location(snap, &it.nav) |
1531 | .map(|cmd| to_command_link(cmd, it.mod_path.clone())) | 1497 | .map(|cmd| to_command_link(cmd, it.mod_path.clone())) |
1532 | }) | 1498 | }) |
1533 | .collect(), | 1499 | .collect(), |
diff --git a/crates/rust-analyzer/src/line_endings.rs b/crates/rust-analyzer/src/line_endings.rs index 9f892f32e..bf0e255d9 100644 --- a/crates/rust-analyzer/src/line_endings.rs +++ b/crates/rust-analyzer/src/line_endings.rs | |||
@@ -46,7 +46,7 @@ impl LineEndings { | |||
46 | return (src, LineEndings::Dos); | 46 | return (src, LineEndings::Dos); |
47 | 47 | ||
48 | fn find_crlf(src: &[u8]) -> Option<usize> { | 48 | fn find_crlf(src: &[u8]) -> Option<usize> { |
49 | src.iter().zip(src.iter().skip(1)).position(|it| it == (&b'\r', &b'\n')) | 49 | src.windows(2).position(|it| it == b"\r\n") |
50 | } | 50 | } |
51 | } | 51 | } |
52 | } | 52 | } |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 29fac96fb..8a2b4d9bd 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -229,11 +229,7 @@ pub(crate) fn completion_item( | |||
229 | } | 229 | } |
230 | 230 | ||
231 | if completion_item.trigger_call_info() { | 231 | if completion_item.trigger_call_info() { |
232 | res.command = Some(lsp_types::Command { | 232 | res.command = Some(command::trigger_parameter_hints()); |
233 | title: "triggerParameterHints".into(), | ||
234 | command: "editor.action.triggerParameterHints".into(), | ||
235 | arguments: None, | ||
236 | }); | ||
237 | } | 233 | } |
238 | 234 | ||
239 | let mut all_results = match completion_item.ref_match() { | 235 | let mut all_results = match completion_item.ref_match() { |
@@ -878,17 +874,10 @@ pub(crate) fn code_lens( | |||
878 | let r = runnable(&snap, run.nav.file_id, run)?; | 874 | let r = runnable(&snap, run.nav.file_id, run)?; |
879 | 875 | ||
880 | let command = if debug { | 876 | let command = if debug { |
881 | lsp_types::Command { | 877 | command::debug_single(&r) |
882 | title: action.run_title.to_string(), | ||
883 | command: "rust-analyzer.runSingle".into(), | ||
884 | arguments: Some(vec![to_value(r).unwrap()]), | ||
885 | } | ||
886 | } else { | 878 | } else { |
887 | lsp_types::Command { | 879 | let title = action.run_title.to_string(); |
888 | title: "Debug".into(), | 880 | command::run_single(&r, &title) |
889 | command: "rust-analyzer.debugSingle".into(), | ||
890 | arguments: Some(vec![to_value(r).unwrap()]), | ||
891 | } | ||
892 | }; | 881 | }; |
893 | 882 | ||
894 | Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None }) | 883 | Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None }) |
@@ -922,7 +911,7 @@ pub(crate) fn code_lens( | |||
922 | }) | 911 | }) |
923 | .collect(); | 912 | .collect(); |
924 | 913 | ||
925 | show_references_command( | 914 | command::show_references( |
926 | implementation_title(locations.len()), | 915 | implementation_title(locations.len()), |
927 | &url, | 916 | &url, |
928 | position, | 917 | position, |
@@ -951,7 +940,12 @@ pub(crate) fn code_lens( | |||
951 | let locations: Vec<lsp_types::Location> = | 940 | let locations: Vec<lsp_types::Location> = |
952 | ranges.into_iter().filter_map(|range| location(snap, range).ok()).collect(); | 941 | ranges.into_iter().filter_map(|range| location(snap, range).ok()).collect(); |
953 | 942 | ||
954 | show_references_command(reference_title(locations.len()), &url, position, locations) | 943 | command::show_references( |
944 | reference_title(locations.len()), | ||
945 | &url, | ||
946 | position, | ||
947 | locations, | ||
948 | ) | ||
955 | }); | 949 | }); |
956 | 950 | ||
957 | Ok(lsp_types::CodeLens { | 951 | Ok(lsp_types::CodeLens { |
@@ -963,24 +957,79 @@ pub(crate) fn code_lens( | |||
963 | } | 957 | } |
964 | } | 958 | } |
965 | 959 | ||
966 | pub(crate) fn show_references_command( | 960 | pub(crate) mod command { |
967 | title: String, | 961 | use ide::{FileRange, NavigationTarget}; |
968 | uri: &lsp_types::Url, | 962 | use serde_json::to_value; |
969 | position: lsp_types::Position, | 963 | |
970 | locations: Vec<lsp_types::Location>, | 964 | use crate::{ |
971 | ) -> lsp_types::Command { | 965 | global_state::GlobalStateSnapshot, |
972 | // We cannot use the 'editor.action.showReferences' command directly | 966 | lsp_ext, |
973 | // because that command requires vscode types which we convert in the handler | 967 | to_proto::{location, location_link}, |
974 | // on the client side. | 968 | }; |
975 | 969 | ||
976 | lsp_types::Command { | 970 | pub(crate) fn show_references( |
977 | title, | 971 | title: String, |
978 | command: "rust-analyzer.showReferences".into(), | 972 | uri: &lsp_types::Url, |
979 | arguments: Some(vec![ | 973 | position: lsp_types::Position, |
980 | to_value(uri).unwrap(), | 974 | locations: Vec<lsp_types::Location>, |
981 | to_value(position).unwrap(), | 975 | ) -> lsp_types::Command { |
982 | to_value(locations).unwrap(), | 976 | // We cannot use the 'editor.action.showReferences' command directly |
983 | ]), | 977 | // because that command requires vscode types which we convert in the handler |
978 | // on the client side. | ||
979 | |||
980 | lsp_types::Command { | ||
981 | title, | ||
982 | command: "rust-analyzer.showReferences".into(), | ||
983 | arguments: Some(vec![ | ||
984 | to_value(uri).unwrap(), | ||
985 | to_value(position).unwrap(), | ||
986 | to_value(locations).unwrap(), | ||
987 | ]), | ||
988 | } | ||
989 | } | ||
990 | |||
991 | pub(crate) fn run_single(runnable: &lsp_ext::Runnable, title: &str) -> lsp_types::Command { | ||
992 | lsp_types::Command { | ||
993 | title: title.to_string(), | ||
994 | command: "rust-analyzer.runSingle".into(), | ||
995 | arguments: Some(vec![to_value(runnable).unwrap()]), | ||
996 | } | ||
997 | } | ||
998 | |||
999 | pub(crate) fn debug_single(runnable: &lsp_ext::Runnable) -> lsp_types::Command { | ||
1000 | lsp_types::Command { | ||
1001 | title: "Debug".into(), | ||
1002 | command: "rust-analyzer.debugSingle".into(), | ||
1003 | arguments: Some(vec![to_value(runnable).unwrap()]), | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | pub(crate) fn goto_location( | ||
1008 | snap: &GlobalStateSnapshot, | ||
1009 | nav: &NavigationTarget, | ||
1010 | ) -> Option<lsp_types::Command> { | ||
1011 | let value = if snap.config.location_link() { | ||
1012 | let link = location_link(snap, None, nav.clone()).ok()?; | ||
1013 | to_value(link).ok()? | ||
1014 | } else { | ||
1015 | let range = FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }; | ||
1016 | let location = location(snap, range).ok()?; | ||
1017 | to_value(location).ok()? | ||
1018 | }; | ||
1019 | |||
1020 | Some(lsp_types::Command { | ||
1021 | title: nav.name.to_string(), | ||
1022 | command: "rust-analyzer.gotoLocation".into(), | ||
1023 | arguments: Some(vec![value]), | ||
1024 | }) | ||
1025 | } | ||
1026 | |||
1027 | pub(crate) fn trigger_parameter_hints() -> lsp_types::Command { | ||
1028 | lsp_types::Command { | ||
1029 | title: "triggerParameterHints".into(), | ||
1030 | command: "editor.action.triggerParameterHints".into(), | ||
1031 | arguments: None, | ||
1032 | } | ||
984 | } | 1033 | } |
985 | } | 1034 | } |
986 | 1035 | ||
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index b105cb0e0..307e150e9 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -3,12 +3,11 @@ | |||
3 | 3 | ||
4 | use std::fmt; | 4 | use std::fmt; |
5 | 5 | ||
6 | use ast::AttrsOwner; | ||
7 | use itertools::Itertools; | 6 | use itertools::Itertools; |
8 | use parser::SyntaxKind; | 7 | use parser::SyntaxKind; |
9 | 8 | ||
10 | use crate::{ | 9 | use crate::{ |
11 | ast::{self, support, AstNode, AstToken, NameOwner, SyntaxNode}, | 10 | ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, |
12 | SmolStr, SyntaxElement, SyntaxToken, T, | 11 | SmolStr, SyntaxElement, SyntaxToken, T, |
13 | }; | 12 | }; |
14 | 13 | ||
@@ -324,7 +323,7 @@ impl ast::RecordPatField { | |||
324 | 323 | ||
325 | pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> { | 324 | pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> { |
326 | let candidate = | 325 | let candidate = |
327 | field_name.syntax().ancestors().nth(3).and_then(ast::RecordPatField::cast)?; | 326 | field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?; |
328 | match candidate.field_name()? { | 327 | match candidate.field_name()? { |
329 | NameOrNameRef::Name(name) if name == *field_name => Some(candidate), | 328 | NameOrNameRef::Name(name) if name == *field_name => Some(candidate), |
330 | _ => None, | 329 | _ => None, |
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 55178c84c..f91e04c31 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -105,7 +105,7 @@ | |||
105 | [[rust-analyzer.runnables.cargoExtraArgs]]rust-analyzer.runnables.cargoExtraArgs (default: `[]`):: | 105 | [[rust-analyzer.runnables.cargoExtraArgs]]rust-analyzer.runnables.cargoExtraArgs (default: `[]`):: |
106 | Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be `--release`. | 106 | Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be `--release`. |
107 | [[rust-analyzer.rustcSource]]rust-analyzer.rustcSource (default: `null`):: | 107 | [[rust-analyzer.rustcSource]]rust-analyzer.rustcSource (default: `null`):: |
108 | Path to the rust compiler sources, for usage in rustc_private projects. | 108 | Path to the rust compiler sources, for usage in rustc_private projects, or "discover" to try to automatically find it. |
109 | [[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`):: | 109 | [[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`):: |
110 | Additional arguments to `rustfmt`. | 110 | Additional arguments to `rustfmt`. |
111 | [[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`):: | 111 | [[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`):: |
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 2d717e366..42077a7fa 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json | |||
@@ -195,9 +195,9 @@ | |||
195 | } | 195 | } |
196 | }, | 196 | }, |
197 | "@types/vscode": { | 197 | "@types/vscode": { |
198 | "version": "1.52.0", | 198 | "version": "1.53.0", |
199 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz", | 199 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.53.0.tgz", |
200 | "integrity": "sha512-Kt3bvWzAvvF/WH9YEcrCICDp0Z7aHhJGhLJ1BxeyNP6yRjonWqWnAIh35/pXAjswAnWOABrYlF7SwXR9+1nnLA==", | 200 | "integrity": "sha512-XjFWbSPOM0EKIT2XhhYm3D3cx3nn3lshMUcWNy1eqefk+oqRuBq8unVb6BYIZqXy9lQZyeUl7eaBCOZWv+LcXQ==", |
201 | "dev": true | 201 | "dev": true |
202 | }, | 202 | }, |
203 | "@typescript-eslint/eslint-plugin": { | 203 | "@typescript-eslint/eslint-plugin": { |
@@ -2364,33 +2364,33 @@ | |||
2364 | } | 2364 | } |
2365 | }, | 2365 | }, |
2366 | "vscode-jsonrpc": { | 2366 | "vscode-jsonrpc": { |
2367 | "version": "6.0.0", | 2367 | "version": "6.1.0-next.1", |
2368 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", | 2368 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.1.0-next.1.tgz", |
2369 | "integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==" | 2369 | "integrity": "sha512-2s1qEg8N97p8pooHnA8xgR4vnslCTJuE3rQqSQeJuSDklFcQSn9yW8gOinH/1vKeWiPuzHTG9FFty91v4v9Pag==" |
2370 | }, | 2370 | }, |
2371 | "vscode-languageclient": { | 2371 | "vscode-languageclient": { |
2372 | "version": "7.0.0", | 2372 | "version": "7.1.0-next.1", |
2373 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz", | 2373 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.1.0-next.1.tgz", |
2374 | "integrity": "sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==", | 2374 | "integrity": "sha512-pMdMyJ5e3CfdyvtDsj6ytTO+WcmrvtrFJWvBk4rZnIKmA3aCjrqTYI0XSWN/Cf4kcaV1J2+fTZf/2RcP2SzDiQ==", |
2375 | "requires": { | 2375 | "requires": { |
2376 | "minimatch": "^3.0.4", | 2376 | "minimatch": "^3.0.4", |
2377 | "semver": "^7.3.4", | 2377 | "semver": "^7.3.4", |
2378 | "vscode-languageserver-protocol": "3.16.0" | 2378 | "vscode-languageserver-protocol": "3.17.0-next.1" |
2379 | } | 2379 | } |
2380 | }, | 2380 | }, |
2381 | "vscode-languageserver-protocol": { | 2381 | "vscode-languageserver-protocol": { |
2382 | "version": "3.16.0", | 2382 | "version": "3.17.0-next.1", |
2383 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz", | 2383 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.1.tgz", |
2384 | "integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==", | 2384 | "integrity": "sha512-cbFKGk+Q7HQ5RDdf6qiQrRv9qxR/87hBm/GrfLcQ5rmHPJOXg//ZYCXEQF+wSJNmcc6IrnET2cHJUxlZYHUEXA==", |
2385 | "requires": { | 2385 | "requires": { |
2386 | "vscode-jsonrpc": "6.0.0", | 2386 | "vscode-jsonrpc": "6.1.0-next.1", |
2387 | "vscode-languageserver-types": "3.16.0" | 2387 | "vscode-languageserver-types": "3.17.0-next.1" |
2388 | } | 2388 | } |
2389 | }, | 2389 | }, |
2390 | "vscode-languageserver-types": { | 2390 | "vscode-languageserver-types": { |
2391 | "version": "3.16.0", | 2391 | "version": "3.17.0-next.1", |
2392 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", | 2392 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.1.tgz", |
2393 | "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==" | 2393 | "integrity": "sha512-VGzh06oynbYa6JbTKUbxOEZN7CYEtWhN7DK5wfzUpeCJl8X8xZX39g2PVfpqXrIEduu7dcJgK007KgnX9tHNKA==" |
2394 | }, | 2394 | }, |
2395 | "vscode-test": { | 2395 | "vscode-test": { |
2396 | "version": "1.4.1", | 2396 | "version": "1.4.1", |
diff --git a/editors/code/package.json b/editors/code/package.json index 55825456e..d26c64a57 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -21,7 +21,7 @@ | |||
21 | "Programming Languages" | 21 | "Programming Languages" |
22 | ], | 22 | ], |
23 | "engines": { | 23 | "engines": { |
24 | "vscode": "^1.52.0" | 24 | "vscode": "^1.53.0" |
25 | }, | 25 | }, |
26 | "enableProposedApi": true, | 26 | "enableProposedApi": true, |
27 | "scripts": { | 27 | "scripts": { |
@@ -36,7 +36,7 @@ | |||
36 | }, | 36 | }, |
37 | "dependencies": { | 37 | "dependencies": { |
38 | "node-fetch": "^2.6.1", | 38 | "node-fetch": "^2.6.1", |
39 | "vscode-languageclient": "7.0.0" | 39 | "vscode-languageclient": "^7.1.0-next.1" |
40 | }, | 40 | }, |
41 | "devDependencies": { | 41 | "devDependencies": { |
42 | "@rollup/plugin-commonjs": "^17.0.0", | 42 | "@rollup/plugin-commonjs": "^17.0.0", |
@@ -45,7 +45,7 @@ | |||
45 | "@types/mocha": "^8.0.4", | 45 | "@types/mocha": "^8.0.4", |
46 | "@types/node": "~12.12.6", | 46 | "@types/node": "~12.12.6", |
47 | "@types/node-fetch": "^2.5.7", | 47 | "@types/node-fetch": "^2.5.7", |
48 | "@types/vscode": "^1.52.0", | 48 | "@types/vscode": "^1.53.0", |
49 | "@typescript-eslint/eslint-plugin": "^4.9.0", | 49 | "@typescript-eslint/eslint-plugin": "^4.9.0", |
50 | "@typescript-eslint/parser": "^4.9.0", | 50 | "@typescript-eslint/parser": "^4.9.0", |
51 | "eslint": "^7.15.0", | 51 | "eslint": "^7.15.0", |
@@ -707,7 +707,7 @@ | |||
707 | } | 707 | } |
708 | }, | 708 | }, |
709 | "rust-analyzer.rustcSource": { | 709 | "rust-analyzer.rustcSource": { |
710 | "markdownDescription": "Path to the rust compiler sources, for usage in rustc_private projects.", | 710 | "markdownDescription": "Path to the rust compiler sources, for usage in rustc_private projects, or \"discover\" to try to automatically find it.", |
711 | "default": null, | 711 | "default": null, |
712 | "type": [ | 712 | "type": [ |
713 | "null", | 713 | "null", |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index aec5c70c0..db5f4c023 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -79,7 +79,7 @@ export function createClient(serverPath: string, cwd: string, extraEnv: Env): lc | |||
79 | return hover; | 79 | return hover; |
80 | }, | 80 | }, |
81 | (error) => { | 81 | (error) => { |
82 | client.handleFailedRequest(lc.HoverRequest.type, error, null); | 82 | client.handleFailedRequest(lc.HoverRequest.type, token, error, null); |
83 | return Promise.resolve(null); | 83 | return Promise.resolve(null); |
84 | }); | 84 | }); |
85 | }, | 85 | }, |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index d18d6c8a9..620810d72 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -246,10 +246,10 @@ async function patchelf(dest: PathLike): Promise<void> { | |||
246 | }, | 246 | }, |
247 | async (progress, _) => { | 247 | async (progress, _) => { |
248 | const expression = ` | 248 | const expression = ` |
249 | {src, pkgs ? import <nixpkgs> {}}: | 249 | {srcStr, pkgs ? import <nixpkgs> {}}: |
250 | pkgs.stdenv.mkDerivation { | 250 | pkgs.stdenv.mkDerivation { |
251 | name = "rust-analyzer"; | 251 | name = "rust-analyzer"; |
252 | inherit src; | 252 | src = /. + srcStr; |
253 | phases = [ "installPhase" "fixupPhase" ]; | 253 | phases = [ "installPhase" "fixupPhase" ]; |
254 | installPhase = "cp $src $out"; | 254 | installPhase = "cp $src $out"; |
255 | fixupPhase = '' | 255 | fixupPhase = '' |
@@ -262,7 +262,7 @@ async function patchelf(dest: PathLike): Promise<void> { | |||
262 | await fs.rename(dest, origFile); | 262 | await fs.rename(dest, origFile); |
263 | progress.report({ message: "Patching executable", increment: 20 }); | 263 | progress.report({ message: "Patching executable", increment: 20 }); |
264 | await new Promise((resolve, reject) => { | 264 | await new Promise((resolve, reject) => { |
265 | const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`, | 265 | const handle = exec(`nix-build -E - --argstr srcStr '${origFile}' -o '${dest}'`, |
266 | (err, stdout, stderr) => { | 266 | (err, stdout, stderr) => { |
267 | if (err != null) { | 267 | if (err != null) { |
268 | reject(Error(stderr)); | 268 | reject(Error(stderr)); |