diff options
Diffstat (limited to 'crates')
306 files changed, 9122 insertions, 5700 deletions
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml index 3fd8327d6..ed8ad666f 100644 --- a/crates/assists/Cargo.toml +++ b/crates/assists/Cargo.toml | |||
@@ -11,7 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | rustc-hash = "1.1.0" | 13 | rustc-hash = "1.1.0" |
14 | itertools = "0.9.0" | 14 | itertools = "0.10.0" |
15 | either = "1.6.1" | 15 | either = "1.6.1" |
16 | 16 | ||
17 | stdx = { path = "../stdx", version = "0.0.0" } | 17 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/assists/src/assist_config.rs b/crates/assists/src/assist_config.rs index c458d9054..4fe8ea761 100644 --- a/crates/assists/src/assist_config.rs +++ b/crates/assists/src/assist_config.rs | |||
@@ -4,8 +4,7 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! assists if we are allowed to. | 5 | //! assists if we are allowed to. |
6 | 6 | ||
7 | use hir::PrefixKind; | 7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; |
8 | use ide_db::helpers::insert_use::MergeBehavior; | ||
9 | 8 | ||
10 | use crate::AssistKind; | 9 | use crate::AssistKind; |
11 | 10 | ||
@@ -16,35 +15,8 @@ pub struct AssistConfig { | |||
16 | pub insert_use: InsertUseConfig, | 15 | pub insert_use: InsertUseConfig, |
17 | } | 16 | } |
18 | 17 | ||
19 | impl AssistConfig { | ||
20 | pub fn allow_snippets(&mut self, yes: bool) { | ||
21 | self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None } | ||
22 | } | ||
23 | } | ||
24 | |||
25 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
26 | pub struct SnippetCap { | ||
27 | _private: (), | ||
28 | } | ||
29 | |||
30 | impl Default for AssistConfig { | ||
31 | fn default() -> Self { | ||
32 | AssistConfig { | ||
33 | snippet_cap: Some(SnippetCap { _private: () }), | ||
34 | allowed: None, | ||
35 | insert_use: InsertUseConfig::default(), | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 18 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
41 | pub struct InsertUseConfig { | 19 | pub struct InsertUseConfig { |
42 | pub merge: Option<MergeBehavior>, | 20 | pub merge: Option<MergeBehavior>, |
43 | pub prefix_kind: PrefixKind, | 21 | pub prefix_kind: hir::PrefixKind, |
44 | } | ||
45 | |||
46 | impl Default for InsertUseConfig { | ||
47 | fn default() -> Self { | ||
48 | InsertUseConfig { merge: Some(MergeBehavior::Full), prefix_kind: PrefixKind::Plain } | ||
49 | } | ||
50 | } | 22 | } |
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs index 4f59d39a9..91cc63427 100644 --- a/crates/assists/src/assist_context.rs +++ b/crates/assists/src/assist_context.rs | |||
@@ -4,7 +4,10 @@ use std::mem; | |||
4 | 4 | ||
5 | use algo::find_covering_element; | 5 | use algo::find_covering_element; |
6 | use hir::Semantics; | 6 | use hir::Semantics; |
7 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange}; | 7 | use ide_db::{ |
8 | base_db::{AnchoredPathBuf, FileId, FileRange}, | ||
9 | helpers::SnippetCap, | ||
10 | }; | ||
8 | use ide_db::{ | 11 | use ide_db::{ |
9 | label::Label, | 12 | label::Label, |
10 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, | 13 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
@@ -17,10 +20,7 @@ use syntax::{ | |||
17 | }; | 20 | }; |
18 | use text_edit::{TextEdit, TextEditBuilder}; | 21 | use text_edit::{TextEdit, TextEditBuilder}; |
19 | 22 | ||
20 | use crate::{ | 23 | use crate::{assist_config::AssistConfig, Assist, AssistId, AssistKind, GroupLabel}; |
21 | assist_config::{AssistConfig, SnippetCap}, | ||
22 | Assist, AssistId, AssistKind, GroupLabel, | ||
23 | }; | ||
24 | 24 | ||
25 | /// `AssistContext` allows to apply an assist or check if it could be applied. | 25 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
26 | /// | 26 | /// |
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs index da94e9987..4a3ed7783 100644 --- a/crates/assists/src/ast_transform.rs +++ b/crates/assists/src/ast_transform.rs | |||
@@ -204,7 +204,8 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> { | |||
204 | } | 204 | } |
205 | PathResolution::Local(_) | 205 | PathResolution::Local(_) |
206 | | PathResolution::TypeParam(_) | 206 | | PathResolution::TypeParam(_) |
207 | | PathResolution::SelfType(_) => None, | 207 | | PathResolution::SelfType(_) |
208 | | PathResolution::ConstParam(_) => None, | ||
208 | PathResolution::Macro(_) => None, | 209 | PathResolution::Macro(_) => None, |
209 | PathResolution::AssocItem(_) => None, | 210 | PathResolution::AssocItem(_) => None, |
210 | } | 211 | } |
diff --git a/crates/assists/src/handlers/add_explicit_type.rs b/crates/assists/src/handlers/add_explicit_type.rs index 563cbf505..cb1548cef 100644 --- a/crates/assists/src/handlers/add_explicit_type.rs +++ b/crates/assists/src/handlers/add_explicit_type.rs | |||
@@ -12,7 +12,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
12 | // | 12 | // |
13 | // ``` | 13 | // ``` |
14 | // fn main() { | 14 | // fn main() { |
15 | // let x<|> = 92; | 15 | // let x$0 = 92; |
16 | // } | 16 | // } |
17 | // ``` | 17 | // ``` |
18 | // -> | 18 | // -> |
@@ -81,21 +81,17 @@ mod tests { | |||
81 | 81 | ||
82 | #[test] | 82 | #[test] |
83 | fn add_explicit_type_target() { | 83 | fn add_explicit_type_target() { |
84 | check_assist_target(add_explicit_type, "fn f() { let a<|> = 1; }", "a"); | 84 | check_assist_target(add_explicit_type, "fn f() { let a$0 = 1; }", "a"); |
85 | } | 85 | } |
86 | 86 | ||
87 | #[test] | 87 | #[test] |
88 | fn add_explicit_type_works_for_simple_expr() { | 88 | fn add_explicit_type_works_for_simple_expr() { |
89 | check_assist(add_explicit_type, "fn f() { let a<|> = 1; }", "fn f() { let a: i32 = 1; }"); | 89 | check_assist(add_explicit_type, "fn f() { let a$0 = 1; }", "fn f() { let a: i32 = 1; }"); |
90 | } | 90 | } |
91 | 91 | ||
92 | #[test] | 92 | #[test] |
93 | fn add_explicit_type_works_for_underscore() { | 93 | fn add_explicit_type_works_for_underscore() { |
94 | check_assist( | 94 | check_assist(add_explicit_type, "fn f() { let a$0: _ = 1; }", "fn f() { let a: i32 = 1; }"); |
95 | add_explicit_type, | ||
96 | "fn f() { let a<|>: _ = 1; }", | ||
97 | "fn f() { let a: i32 = 1; }", | ||
98 | ); | ||
99 | } | 95 | } |
100 | 96 | ||
101 | #[test] | 97 | #[test] |
@@ -109,7 +105,7 @@ mod tests { | |||
109 | } | 105 | } |
110 | 106 | ||
111 | fn f() { | 107 | fn f() { |
112 | let a<|>: Option<_> = Option::Some(1); | 108 | let a$0: Option<_> = Option::Some(1); |
113 | }"#, | 109 | }"#, |
114 | r#" | 110 | r#" |
115 | enum Option<T> { | 111 | enum Option<T> { |
@@ -127,7 +123,7 @@ mod tests { | |||
127 | fn add_explicit_type_works_for_macro_call() { | 123 | fn add_explicit_type_works_for_macro_call() { |
128 | check_assist( | 124 | check_assist( |
129 | add_explicit_type, | 125 | add_explicit_type, |
130 | r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", | 126 | r"macro_rules! v { () => {0u64} } fn f() { let a$0 = v!(); }", |
131 | r"macro_rules! v { () => {0u64} } fn f() { let a: u64 = v!(); }", | 127 | r"macro_rules! v { () => {0u64} } fn f() { let a: u64 = v!(); }", |
132 | ); | 128 | ); |
133 | } | 129 | } |
@@ -136,31 +132,31 @@ mod tests { | |||
136 | fn add_explicit_type_works_for_macro_call_recursive() { | 132 | fn add_explicit_type_works_for_macro_call_recursive() { |
137 | check_assist( | 133 | check_assist( |
138 | add_explicit_type, | 134 | add_explicit_type, |
139 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }"#, | 135 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a$0 = v!(); }"#, |
140 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a: u64 = v!(); }"#, | 136 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a: u64 = v!(); }"#, |
141 | ); | 137 | ); |
142 | } | 138 | } |
143 | 139 | ||
144 | #[test] | 140 | #[test] |
145 | fn add_explicit_type_not_applicable_if_ty_not_inferred() { | 141 | fn add_explicit_type_not_applicable_if_ty_not_inferred() { |
146 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }"); | 142 | check_assist_not_applicable(add_explicit_type, "fn f() { let a$0 = None; }"); |
147 | } | 143 | } |
148 | 144 | ||
149 | #[test] | 145 | #[test] |
150 | fn add_explicit_type_not_applicable_if_ty_already_specified() { | 146 | fn add_explicit_type_not_applicable_if_ty_already_specified() { |
151 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: i32 = 1; }"); | 147 | check_assist_not_applicable(add_explicit_type, "fn f() { let a$0: i32 = 1; }"); |
152 | } | 148 | } |
153 | 149 | ||
154 | #[test] | 150 | #[test] |
155 | fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { | 151 | fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { |
156 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: (i32, i32) = (3, 4); }"); | 152 | check_assist_not_applicable(add_explicit_type, "fn f() { let a$0: (i32, i32) = (3, 4); }"); |
157 | } | 153 | } |
158 | 154 | ||
159 | #[test] | 155 | #[test] |
160 | fn add_explicit_type_not_applicable_if_cursor_after_equals() { | 156 | fn add_explicit_type_not_applicable_if_cursor_after_equals() { |
161 | check_assist_not_applicable( | 157 | check_assist_not_applicable( |
162 | add_explicit_type, | 158 | add_explicit_type, |
163 | "fn f() {let a =<|> match 1 {2 => 3, 3 => 5};}", | 159 | "fn f() {let a =$0 match 1 {2 => 3, 3 => 5};}", |
164 | ) | 160 | ) |
165 | } | 161 | } |
166 | 162 | ||
@@ -168,7 +164,7 @@ mod tests { | |||
168 | fn add_explicit_type_not_applicable_if_cursor_before_let() { | 164 | fn add_explicit_type_not_applicable_if_cursor_before_let() { |
169 | check_assist_not_applicable( | 165 | check_assist_not_applicable( |
170 | add_explicit_type, | 166 | add_explicit_type, |
171 | "fn f() <|>{let a = match 1 {2 => 3, 3 => 5};}", | 167 | "fn f() $0{let a = match 1 {2 => 3, 3 => 5};}", |
172 | ) | 168 | ) |
173 | } | 169 | } |
174 | 170 | ||
@@ -178,7 +174,7 @@ mod tests { | |||
178 | add_explicit_type, | 174 | add_explicit_type, |
179 | r#" | 175 | r#" |
180 | fn main() { | 176 | fn main() { |
181 | let multiply_by_two<|> = |i| i * 3; | 177 | let multiply_by_two$0 = |i| i * 3; |
182 | let six = multiply_by_two(2); | 178 | let six = multiply_by_two(2); |
183 | }"#, | 179 | }"#, |
184 | ) | 180 | ) |
@@ -195,7 +191,7 @@ struct Test<K, T = u8> { | |||
195 | } | 191 | } |
196 | 192 | ||
197 | fn main() { | 193 | fn main() { |
198 | let test<|> = Test { t: 23u8, k: 33 }; | 194 | let test$0 = Test { t: 23u8, k: 33 }; |
199 | }"#, | 195 | }"#, |
200 | r#" | 196 | r#" |
201 | struct Test<K, T = u8> { | 197 | struct Test<K, T = u8> { |
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs index 7df05b841..63cea754d 100644 --- a/crates/assists/src/handlers/add_missing_impl_members.rs +++ b/crates/assists/src/handlers/add_missing_impl_members.rs | |||
@@ -20,7 +20,7 @@ use crate::{ | |||
20 | // fn bar(&self) {} | 20 | // fn bar(&self) {} |
21 | // } | 21 | // } |
22 | // | 22 | // |
23 | // impl Trait<u32> for () {<|> | 23 | // impl Trait<u32> for () {$0 |
24 | // | 24 | // |
25 | // } | 25 | // } |
26 | // ``` | 26 | // ``` |
@@ -63,7 +63,7 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) - | |||
63 | // | 63 | // |
64 | // impl Trait for () { | 64 | // impl Trait for () { |
65 | // type X = (); | 65 | // type X = (); |
66 | // fn foo(&self) {}<|> | 66 | // fn foo(&self) {}$0 |
67 | // | 67 | // |
68 | // } | 68 | // } |
69 | // ``` | 69 | // ``` |
@@ -166,7 +166,7 @@ struct S; | |||
166 | 166 | ||
167 | impl Foo for S { | 167 | impl Foo for S { |
168 | fn bar(&self) {} | 168 | fn bar(&self) {} |
169 | <|> | 169 | $0 |
170 | }"#, | 170 | }"#, |
171 | r#" | 171 | r#" |
172 | trait Foo { | 172 | trait Foo { |
@@ -214,7 +214,7 @@ struct S; | |||
214 | 214 | ||
215 | impl Foo for S { | 215 | impl Foo for S { |
216 | fn bar(&self) {} | 216 | fn bar(&self) {} |
217 | <|> | 217 | $0 |
218 | }"#, | 218 | }"#, |
219 | r#" | 219 | r#" |
220 | trait Foo { | 220 | trait Foo { |
@@ -242,7 +242,7 @@ impl Foo for S { | |||
242 | r#" | 242 | r#" |
243 | trait Foo { fn foo(&self); } | 243 | trait Foo { fn foo(&self); } |
244 | struct S; | 244 | struct S; |
245 | impl Foo for S { <|> }"#, | 245 | impl Foo for S { $0 }"#, |
246 | r#" | 246 | r#" |
247 | trait Foo { fn foo(&self); } | 247 | trait Foo { fn foo(&self); } |
248 | struct S; | 248 | struct S; |
@@ -261,7 +261,7 @@ impl Foo for S { | |||
261 | r#" | 261 | r#" |
262 | trait Foo { fn foo(&self); } | 262 | trait Foo { fn foo(&self); } |
263 | struct S; | 263 | struct S; |
264 | impl Foo for S<|>"#, | 264 | impl Foo for S$0"#, |
265 | r#" | 265 | r#" |
266 | trait Foo { fn foo(&self); } | 266 | trait Foo { fn foo(&self); } |
267 | struct S; | 267 | struct S; |
@@ -280,7 +280,7 @@ impl Foo for S { | |||
280 | r#" | 280 | r#" |
281 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 281 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
282 | struct S; | 282 | struct S; |
283 | impl Foo<u32> for S { <|> }"#, | 283 | impl Foo<u32> for S { $0 }"#, |
284 | r#" | 284 | r#" |
285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
286 | struct S; | 286 | struct S; |
@@ -299,7 +299,7 @@ impl Foo<u32> for S { | |||
299 | r#" | 299 | r#" |
300 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 300 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
301 | struct S; | 301 | struct S; |
302 | impl<U> Foo<U> for S { <|> }"#, | 302 | impl<U> Foo<U> for S { $0 }"#, |
303 | r#" | 303 | r#" |
304 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 304 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
305 | struct S; | 305 | struct S; |
@@ -318,7 +318,7 @@ impl<U> Foo<U> for S { | |||
318 | r#" | 318 | r#" |
319 | trait Foo { fn foo(&self); } | 319 | trait Foo { fn foo(&self); } |
320 | struct S; | 320 | struct S; |
321 | impl Foo for S {}<|>"#, | 321 | impl Foo for S {}$0"#, |
322 | r#" | 322 | r#" |
323 | trait Foo { fn foo(&self); } | 323 | trait Foo { fn foo(&self); } |
324 | struct S; | 324 | struct S; |
@@ -340,7 +340,7 @@ mod foo { | |||
340 | trait Foo { fn foo(&self, bar: Bar); } | 340 | trait Foo { fn foo(&self, bar: Bar); } |
341 | } | 341 | } |
342 | struct S; | 342 | struct S; |
343 | impl foo::Foo for S { <|> }"#, | 343 | impl foo::Foo for S { $0 }"#, |
344 | r#" | 344 | r#" |
345 | mod foo { | 345 | mod foo { |
346 | pub struct Bar; | 346 | pub struct Bar; |
@@ -370,7 +370,7 @@ mod foo { | |||
370 | use foo::bar; | 370 | use foo::bar; |
371 | 371 | ||
372 | struct S; | 372 | struct S; |
373 | impl bar::Foo for S { <|> }"#, | 373 | impl bar::Foo for S { $0 }"#, |
374 | r#" | 374 | r#" |
375 | mod foo { | 375 | mod foo { |
376 | pub mod bar { | 376 | pub mod bar { |
@@ -400,7 +400,7 @@ mod foo { | |||
400 | trait Foo { fn foo(&self, bar: Bar<u32>); } | 400 | trait Foo { fn foo(&self, bar: Bar<u32>); } |
401 | } | 401 | } |
402 | struct S; | 402 | struct S; |
403 | impl foo::Foo for S { <|> }"#, | 403 | impl foo::Foo for S { $0 }"#, |
404 | r#" | 404 | r#" |
405 | mod foo { | 405 | mod foo { |
406 | pub struct Bar<T>; | 406 | pub struct Bar<T>; |
@@ -425,7 +425,7 @@ mod foo { | |||
425 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } | 425 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } |
426 | } | 426 | } |
427 | struct S; | 427 | struct S; |
428 | impl foo::Foo<u32> for S { <|> }"#, | 428 | impl foo::Foo<u32> for S { $0 }"#, |
429 | r#" | 429 | r#" |
430 | mod foo { | 430 | mod foo { |
431 | pub struct Bar<T>; | 431 | pub struct Bar<T>; |
@@ -452,7 +452,7 @@ mod foo { | |||
452 | } | 452 | } |
453 | struct Param; | 453 | struct Param; |
454 | struct S; | 454 | struct S; |
455 | impl foo::Foo<Param> for S { <|> }"#, | 455 | impl foo::Foo<Param> for S { $0 }"#, |
456 | r#" | 456 | r#" |
457 | mod foo { | 457 | mod foo { |
458 | trait Foo<T> { fn foo(&self, bar: T); } | 458 | trait Foo<T> { fn foo(&self, bar: T); } |
@@ -479,7 +479,7 @@ mod foo { | |||
479 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } | 479 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } |
480 | } | 480 | } |
481 | struct S; | 481 | struct S; |
482 | impl foo::Foo for S { <|> }"#, | 482 | impl foo::Foo for S { $0 }"#, |
483 | r#" | 483 | r#" |
484 | mod foo { | 484 | mod foo { |
485 | pub struct Bar<T>; | 485 | pub struct Bar<T>; |
@@ -506,7 +506,7 @@ mod foo { | |||
506 | trait Foo { fn foo(&self, bar: Bar<Baz>); } | 506 | trait Foo { fn foo(&self, bar: Bar<Baz>); } |
507 | } | 507 | } |
508 | struct S; | 508 | struct S; |
509 | impl foo::Foo for S { <|> }"#, | 509 | impl foo::Foo for S { $0 }"#, |
510 | r#" | 510 | r#" |
511 | mod foo { | 511 | mod foo { |
512 | pub struct Bar<T>; | 512 | pub struct Bar<T>; |
@@ -532,7 +532,7 @@ mod foo { | |||
532 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } | 532 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } |
533 | } | 533 | } |
534 | struct S; | 534 | struct S; |
535 | impl foo::Foo for S { <|> }"#, | 535 | impl foo::Foo for S { $0 }"#, |
536 | r#" | 536 | r#" |
537 | mod foo { | 537 | mod foo { |
538 | pub trait Fn<Args> { type Output; } | 538 | pub trait Fn<Args> { type Output; } |
@@ -554,7 +554,7 @@ impl foo::Foo for S { | |||
554 | r#" | 554 | r#" |
555 | trait Foo; | 555 | trait Foo; |
556 | struct S; | 556 | struct S; |
557 | impl Foo for S { <|> }"#, | 557 | impl Foo for S { $0 }"#, |
558 | ) | 558 | ) |
559 | } | 559 | } |
560 | 560 | ||
@@ -568,7 +568,7 @@ trait Foo { | |||
568 | fn valid(some: u32) -> bool { false } | 568 | fn valid(some: u32) -> bool { false } |
569 | } | 569 | } |
570 | struct S; | 570 | struct S; |
571 | impl Foo for S { <|> }"#, | 571 | impl Foo for S { $0 }"#, |
572 | ) | 572 | ) |
573 | } | 573 | } |
574 | 574 | ||
@@ -586,7 +586,7 @@ trait Foo { | |||
586 | fn foo(&self); | 586 | fn foo(&self); |
587 | } | 587 | } |
588 | struct S; | 588 | struct S; |
589 | impl Foo for S {}<|>"#, | 589 | impl Foo for S {}$0"#, |
590 | r#" | 590 | r#" |
591 | #[doc(alias = "test alias")] | 591 | #[doc(alias = "test alias")] |
592 | trait Foo { | 592 | trait Foo { |
@@ -621,7 +621,7 @@ trait Foo { | |||
621 | fn foo(some: u32) -> bool; | 621 | fn foo(some: u32) -> bool; |
622 | } | 622 | } |
623 | struct S; | 623 | struct S; |
624 | impl Foo for S { <|> }"#, | 624 | impl Foo for S { $0 }"#, |
625 | r#" | 625 | r#" |
626 | trait Foo { | 626 | trait Foo { |
627 | type Output; | 627 | type Output; |
@@ -648,7 +648,7 @@ trait Foo<T = Self> { | |||
648 | } | 648 | } |
649 | 649 | ||
650 | struct S; | 650 | struct S; |
651 | impl Foo for S { <|> }"#, | 651 | impl Foo for S { $0 }"#, |
652 | r#" | 652 | r#" |
653 | trait Foo<T = Self> { | 653 | trait Foo<T = Self> { |
654 | fn bar(&self, other: &T); | 654 | fn bar(&self, other: &T); |
@@ -673,7 +673,7 @@ trait Foo<T1, T2 = Self> { | |||
673 | } | 673 | } |
674 | 674 | ||
675 | struct S<T>; | 675 | struct S<T>; |
676 | impl Foo<T> for S<T> { <|> }"#, | 676 | impl Foo<T> for S<T> { $0 }"#, |
677 | r#" | 677 | r#" |
678 | trait Foo<T1, T2 = Self> { | 678 | trait Foo<T1, T2 = Self> { |
679 | fn bar(&self, this: &T1, that: &T2); | 679 | fn bar(&self, this: &T1, that: &T2); |
@@ -697,7 +697,7 @@ trait Tr { | |||
697 | type Ty: Copy + 'static; | 697 | type Ty: Copy + 'static; |
698 | } | 698 | } |
699 | 699 | ||
700 | impl Tr for ()<|> { | 700 | impl Tr for ()$0 { |
701 | }"#, | 701 | }"#, |
702 | r#" | 702 | r#" |
703 | trait Tr { | 703 | trait Tr { |
@@ -719,7 +719,7 @@ trait Tr { | |||
719 | fn foo(); | 719 | fn foo(); |
720 | } | 720 | } |
721 | 721 | ||
722 | impl Tr for ()<|> { | 722 | impl Tr for ()$0 { |
723 | +++ | 723 | +++ |
724 | }"#, | 724 | }"#, |
725 | r#" | 725 | r#" |
@@ -745,7 +745,7 @@ trait Tr { | |||
745 | fn foo(); | 745 | fn foo(); |
746 | } | 746 | } |
747 | 747 | ||
748 | impl Tr for ()<|> { | 748 | impl Tr for ()$0 { |
749 | // very important | 749 | // very important |
750 | }"#, | 750 | }"#, |
751 | r#" | 751 | r#" |
@@ -771,7 +771,7 @@ trait Test { | |||
771 | fn foo(&self, x: crate) | 771 | fn foo(&self, x: crate) |
772 | } | 772 | } |
773 | impl Test for () { | 773 | impl Test for () { |
774 | <|> | 774 | $0 |
775 | } | 775 | } |
776 | "#, | 776 | "#, |
777 | r#" | 777 | r#" |
@@ -796,7 +796,7 @@ trait Foo<BAR> { | |||
796 | fn foo(&self, bar: BAR); | 796 | fn foo(&self, bar: BAR); |
797 | } | 797 | } |
798 | impl Foo for () { | 798 | impl Foo for () { |
799 | <|> | 799 | $0 |
800 | } | 800 | } |
801 | "#, | 801 | "#, |
802 | r#" | 802 | r#" |
diff --git a/crates/assists/src/handlers/add_turbo_fish.rs b/crates/assists/src/handlers/add_turbo_fish.rs index 1f486c013..8e9ea4fad 100644 --- a/crates/assists/src/handlers/add_turbo_fish.rs +++ b/crates/assists/src/handlers/add_turbo_fish.rs | |||
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | // ``` | 14 | // ``` |
15 | // fn make<T>() -> T { todo!() } | 15 | // fn make<T>() -> T { todo!() } |
16 | // fn main() { | 16 | // fn main() { |
17 | // let x = make<|>(); | 17 | // let x = make$0(); |
18 | // } | 18 | // } |
19 | // ``` | 19 | // ``` |
20 | // -> | 20 | // -> |
@@ -77,7 +77,7 @@ mod tests { | |||
77 | r#" | 77 | r#" |
78 | fn make<T>() -> T {} | 78 | fn make<T>() -> T {} |
79 | fn main() { | 79 | fn main() { |
80 | make<|>(); | 80 | make$0(); |
81 | } | 81 | } |
82 | "#, | 82 | "#, |
83 | r#" | 83 | r#" |
@@ -97,7 +97,7 @@ fn main() { | |||
97 | r#" | 97 | r#" |
98 | fn make<T>() -> T {} | 98 | fn make<T>() -> T {} |
99 | fn main() { | 99 | fn main() { |
100 | make()<|>; | 100 | make()$0; |
101 | } | 101 | } |
102 | "#, | 102 | "#, |
103 | r#" | 103 | r#" |
@@ -119,7 +119,7 @@ impl S { | |||
119 | fn make<T>(&self) -> T {} | 119 | fn make<T>(&self) -> T {} |
120 | } | 120 | } |
121 | fn main() { | 121 | fn main() { |
122 | S.make<|>(); | 122 | S.make$0(); |
123 | } | 123 | } |
124 | "#, | 124 | "#, |
125 | r#" | 125 | r#" |
@@ -142,7 +142,7 @@ fn main() { | |||
142 | r#" | 142 | r#" |
143 | fn make<T>() -> T {} | 143 | fn make<T>() -> T {} |
144 | fn main() { | 144 | fn main() { |
145 | make<|>::<()>(); | 145 | make$0::<()>(); |
146 | } | 146 | } |
147 | "#, | 147 | "#, |
148 | ); | 148 | ); |
@@ -156,7 +156,7 @@ fn main() { | |||
156 | r#" | 156 | r#" |
157 | fn make() -> () {} | 157 | fn make() -> () {} |
158 | fn main() { | 158 | fn main() { |
159 | make<|>(); | 159 | make$0(); |
160 | } | 160 | } |
161 | "#, | 161 | "#, |
162 | ); | 162 | ); |
diff --git a/crates/assists/src/handlers/apply_demorgan.rs b/crates/assists/src/handlers/apply_demorgan.rs index 1a6fdafda..ed4d11455 100644 --- a/crates/assists/src/handlers/apply_demorgan.rs +++ b/crates/assists/src/handlers/apply_demorgan.rs | |||
@@ -12,7 +12,7 @@ use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKin | |||
12 | // | 12 | // |
13 | // ``` | 13 | // ``` |
14 | // fn main() { | 14 | // fn main() { |
15 | // if x != 4 ||<|> !y {} | 15 | // if x != 4 ||$0 !y {} |
16 | // } | 16 | // } |
17 | // ``` | 17 | // ``` |
18 | // -> | 18 | // -> |
@@ -68,26 +68,26 @@ mod tests { | |||
68 | 68 | ||
69 | #[test] | 69 | #[test] |
70 | fn demorgan_turns_and_into_or() { | 70 | fn demorgan_turns_and_into_or() { |
71 | check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x || x) }") | 71 | check_assist(apply_demorgan, "fn f() { !x &&$0 !x }", "fn f() { !(x || x) }") |
72 | } | 72 | } |
73 | 73 | ||
74 | #[test] | 74 | #[test] |
75 | fn demorgan_turns_or_into_and() { | 75 | fn demorgan_turns_or_into_and() { |
76 | check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x && x) }") | 76 | check_assist(apply_demorgan, "fn f() { !x ||$0 !x }", "fn f() { !(x && x) }") |
77 | } | 77 | } |
78 | 78 | ||
79 | #[test] | 79 | #[test] |
80 | fn demorgan_removes_inequality() { | 80 | fn demorgan_removes_inequality() { |
81 | check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x && x) }") | 81 | check_assist(apply_demorgan, "fn f() { x != x ||$0 !x }", "fn f() { !(x == x && x) }") |
82 | } | 82 | } |
83 | 83 | ||
84 | #[test] | 84 | #[test] |
85 | fn demorgan_general_case() { | 85 | fn demorgan_general_case() { |
86 | check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x && !x) }") | 86 | check_assist(apply_demorgan, "fn f() { x ||$0 x }", "fn f() { !(!x && !x) }") |
87 | } | 87 | } |
88 | 88 | ||
89 | #[test] | 89 | #[test] |
90 | fn demorgan_doesnt_apply_with_cursor_not_on_op() { | 90 | fn demorgan_doesnt_apply_with_cursor_not_on_op() { |
91 | check_assist_not_applicable(apply_demorgan, "fn f() { <|> !x || !x }") | 91 | check_assist_not_applicable(apply_demorgan, "fn f() { $0 !x || !x }") |
92 | } | 92 | } |
93 | } | 93 | } |
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index bd5bba646..55620f0f3 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -70,7 +70,7 @@ use crate::{ | |||
70 | // | 70 | // |
71 | // ``` | 71 | // ``` |
72 | // fn main() { | 72 | // fn main() { |
73 | // let map = HashMap<|>::new(); | 73 | // let map = HashMap$0::new(); |
74 | // } | 74 | // } |
75 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | 75 | // # pub mod std { pub mod collections { pub struct HashMap { } } } |
76 | // ``` | 76 | // ``` |
@@ -151,7 +151,7 @@ mod tests { | |||
151 | 151 | ||
152 | use std::fmt; | 152 | use std::fmt; |
153 | 153 | ||
154 | <|>Formatter | 154 | $0Formatter |
155 | ", | 155 | ", |
156 | r" | 156 | r" |
157 | mod std { | 157 | mod std { |
@@ -172,7 +172,7 @@ mod tests { | |||
172 | check_assist( | 172 | check_assist( |
173 | auto_import, | 173 | auto_import, |
174 | r" | 174 | r" |
175 | <|>PubStruct | 175 | $0PubStruct |
176 | 176 | ||
177 | pub mod PubMod { | 177 | pub mod PubMod { |
178 | pub struct PubStruct; | 178 | pub struct PubStruct; |
@@ -198,7 +198,7 @@ mod tests { | |||
198 | macro_rules! foo { | 198 | macro_rules! foo { |
199 | ($i:ident) => { fn foo(a: $i) {} } | 199 | ($i:ident) => { fn foo(a: $i) {} } |
200 | } | 200 | } |
201 | foo!(Pub<|>Struct); | 201 | foo!(Pub$0Struct); |
202 | 202 | ||
203 | pub mod PubMod { | 203 | pub mod PubMod { |
204 | pub struct PubStruct; | 204 | pub struct PubStruct; |
@@ -227,7 +227,7 @@ mod tests { | |||
227 | use PubMod::PubStruct1; | 227 | use PubMod::PubStruct1; |
228 | 228 | ||
229 | struct Test { | 229 | struct Test { |
230 | test: Pub<|>Struct2<u8>, | 230 | test: Pub$0Struct2<u8>, |
231 | } | 231 | } |
232 | 232 | ||
233 | pub mod PubMod { | 233 | pub mod PubMod { |
@@ -259,7 +259,7 @@ mod tests { | |||
259 | check_assist( | 259 | check_assist( |
260 | auto_import, | 260 | auto_import, |
261 | r" | 261 | r" |
262 | PubSt<|>ruct | 262 | PubSt$0ruct |
263 | 263 | ||
264 | pub mod PubMod1 { | 264 | pub mod PubMod1 { |
265 | pub struct PubStruct; | 265 | pub struct PubStruct; |
@@ -296,7 +296,7 @@ mod tests { | |||
296 | r" | 296 | r" |
297 | use PubMod::PubStruct; | 297 | use PubMod::PubStruct; |
298 | 298 | ||
299 | PubStruct<|> | 299 | PubStruct$0 |
300 | 300 | ||
301 | pub mod PubMod { | 301 | pub mod PubMod { |
302 | pub struct PubStruct; | 302 | pub struct PubStruct; |
@@ -310,7 +310,7 @@ mod tests { | |||
310 | check_assist_not_applicable( | 310 | check_assist_not_applicable( |
311 | auto_import, | 311 | auto_import, |
312 | r" | 312 | r" |
313 | PrivateStruct<|> | 313 | PrivateStruct$0 |
314 | 314 | ||
315 | pub mod PubMod { | 315 | pub mod PubMod { |
316 | struct PrivateStruct; | 316 | struct PrivateStruct; |
@@ -324,7 +324,7 @@ mod tests { | |||
324 | check_assist_not_applicable( | 324 | check_assist_not_applicable( |
325 | auto_import, | 325 | auto_import, |
326 | " | 326 | " |
327 | PubStruct<|>", | 327 | PubStruct$0", |
328 | ); | 328 | ); |
329 | } | 329 | } |
330 | 330 | ||
@@ -333,7 +333,7 @@ mod tests { | |||
333 | check_assist_not_applicable( | 333 | check_assist_not_applicable( |
334 | auto_import, | 334 | auto_import, |
335 | r" | 335 | r" |
336 | use PubStruct<|>; | 336 | use PubStruct$0; |
337 | 337 | ||
338 | pub mod PubMod { | 338 | pub mod PubMod { |
339 | pub struct PubStruct; | 339 | pub struct PubStruct; |
@@ -346,7 +346,7 @@ mod tests { | |||
346 | check_assist( | 346 | check_assist( |
347 | auto_import, | 347 | auto_import, |
348 | r" | 348 | r" |
349 | test_function<|> | 349 | test_function$0 |
350 | 350 | ||
351 | pub mod PubMod { | 351 | pub mod PubMod { |
352 | pub fn test_function() {}; | 352 | pub fn test_function() {}; |
@@ -377,7 +377,7 @@ macro_rules! foo { | |||
377 | 377 | ||
378 | //- /main.rs crate:main deps:crate_with_macro | 378 | //- /main.rs crate:main deps:crate_with_macro |
379 | fn main() { | 379 | fn main() { |
380 | foo<|> | 380 | foo$0 |
381 | } | 381 | } |
382 | ", | 382 | ", |
383 | r"use crate_with_macro::foo; | 383 | r"use crate_with_macro::foo; |
@@ -395,7 +395,7 @@ fn main() { | |||
395 | auto_import, | 395 | auto_import, |
396 | r" | 396 | r" |
397 | struct AssistInfo { | 397 | struct AssistInfo { |
398 | group_label: Option<<|>GroupLabel>, | 398 | group_label: Option<$0GroupLabel>, |
399 | } | 399 | } |
400 | 400 | ||
401 | mod m { pub struct GroupLabel; } | 401 | mod m { pub struct GroupLabel; } |
@@ -419,7 +419,7 @@ fn main() { | |||
419 | 419 | ||
420 | use mod1::mod2; | 420 | use mod1::mod2; |
421 | fn main() { | 421 | fn main() { |
422 | mod2::mod3::TestStruct<|> | 422 | mod2::mod3::TestStruct$0 |
423 | } | 423 | } |
424 | ", | 424 | ", |
425 | ); | 425 | ); |
@@ -436,7 +436,7 @@ fn main() { | |||
436 | 436 | ||
437 | use test_mod::test_function; | 437 | use test_mod::test_function; |
438 | fn main() { | 438 | fn main() { |
439 | test_function<|> | 439 | test_function$0 |
440 | } | 440 | } |
441 | ", | 441 | ", |
442 | ); | 442 | ); |
@@ -455,7 +455,7 @@ fn main() { | |||
455 | } | 455 | } |
456 | 456 | ||
457 | fn main() { | 457 | fn main() { |
458 | TestStruct::test_function<|> | 458 | TestStruct::test_function$0 |
459 | } | 459 | } |
460 | ", | 460 | ", |
461 | r" | 461 | r" |
@@ -488,7 +488,7 @@ fn main() { | |||
488 | } | 488 | } |
489 | 489 | ||
490 | fn main() { | 490 | fn main() { |
491 | TestStruct::TEST_CONST<|> | 491 | TestStruct::TEST_CONST$0 |
492 | } | 492 | } |
493 | ", | 493 | ", |
494 | r" | 494 | r" |
@@ -524,7 +524,7 @@ fn main() { | |||
524 | } | 524 | } |
525 | 525 | ||
526 | fn main() { | 526 | fn main() { |
527 | test_mod::TestStruct::test_function<|> | 527 | test_mod::TestStruct::test_function$0 |
528 | } | 528 | } |
529 | ", | 529 | ", |
530 | r" | 530 | r" |
@@ -573,7 +573,7 @@ fn main() { | |||
573 | 573 | ||
574 | use test_mod::TestTrait2; | 574 | use test_mod::TestTrait2; |
575 | fn main() { | 575 | fn main() { |
576 | test_mod::TestEnum::test_function<|>; | 576 | test_mod::TestEnum::test_function$0; |
577 | } | 577 | } |
578 | ", | 578 | ", |
579 | ) | 579 | ) |
@@ -595,7 +595,7 @@ fn main() { | |||
595 | } | 595 | } |
596 | 596 | ||
597 | fn main() { | 597 | fn main() { |
598 | test_mod::TestStruct::TEST_CONST<|> | 598 | test_mod::TestStruct::TEST_CONST$0 |
599 | } | 599 | } |
600 | ", | 600 | ", |
601 | r" | 601 | r" |
@@ -644,7 +644,7 @@ fn main() { | |||
644 | 644 | ||
645 | use test_mod::TestTrait2; | 645 | use test_mod::TestTrait2; |
646 | fn main() { | 646 | fn main() { |
647 | test_mod::TestEnum::TEST_CONST<|>; | 647 | test_mod::TestEnum::TEST_CONST$0; |
648 | } | 648 | } |
649 | ", | 649 | ", |
650 | ) | 650 | ) |
@@ -667,7 +667,7 @@ fn main() { | |||
667 | 667 | ||
668 | fn main() { | 668 | fn main() { |
669 | let test_struct = test_mod::TestStruct {}; | 669 | let test_struct = test_mod::TestStruct {}; |
670 | test_struct.test_meth<|>od() | 670 | test_struct.test_meth$0od() |
671 | } | 671 | } |
672 | ", | 672 | ", |
673 | r" | 673 | r" |
@@ -699,7 +699,7 @@ fn main() { | |||
699 | //- /main.rs crate:main deps:dep | 699 | //- /main.rs crate:main deps:dep |
700 | fn main() { | 700 | fn main() { |
701 | let test_struct = dep::test_mod::TestStruct {}; | 701 | let test_struct = dep::test_mod::TestStruct {}; |
702 | test_struct.test_meth<|>od() | 702 | test_struct.test_meth$0od() |
703 | } | 703 | } |
704 | //- /dep.rs crate:dep | 704 | //- /dep.rs crate:dep |
705 | pub mod test_mod { | 705 | pub mod test_mod { |
@@ -730,7 +730,7 @@ fn main() { | |||
730 | r" | 730 | r" |
731 | //- /main.rs crate:main deps:dep | 731 | //- /main.rs crate:main deps:dep |
732 | fn main() { | 732 | fn main() { |
733 | dep::test_mod::TestStruct::test_func<|>tion | 733 | dep::test_mod::TestStruct::test_func$0tion |
734 | } | 734 | } |
735 | //- /dep.rs crate:dep | 735 | //- /dep.rs crate:dep |
736 | pub mod test_mod { | 736 | pub mod test_mod { |
@@ -760,7 +760,7 @@ fn main() { | |||
760 | r" | 760 | r" |
761 | //- /main.rs crate:main deps:dep | 761 | //- /main.rs crate:main deps:dep |
762 | fn main() { | 762 | fn main() { |
763 | dep::test_mod::TestStruct::CONST<|> | 763 | dep::test_mod::TestStruct::CONST$0 |
764 | } | 764 | } |
765 | //- /dep.rs crate:dep | 765 | //- /dep.rs crate:dep |
766 | pub mod test_mod { | 766 | pub mod test_mod { |
@@ -791,7 +791,7 @@ fn main() { | |||
791 | //- /main.rs crate:main deps:dep | 791 | //- /main.rs crate:main deps:dep |
792 | fn main() { | 792 | fn main() { |
793 | let test_struct = dep::test_mod::TestStruct {}; | 793 | let test_struct = dep::test_mod::TestStruct {}; |
794 | test_struct.test_func<|>tion() | 794 | test_struct.test_func$0tion() |
795 | } | 795 | } |
796 | //- /dep.rs crate:dep | 796 | //- /dep.rs crate:dep |
797 | pub mod test_mod { | 797 | pub mod test_mod { |
@@ -815,7 +815,7 @@ fn main() { | |||
815 | //- /main.rs crate:main deps:dep | 815 | //- /main.rs crate:main deps:dep |
816 | fn main() { | 816 | fn main() { |
817 | let test_struct = dep::test_mod::TestStruct {}; | 817 | let test_struct = dep::test_mod::TestStruct {}; |
818 | test_struct.test_meth<|>od() | 818 | test_struct.test_meth$0od() |
819 | } | 819 | } |
820 | //- /dep.rs crate:dep | 820 | //- /dep.rs crate:dep |
821 | pub mod test_mod { | 821 | pub mod test_mod { |
@@ -858,7 +858,7 @@ fn main() { | |||
858 | use test_mod::TestTrait2; | 858 | use test_mod::TestTrait2; |
859 | fn main() { | 859 | fn main() { |
860 | let one = test_mod::TestEnum::One; | 860 | let one = test_mod::TestEnum::One; |
861 | one.test<|>_method(); | 861 | one.test$0_method(); |
862 | } | 862 | } |
863 | ", | 863 | ", |
864 | ) | 864 | ) |
@@ -874,7 +874,7 @@ pub struct Struct; | |||
874 | 874 | ||
875 | //- /main.rs crate:main deps:dep | 875 | //- /main.rs crate:main deps:dep |
876 | fn main() { | 876 | fn main() { |
877 | Struct<|> | 877 | Struct$0 |
878 | } | 878 | } |
879 | ", | 879 | ", |
880 | r"use dep::Struct; | 880 | r"use dep::Struct; |
@@ -902,7 +902,7 @@ pub fn panic_fmt() {} | |||
902 | //- /main.rs crate:main deps:dep | 902 | //- /main.rs crate:main deps:dep |
903 | struct S; | 903 | struct S; |
904 | 904 | ||
905 | impl f<|>mt::Display for S {} | 905 | impl f$0mt::Display for S {} |
906 | ", | 906 | ", |
907 | r"use dep::fmt; | 907 | r"use dep::fmt; |
908 | 908 | ||
@@ -930,7 +930,7 @@ mac!(); | |||
930 | 930 | ||
931 | //- /main.rs crate:main deps:dep | 931 | //- /main.rs crate:main deps:dep |
932 | fn main() { | 932 | fn main() { |
933 | Cheese<|>; | 933 | Cheese$0; |
934 | } | 934 | } |
935 | ", | 935 | ", |
936 | r"use dep::Cheese; | 936 | r"use dep::Cheese; |
@@ -954,7 +954,7 @@ pub struct fmt; | |||
954 | 954 | ||
955 | //- /main.rs crate:main deps:dep | 955 | //- /main.rs crate:main deps:dep |
956 | fn main() { | 956 | fn main() { |
957 | FMT<|>; | 957 | FMT$0; |
958 | } | 958 | } |
959 | ", | 959 | ", |
960 | r"use dep::FMT; | 960 | r"use dep::FMT; |
diff --git a/crates/assists/src/handlers/change_visibility.rs b/crates/assists/src/handlers/change_visibility.rs index 22d7c95d9..ac8c44124 100644 --- a/crates/assists/src/handlers/change_visibility.rs +++ b/crates/assists/src/handlers/change_visibility.rs | |||
@@ -13,7 +13,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; | |||
13 | // Adds or changes existing visibility specifier. | 13 | // Adds or changes existing visibility specifier. |
14 | // | 14 | // |
15 | // ``` | 15 | // ``` |
16 | // <|>fn frobnicate() {} | 16 | // $0fn frobnicate() {} |
17 | // ``` | 17 | // ``` |
18 | // -> | 18 | // -> |
19 | // ``` | 19 | // ``` |
@@ -118,23 +118,23 @@ mod tests { | |||
118 | 118 | ||
119 | #[test] | 119 | #[test] |
120 | fn change_visibility_adds_pub_crate_to_items() { | 120 | fn change_visibility_adds_pub_crate_to_items() { |
121 | check_assist(change_visibility, "<|>fn foo() {}", "pub(crate) fn foo() {}"); | 121 | check_assist(change_visibility, "$0fn foo() {}", "pub(crate) fn foo() {}"); |
122 | check_assist(change_visibility, "f<|>n foo() {}", "pub(crate) fn foo() {}"); | 122 | check_assist(change_visibility, "f$0n foo() {}", "pub(crate) fn foo() {}"); |
123 | check_assist(change_visibility, "<|>struct Foo {}", "pub(crate) struct Foo {}"); | 123 | check_assist(change_visibility, "$0struct Foo {}", "pub(crate) struct Foo {}"); |
124 | check_assist(change_visibility, "<|>mod foo {}", "pub(crate) mod foo {}"); | 124 | check_assist(change_visibility, "$0mod foo {}", "pub(crate) mod foo {}"); |
125 | check_assist(change_visibility, "<|>trait Foo {}", "pub(crate) trait Foo {}"); | 125 | check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}"); |
126 | check_assist(change_visibility, "m<|>od {}", "pub(crate) mod {}"); | 126 | check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}"); |
127 | check_assist(change_visibility, "unsafe f<|>n foo() {}", "pub(crate) unsafe fn foo() {}"); | 127 | check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}"); |
128 | } | 128 | } |
129 | 129 | ||
130 | #[test] | 130 | #[test] |
131 | fn change_visibility_works_with_struct_fields() { | 131 | fn change_visibility_works_with_struct_fields() { |
132 | check_assist( | 132 | check_assist( |
133 | change_visibility, | 133 | change_visibility, |
134 | r"struct S { <|>field: u32 }", | 134 | r"struct S { $0field: u32 }", |
135 | r"struct S { pub(crate) field: u32 }", | 135 | r"struct S { pub(crate) field: u32 }", |
136 | ); | 136 | ); |
137 | check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( pub(crate) u32 )"); | 137 | check_assist(change_visibility, r"struct S ( $0u32 )", r"struct S ( pub(crate) u32 )"); |
138 | } | 138 | } |
139 | 139 | ||
140 | #[test] | 140 | #[test] |
@@ -142,33 +142,33 @@ mod tests { | |||
142 | mark::check!(change_visibility_field_false_positive); | 142 | mark::check!(change_visibility_field_false_positive); |
143 | check_assist_not_applicable( | 143 | check_assist_not_applicable( |
144 | change_visibility, | 144 | change_visibility, |
145 | r"struct S { field: [(); { let <|>x = ();}] }", | 145 | r"struct S { field: [(); { let $0x = ();}] }", |
146 | ) | 146 | ) |
147 | } | 147 | } |
148 | 148 | ||
149 | #[test] | 149 | #[test] |
150 | fn change_visibility_pub_to_pub_crate() { | 150 | fn change_visibility_pub_to_pub_crate() { |
151 | check_assist(change_visibility, "<|>pub fn foo() {}", "pub(crate) fn foo() {}") | 151 | check_assist(change_visibility, "$0pub fn foo() {}", "pub(crate) fn foo() {}") |
152 | } | 152 | } |
153 | 153 | ||
154 | #[test] | 154 | #[test] |
155 | fn change_visibility_pub_crate_to_pub() { | 155 | fn change_visibility_pub_crate_to_pub() { |
156 | check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "pub fn foo() {}") | 156 | check_assist(change_visibility, "$0pub(crate) fn foo() {}", "pub fn foo() {}") |
157 | } | 157 | } |
158 | 158 | ||
159 | #[test] | 159 | #[test] |
160 | fn change_visibility_const() { | 160 | fn change_visibility_const() { |
161 | check_assist(change_visibility, "<|>const FOO = 3u8;", "pub(crate) const FOO = 3u8;"); | 161 | check_assist(change_visibility, "$0const FOO = 3u8;", "pub(crate) const FOO = 3u8;"); |
162 | } | 162 | } |
163 | 163 | ||
164 | #[test] | 164 | #[test] |
165 | fn change_visibility_static() { | 165 | fn change_visibility_static() { |
166 | check_assist(change_visibility, "<|>static FOO = 3u8;", "pub(crate) static FOO = 3u8;"); | 166 | check_assist(change_visibility, "$0static FOO = 3u8;", "pub(crate) static FOO = 3u8;"); |
167 | } | 167 | } |
168 | 168 | ||
169 | #[test] | 169 | #[test] |
170 | fn change_visibility_type_alias() { | 170 | fn change_visibility_type_alias() { |
171 | check_assist(change_visibility, "<|>type T = ();", "pub(crate) type T = ();"); | 171 | check_assist(change_visibility, "$0type T = ();", "pub(crate) type T = ();"); |
172 | } | 172 | } |
173 | 173 | ||
174 | #[test] | 174 | #[test] |
@@ -181,7 +181,7 @@ mod tests { | |||
181 | // comments | 181 | // comments |
182 | 182 | ||
183 | #[derive(Debug)] | 183 | #[derive(Debug)] |
184 | <|>struct Foo; | 184 | $0struct Foo; |
185 | ", | 185 | ", |
186 | r" | 186 | r" |
187 | /// docs | 187 | /// docs |
@@ -199,14 +199,14 @@ mod tests { | |||
199 | check_assist_not_applicable( | 199 | check_assist_not_applicable( |
200 | change_visibility, | 200 | change_visibility, |
201 | r"mod foo { pub enum Foo {Foo1} } | 201 | r"mod foo { pub enum Foo {Foo1} } |
202 | fn main() { foo::Foo::Foo1<|> } ", | 202 | fn main() { foo::Foo::Foo1$0 } ", |
203 | ); | 203 | ); |
204 | } | 204 | } |
205 | 205 | ||
206 | #[test] | 206 | #[test] |
207 | fn change_visibility_target() { | 207 | fn change_visibility_target() { |
208 | check_assist_target(change_visibility, "<|>fn foo() {}", "fn"); | 208 | check_assist_target(change_visibility, "$0fn foo() {}", "fn"); |
209 | check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)"); | 209 | check_assist_target(change_visibility, "pub(crate)$0 fn foo() {}", "pub(crate)"); |
210 | check_assist_target(change_visibility, "struct S { <|>field: u32 }", "field"); | 210 | check_assist_target(change_visibility, "struct S { $0field: u32 }", "field"); |
211 | } | 211 | } |
212 | } | 212 | } |
diff --git a/crates/assists/src/handlers/convert_integer_literal.rs b/crates/assists/src/handlers/convert_integer_literal.rs index 667115382..a8a819cfc 100644 --- a/crates/assists/src/handlers/convert_integer_literal.rs +++ b/crates/assists/src/handlers/convert_integer_literal.rs | |||
@@ -7,7 +7,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; | |||
7 | // Converts the base of integer literals to other bases. | 7 | // Converts the base of integer literals to other bases. |
8 | // | 8 | // |
9 | // ``` | 9 | // ``` |
10 | // const _: i32 = 10<|>; | 10 | // const _: i32 = 10$0; |
11 | // ``` | 11 | // ``` |
12 | // -> | 12 | // -> |
13 | // ``` | 13 | // ``` |
@@ -65,47 +65,47 @@ mod tests { | |||
65 | 65 | ||
66 | #[test] | 66 | #[test] |
67 | fn binary_target() { | 67 | fn binary_target() { |
68 | check_assist_target(convert_integer_literal, "const _: i32 = 0b1010<|>;", "0b1010"); | 68 | check_assist_target(convert_integer_literal, "const _: i32 = 0b1010$0;", "0b1010"); |
69 | } | 69 | } |
70 | 70 | ||
71 | #[test] | 71 | #[test] |
72 | fn octal_target() { | 72 | fn octal_target() { |
73 | check_assist_target(convert_integer_literal, "const _: i32 = 0o12<|>;", "0o12"); | 73 | check_assist_target(convert_integer_literal, "const _: i32 = 0o12$0;", "0o12"); |
74 | } | 74 | } |
75 | 75 | ||
76 | #[test] | 76 | #[test] |
77 | fn decimal_target() { | 77 | fn decimal_target() { |
78 | check_assist_target(convert_integer_literal, "const _: i32 = 10<|>;", "10"); | 78 | check_assist_target(convert_integer_literal, "const _: i32 = 10$0;", "10"); |
79 | } | 79 | } |
80 | 80 | ||
81 | #[test] | 81 | #[test] |
82 | fn hexadecimal_target() { | 82 | fn hexadecimal_target() { |
83 | check_assist_target(convert_integer_literal, "const _: i32 = 0xA<|>;", "0xA"); | 83 | check_assist_target(convert_integer_literal, "const _: i32 = 0xA$0;", "0xA"); |
84 | } | 84 | } |
85 | 85 | ||
86 | #[test] | 86 | #[test] |
87 | fn binary_target_with_underscores() { | 87 | fn binary_target_with_underscores() { |
88 | check_assist_target(convert_integer_literal, "const _: i32 = 0b10_10<|>;", "0b10_10"); | 88 | check_assist_target(convert_integer_literal, "const _: i32 = 0b10_10$0;", "0b10_10"); |
89 | } | 89 | } |
90 | 90 | ||
91 | #[test] | 91 | #[test] |
92 | fn octal_target_with_underscores() { | 92 | fn octal_target_with_underscores() { |
93 | check_assist_target(convert_integer_literal, "const _: i32 = 0o1_2<|>;", "0o1_2"); | 93 | check_assist_target(convert_integer_literal, "const _: i32 = 0o1_2$0;", "0o1_2"); |
94 | } | 94 | } |
95 | 95 | ||
96 | #[test] | 96 | #[test] |
97 | fn decimal_target_with_underscores() { | 97 | fn decimal_target_with_underscores() { |
98 | check_assist_target(convert_integer_literal, "const _: i32 = 1_0<|>;", "1_0"); | 98 | check_assist_target(convert_integer_literal, "const _: i32 = 1_0$0;", "1_0"); |
99 | } | 99 | } |
100 | 100 | ||
101 | #[test] | 101 | #[test] |
102 | fn hexadecimal_target_with_underscores() { | 102 | fn hexadecimal_target_with_underscores() { |
103 | check_assist_target(convert_integer_literal, "const _: i32 = 0x_A<|>;", "0x_A"); | 103 | check_assist_target(convert_integer_literal, "const _: i32 = 0x_A$0;", "0x_A"); |
104 | } | 104 | } |
105 | 105 | ||
106 | #[test] | 106 | #[test] |
107 | fn convert_decimal_integer() { | 107 | fn convert_decimal_integer() { |
108 | let before = "const _: i32 = 1000<|>;"; | 108 | let before = "const _: i32 = 1000$0;"; |
109 | 109 | ||
110 | check_assist_by_label( | 110 | check_assist_by_label( |
111 | convert_integer_literal, | 111 | convert_integer_literal, |
@@ -131,7 +131,7 @@ mod tests { | |||
131 | 131 | ||
132 | #[test] | 132 | #[test] |
133 | fn convert_hexadecimal_integer() { | 133 | fn convert_hexadecimal_integer() { |
134 | let before = "const _: i32 = 0xFF<|>;"; | 134 | let before = "const _: i32 = 0xFF$0;"; |
135 | 135 | ||
136 | check_assist_by_label( | 136 | check_assist_by_label( |
137 | convert_integer_literal, | 137 | convert_integer_literal, |
@@ -157,7 +157,7 @@ mod tests { | |||
157 | 157 | ||
158 | #[test] | 158 | #[test] |
159 | fn convert_binary_integer() { | 159 | fn convert_binary_integer() { |
160 | let before = "const _: i32 = 0b11111111<|>;"; | 160 | let before = "const _: i32 = 0b11111111$0;"; |
161 | 161 | ||
162 | check_assist_by_label( | 162 | check_assist_by_label( |
163 | convert_integer_literal, | 163 | convert_integer_literal, |
@@ -183,7 +183,7 @@ mod tests { | |||
183 | 183 | ||
184 | #[test] | 184 | #[test] |
185 | fn convert_octal_integer() { | 185 | fn convert_octal_integer() { |
186 | let before = "const _: i32 = 0o377<|>;"; | 186 | let before = "const _: i32 = 0o377$0;"; |
187 | 187 | ||
188 | check_assist_by_label( | 188 | check_assist_by_label( |
189 | convert_integer_literal, | 189 | convert_integer_literal, |
@@ -209,7 +209,7 @@ mod tests { | |||
209 | 209 | ||
210 | #[test] | 210 | #[test] |
211 | fn convert_integer_with_underscores() { | 211 | fn convert_integer_with_underscores() { |
212 | let before = "const _: i32 = 1_00_0<|>;"; | 212 | let before = "const _: i32 = 1_00_0$0;"; |
213 | 213 | ||
214 | check_assist_by_label( | 214 | check_assist_by_label( |
215 | convert_integer_literal, | 215 | convert_integer_literal, |
@@ -235,7 +235,7 @@ mod tests { | |||
235 | 235 | ||
236 | #[test] | 236 | #[test] |
237 | fn convert_integer_with_suffix() { | 237 | fn convert_integer_with_suffix() { |
238 | let before = "const _: i32 = 1000i32<|>;"; | 238 | let before = "const _: i32 = 1000i32$0;"; |
239 | 239 | ||
240 | check_assist_by_label( | 240 | check_assist_by_label( |
241 | convert_integer_literal, | 241 | convert_integer_literal, |
@@ -262,7 +262,7 @@ mod tests { | |||
262 | #[test] | 262 | #[test] |
263 | fn convert_overflowing_literal() { | 263 | fn convert_overflowing_literal() { |
264 | let before = "const _: i32 = | 264 | let before = "const _: i32 = |
265 | 111111111111111111111111111111111111111111111111111111111111111111111111<|>;"; | 265 | 111111111111111111111111111111111111111111111111111111111111111111111111$0;"; |
266 | check_assist_not_applicable(convert_integer_literal, before); | 266 | check_assist_not_applicable(convert_integer_literal, before); |
267 | } | 267 | } |
268 | } | 268 | } |
diff --git a/crates/assists/src/handlers/early_return.rs b/crates/assists/src/handlers/early_return.rs index 7bcc318a9..8bbbb7ed5 100644 --- a/crates/assists/src/handlers/early_return.rs +++ b/crates/assists/src/handlers/early_return.rs | |||
@@ -24,7 +24,7 @@ use crate::{ | |||
24 | // | 24 | // |
25 | // ``` | 25 | // ``` |
26 | // fn main() { | 26 | // fn main() { |
27 | // <|>if cond { | 27 | // $0if cond { |
28 | // foo(); | 28 | // foo(); |
29 | // bar(); | 29 | // bar(); |
30 | // } | 30 | // } |
@@ -69,7 +69,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
69 | 69 | ||
70 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; | 70 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; |
71 | 71 | ||
72 | if parent_block.expr()? != if_expr.clone().into() { | 72 | if parent_block.tail_expr()? != if_expr.clone().into() { |
73 | return None; | 73 | return None; |
74 | } | 74 | } |
75 | 75 | ||
@@ -200,7 +200,7 @@ mod tests { | |||
200 | r#" | 200 | r#" |
201 | fn main() { | 201 | fn main() { |
202 | bar(); | 202 | bar(); |
203 | if<|> true { | 203 | if$0 true { |
204 | foo(); | 204 | foo(); |
205 | 205 | ||
206 | //comment | 206 | //comment |
@@ -230,7 +230,7 @@ mod tests { | |||
230 | r#" | 230 | r#" |
231 | fn main(n: Option<String>) { | 231 | fn main(n: Option<String>) { |
232 | bar(); | 232 | bar(); |
233 | if<|> let Some(n) = n { | 233 | if$0 let Some(n) = n { |
234 | foo(n); | 234 | foo(n); |
235 | 235 | ||
236 | //comment | 236 | //comment |
@@ -260,7 +260,7 @@ mod tests { | |||
260 | convert_to_guarded_return, | 260 | convert_to_guarded_return, |
261 | r#" | 261 | r#" |
262 | fn main() { | 262 | fn main() { |
263 | if<|> let Ok(x) = Err(92) { | 263 | if$0 let Ok(x) = Err(92) { |
264 | foo(x); | 264 | foo(x); |
265 | } | 265 | } |
266 | } | 266 | } |
@@ -284,7 +284,7 @@ mod tests { | |||
284 | r#" | 284 | r#" |
285 | fn main(n: Option<String>) { | 285 | fn main(n: Option<String>) { |
286 | bar(); | 286 | bar(); |
287 | if<|> let Ok(n) = n { | 287 | if$0 let Ok(n) = n { |
288 | foo(n); | 288 | foo(n); |
289 | 289 | ||
290 | //comment | 290 | //comment |
@@ -315,7 +315,7 @@ mod tests { | |||
315 | r#" | 315 | r#" |
316 | fn main() { | 316 | fn main() { |
317 | while true { | 317 | while true { |
318 | if<|> true { | 318 | if$0 true { |
319 | foo(); | 319 | foo(); |
320 | bar(); | 320 | bar(); |
321 | } | 321 | } |
@@ -343,7 +343,7 @@ mod tests { | |||
343 | r#" | 343 | r#" |
344 | fn main() { | 344 | fn main() { |
345 | while true { | 345 | while true { |
346 | if<|> let Some(n) = n { | 346 | if$0 let Some(n) = n { |
347 | foo(n); | 347 | foo(n); |
348 | bar(); | 348 | bar(); |
349 | } | 349 | } |
@@ -372,7 +372,7 @@ mod tests { | |||
372 | r#" | 372 | r#" |
373 | fn main() { | 373 | fn main() { |
374 | loop { | 374 | loop { |
375 | if<|> true { | 375 | if$0 true { |
376 | foo(); | 376 | foo(); |
377 | bar(); | 377 | bar(); |
378 | } | 378 | } |
@@ -400,7 +400,7 @@ mod tests { | |||
400 | r#" | 400 | r#" |
401 | fn main() { | 401 | fn main() { |
402 | loop { | 402 | loop { |
403 | if<|> let Some(n) = n { | 403 | if$0 let Some(n) = n { |
404 | foo(n); | 404 | foo(n); |
405 | bar(); | 405 | bar(); |
406 | } | 406 | } |
@@ -428,7 +428,7 @@ mod tests { | |||
428 | convert_to_guarded_return, | 428 | convert_to_guarded_return, |
429 | r#" | 429 | r#" |
430 | fn main() { | 430 | fn main() { |
431 | if<|> true { | 431 | if$0 true { |
432 | return; | 432 | return; |
433 | } | 433 | } |
434 | } | 434 | } |
@@ -443,7 +443,7 @@ mod tests { | |||
443 | r#" | 443 | r#" |
444 | fn main() { | 444 | fn main() { |
445 | loop { | 445 | loop { |
446 | if<|> true { | 446 | if$0 true { |
447 | continue; | 447 | continue; |
448 | } | 448 | } |
449 | } | 449 | } |
@@ -458,7 +458,7 @@ mod tests { | |||
458 | convert_to_guarded_return, | 458 | convert_to_guarded_return, |
459 | r#" | 459 | r#" |
460 | fn main() { | 460 | fn main() { |
461 | if<|> true { | 461 | if$0 true { |
462 | return | 462 | return |
463 | } | 463 | } |
464 | } | 464 | } |
@@ -472,7 +472,7 @@ mod tests { | |||
472 | convert_to_guarded_return, | 472 | convert_to_guarded_return, |
473 | r#" | 473 | r#" |
474 | fn main() { | 474 | fn main() { |
475 | if<|> true { | 475 | if$0 true { |
476 | foo(); | 476 | foo(); |
477 | } else { | 477 | } else { |
478 | bar() | 478 | bar() |
@@ -488,7 +488,7 @@ mod tests { | |||
488 | convert_to_guarded_return, | 488 | convert_to_guarded_return, |
489 | r#" | 489 | r#" |
490 | fn main() { | 490 | fn main() { |
491 | if<|> true { | 491 | if$0 true { |
492 | foo(); | 492 | foo(); |
493 | } | 493 | } |
494 | bar(); | 494 | bar(); |
@@ -504,7 +504,7 @@ mod tests { | |||
504 | r#" | 504 | r#" |
505 | fn main() { | 505 | fn main() { |
506 | if false { | 506 | if false { |
507 | if<|> true { | 507 | if$0 true { |
508 | foo(); | 508 | foo(); |
509 | } | 509 | } |
510 | } | 510 | } |
diff --git a/crates/assists/src/handlers/expand_glob_import.rs b/crates/assists/src/handlers/expand_glob_import.rs index f51a9a4ad..5fe617ba4 100644 --- a/crates/assists/src/handlers/expand_glob_import.rs +++ b/crates/assists/src/handlers/expand_glob_import.rs | |||
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | // pub struct Baz; | 25 | // pub struct Baz; |
26 | // } | 26 | // } |
27 | // | 27 | // |
28 | // use foo::*<|>; | 28 | // use foo::*$0; |
29 | // | 29 | // |
30 | // fn qux(bar: Bar, baz: Baz) {} | 30 | // fn qux(bar: Bar, baz: Baz) {} |
31 | // ``` | 31 | // ``` |
@@ -201,7 +201,7 @@ fn is_mod_visible_from(ctx: &AssistContext, module: Module, from: Module) -> boo | |||
201 | // } | 201 | // } |
202 | // | 202 | // |
203 | // ↓ --------------- | 203 | // ↓ --------------- |
204 | // use foo::*<|>; | 204 | // use foo::*$0; |
205 | // use baz::Baz; | 205 | // use baz::Baz; |
206 | // ↑ --------------- | 206 | // ↑ --------------- |
207 | fn find_imported_defs(ctx: &AssistContext, star: SyntaxToken) -> Option<Vec<Def>> { | 207 | fn find_imported_defs(ctx: &AssistContext, star: SyntaxToken) -> Option<Vec<Def>> { |
@@ -303,7 +303,7 @@ mod foo { | |||
303 | pub fn f() {} | 303 | pub fn f() {} |
304 | } | 304 | } |
305 | 305 | ||
306 | use foo::*<|>; | 306 | use foo::*$0; |
307 | 307 | ||
308 | fn qux(bar: Bar, baz: Baz) { | 308 | fn qux(bar: Bar, baz: Baz) { |
309 | f(); | 309 | f(); |
@@ -340,7 +340,7 @@ mod foo { | |||
340 | pub fn f() {} | 340 | pub fn f() {} |
341 | } | 341 | } |
342 | 342 | ||
343 | use foo::{*<|>, f}; | 343 | use foo::{*$0, f}; |
344 | 344 | ||
345 | fn qux(bar: Bar, baz: Baz) { | 345 | fn qux(bar: Bar, baz: Baz) { |
346 | f(); | 346 | f(); |
@@ -378,7 +378,7 @@ mod foo { | |||
378 | } | 378 | } |
379 | 379 | ||
380 | use foo::Bar; | 380 | use foo::Bar; |
381 | use foo::{*<|>, f}; | 381 | use foo::{*$0, f}; |
382 | 382 | ||
383 | fn qux(bar: Bar, baz: Baz) { | 383 | fn qux(bar: Bar, baz: Baz) { |
384 | f(); | 384 | f(); |
@@ -422,7 +422,7 @@ mod foo { | |||
422 | } | 422 | } |
423 | } | 423 | } |
424 | 424 | ||
425 | use foo::{bar::{*<|>, f}, baz::*}; | 425 | use foo::{bar::{*$0, f}, baz::*}; |
426 | 426 | ||
427 | fn qux(bar: Bar, baz: Baz) { | 427 | fn qux(bar: Bar, baz: Baz) { |
428 | f(); | 428 | f(); |
@@ -470,7 +470,7 @@ mod foo { | |||
470 | } | 470 | } |
471 | } | 471 | } |
472 | 472 | ||
473 | use foo::{bar::{Bar, Baz, f}, baz::*<|>}; | 473 | use foo::{bar::{Bar, Baz, f}, baz::*$0}; |
474 | 474 | ||
475 | fn qux(bar: Bar, baz: Baz) { | 475 | fn qux(bar: Bar, baz: Baz) { |
476 | f(); | 476 | f(); |
@@ -529,7 +529,7 @@ mod foo { | |||
529 | 529 | ||
530 | use foo::{ | 530 | use foo::{ |
531 | bar::{*, f}, | 531 | bar::{*, f}, |
532 | baz::{g, qux::*<|>} | 532 | baz::{g, qux::*$0} |
533 | }; | 533 | }; |
534 | 534 | ||
535 | fn qux(bar: Bar, baz: Baz) { | 535 | fn qux(bar: Bar, baz: Baz) { |
@@ -605,7 +605,7 @@ mod foo { | |||
605 | 605 | ||
606 | use foo::{ | 606 | use foo::{ |
607 | bar::{*, f}, | 607 | bar::{*, f}, |
608 | baz::{g, qux::{h, q::*<|>}} | 608 | baz::{g, qux::{h, q::*$0}} |
609 | }; | 609 | }; |
610 | 610 | ||
611 | fn qux(bar: Bar, baz: Baz) { | 611 | fn qux(bar: Bar, baz: Baz) { |
@@ -681,7 +681,7 @@ mod foo { | |||
681 | 681 | ||
682 | use foo::{ | 682 | use foo::{ |
683 | bar::{*, f}, | 683 | bar::{*, f}, |
684 | baz::{g, qux::{q::j, *<|>}} | 684 | baz::{g, qux::{q::j, *$0}} |
685 | }; | 685 | }; |
686 | 686 | ||
687 | fn qux(bar: Bar, baz: Baz) { | 687 | fn qux(bar: Bar, baz: Baz) { |
@@ -747,7 +747,7 @@ fn qux(bar: Bar, baz: Baz) { | |||
747 | // pub fn baz() {} | 747 | // pub fn baz() {} |
748 | 748 | ||
749 | // //- /main.rs crate:main deps:foo | 749 | // //- /main.rs crate:main deps:foo |
750 | // use foo::*<|>; | 750 | // use foo::*$0; |
751 | 751 | ||
752 | // fn main() { | 752 | // fn main() { |
753 | // bar!(); | 753 | // bar!(); |
@@ -777,7 +777,7 @@ pub trait Tr { | |||
777 | impl Tr for () {} | 777 | impl Tr for () {} |
778 | 778 | ||
779 | //- /main.rs crate:main deps:foo | 779 | //- /main.rs crate:main deps:foo |
780 | use foo::*<|>; | 780 | use foo::*$0; |
781 | 781 | ||
782 | fn main() { | 782 | fn main() { |
783 | ().method(); | 783 | ().method(); |
@@ -807,7 +807,7 @@ pub trait Tr2 { | |||
807 | impl Tr2 for () {} | 807 | impl Tr2 for () {} |
808 | 808 | ||
809 | //- /main.rs crate:main deps:foo | 809 | //- /main.rs crate:main deps:foo |
810 | use foo::*<|>; | 810 | use foo::*$0; |
811 | 811 | ||
812 | fn main() { | 812 | fn main() { |
813 | ().method(); | 813 | ().method(); |
@@ -834,7 +834,7 @@ mod foo { | |||
834 | } | 834 | } |
835 | } | 835 | } |
836 | 836 | ||
837 | use foo::bar::*<|>; | 837 | use foo::bar::*$0; |
838 | 838 | ||
839 | fn baz(bar: Bar) {} | 839 | fn baz(bar: Bar) {} |
840 | ", | 840 | ", |
@@ -851,7 +851,7 @@ mod foo { | |||
851 | } | 851 | } |
852 | } | 852 | } |
853 | 853 | ||
854 | use foo::bar::baz::*<|>; | 854 | use foo::bar::baz::*$0; |
855 | 855 | ||
856 | fn qux(baz: Baz) {} | 856 | fn qux(baz: Baz) {} |
857 | ", | 857 | ", |
@@ -869,7 +869,7 @@ fn qux(baz: Baz) {} | |||
869 | pub struct Qux; | 869 | pub struct Qux; |
870 | } | 870 | } |
871 | 871 | ||
872 | use foo::Bar<|>; | 872 | use foo::Bar$0; |
873 | 873 | ||
874 | fn qux(bar: Bar, baz: Baz) {} | 874 | fn qux(bar: Bar, baz: Baz) {} |
875 | ", | 875 | ", |
@@ -885,7 +885,7 @@ mod foo { | |||
885 | pub struct Bar; | 885 | pub struct Bar; |
886 | } | 886 | } |
887 | 887 | ||
888 | use foo::{*<|>}; | 888 | use foo::{*$0}; |
889 | 889 | ||
890 | struct Baz { | 890 | struct Baz { |
891 | bar: Bar | 891 | bar: Bar |
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 030b9cd0c..e3ef04932 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -2,12 +2,16 @@ use std::iter; | |||
2 | 2 | ||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir::{AsName, Module, ModuleDef, Name, Variant}; | 4 | use hir::{AsName, Module, ModuleDef, Name, Variant}; |
5 | use ide_db::helpers::{ | 5 | use ide_db::{ |
6 | insert_use::{insert_use, ImportScope}, | 6 | defs::Definition, |
7 | mod_path_to_ast, | 7 | helpers::{ |
8 | insert_use::{insert_use, ImportScope}, | ||
9 | mod_path_to_ast, | ||
10 | }, | ||
11 | search::FileReference, | ||
12 | RootDatabase, | ||
8 | }; | 13 | }; |
9 | use ide_db::{defs::Definition, search::Reference, RootDatabase}; | 14 | use rustc_hash::FxHashSet; |
10 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
11 | use syntax::{ | 15 | use syntax::{ |
12 | algo::{find_node_at_offset, SyntaxRewriter}, | 16 | algo::{find_node_at_offset, SyntaxRewriter}, |
13 | ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, | 17 | ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, |
@@ -21,7 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
21 | // Extracts a struct from enum variant. | 25 | // Extracts a struct from enum variant. |
22 | // | 26 | // |
23 | // ``` | 27 | // ``` |
24 | // enum A { <|>One(u32, u32) } | 28 | // enum A { $0One(u32, u32) } |
25 | // ``` | 29 | // ``` |
26 | // -> | 30 | // -> |
27 | // ``` | 31 | // ``` |
@@ -58,29 +62,29 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
58 | let mut visited_modules_set = FxHashSet::default(); | 62 | let mut visited_modules_set = FxHashSet::default(); |
59 | let current_module = enum_hir.module(ctx.db()); | 63 | let current_module = enum_hir.module(ctx.db()); |
60 | visited_modules_set.insert(current_module); | 64 | visited_modules_set.insert(current_module); |
61 | let mut rewriters = FxHashMap::default(); | 65 | let mut def_rewriter = None; |
62 | for reference in usages { | 66 | for (file_id, references) in usages { |
63 | let rewriter = rewriters | 67 | let mut rewriter = SyntaxRewriter::default(); |
64 | .entry(reference.file_range.file_id) | 68 | let source_file = ctx.sema.parse(file_id); |
65 | .or_insert_with(SyntaxRewriter::default); | 69 | for reference in references { |
66 | let source_file = ctx.sema.parse(reference.file_range.file_id); | 70 | update_reference( |
67 | update_reference( | 71 | ctx, |
68 | ctx, | 72 | &mut rewriter, |
69 | rewriter, | 73 | reference, |
70 | reference, | 74 | &source_file, |
71 | &source_file, | 75 | &enum_module_def, |
72 | &enum_module_def, | 76 | &variant_hir_name, |
73 | &variant_hir_name, | 77 | &mut visited_modules_set, |
74 | &mut visited_modules_set, | 78 | ); |
75 | ); | 79 | } |
76 | } | 80 | if file_id == ctx.frange.file_id { |
77 | let mut rewriter = | 81 | def_rewriter = Some(rewriter); |
78 | rewriters.remove(&ctx.frange.file_id).unwrap_or_else(SyntaxRewriter::default); | 82 | continue; |
79 | for (file_id, rewriter) in rewriters { | 83 | } |
80 | builder.edit_file(file_id); | 84 | builder.edit_file(file_id); |
81 | builder.rewrite(rewriter); | 85 | builder.rewrite(rewriter); |
82 | } | 86 | } |
83 | builder.edit_file(ctx.frange.file_id); | 87 | let mut rewriter = def_rewriter.unwrap_or_default(); |
84 | update_variant(&mut rewriter, &variant); | 88 | update_variant(&mut rewriter, &variant); |
85 | extract_struct_def( | 89 | extract_struct_def( |
86 | &mut rewriter, | 90 | &mut rewriter, |
@@ -90,6 +94,7 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
90 | &variant.parent_enum().syntax().clone().into(), | 94 | &variant.parent_enum().syntax().clone().into(), |
91 | enum_ast.visibility(), | 95 | enum_ast.visibility(), |
92 | ); | 96 | ); |
97 | builder.edit_file(ctx.frange.file_id); | ||
93 | builder.rewrite(rewriter); | 98 | builder.rewrite(rewriter); |
94 | }, | 99 | }, |
95 | ) | 100 | ) |
@@ -117,10 +122,14 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va | |||
117 | .into_iter() | 122 | .into_iter() |
118 | .filter(|(_, def)| match def { | 123 | .filter(|(_, def)| match def { |
119 | // only check type-namespace | 124 | // only check type-namespace |
120 | hir::ScopeDef::ModuleDef(def) => matches!(def, | 125 | hir::ScopeDef::ModuleDef(def) => matches!( |
121 | ModuleDef::Module(_) | ModuleDef::Adt(_) | | 126 | def, |
122 | ModuleDef::Variant(_) | ModuleDef::Trait(_) | | 127 | ModuleDef::Module(_) |
123 | ModuleDef::TypeAlias(_) | ModuleDef::BuiltinType(_) | 128 | | ModuleDef::Adt(_) |
129 | | ModuleDef::Variant(_) | ||
130 | | ModuleDef::Trait(_) | ||
131 | | ModuleDef::TypeAlias(_) | ||
132 | | ModuleDef::BuiltinType(_) | ||
124 | ), | 133 | ), |
125 | _ => false, | 134 | _ => false, |
126 | }) | 135 | }) |
@@ -201,13 +210,13 @@ fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Opti | |||
201 | fn update_reference( | 210 | fn update_reference( |
202 | ctx: &AssistContext, | 211 | ctx: &AssistContext, |
203 | rewriter: &mut SyntaxRewriter, | 212 | rewriter: &mut SyntaxRewriter, |
204 | reference: Reference, | 213 | reference: FileReference, |
205 | source_file: &SourceFile, | 214 | source_file: &SourceFile, |
206 | enum_module_def: &ModuleDef, | 215 | enum_module_def: &ModuleDef, |
207 | variant_hir_name: &Name, | 216 | variant_hir_name: &Name, |
208 | visited_modules_set: &mut FxHashSet<Module>, | 217 | visited_modules_set: &mut FxHashSet<Module>, |
209 | ) -> Option<()> { | 218 | ) -> Option<()> { |
210 | let offset = reference.file_range.range.start(); | 219 | let offset = reference.range.start(); |
211 | let (segment, expr) = if let Some(path_expr) = | 220 | let (segment, expr) = if let Some(path_expr) = |
212 | find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset) | 221 | find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset) |
213 | { | 222 | { |
@@ -247,7 +256,7 @@ mod tests { | |||
247 | fn test_extract_struct_several_fields_tuple() { | 256 | fn test_extract_struct_several_fields_tuple() { |
248 | check_assist( | 257 | check_assist( |
249 | extract_struct_from_enum_variant, | 258 | extract_struct_from_enum_variant, |
250 | "enum A { <|>One(u32, u32) }", | 259 | "enum A { $0One(u32, u32) }", |
251 | r#"struct One(pub u32, pub u32); | 260 | r#"struct One(pub u32, pub u32); |
252 | 261 | ||
253 | enum A { One(One) }"#, | 262 | enum A { One(One) }"#, |
@@ -258,7 +267,7 @@ enum A { One(One) }"#, | |||
258 | fn test_extract_struct_several_fields_named() { | 267 | fn test_extract_struct_several_fields_named() { |
259 | check_assist( | 268 | check_assist( |
260 | extract_struct_from_enum_variant, | 269 | extract_struct_from_enum_variant, |
261 | "enum A { <|>One { foo: u32, bar: u32 } }", | 270 | "enum A { $0One { foo: u32, bar: u32 } }", |
262 | r#"struct One{ pub foo: u32, pub bar: u32 } | 271 | r#"struct One{ pub foo: u32, pub bar: u32 } |
263 | 272 | ||
264 | enum A { One(One) }"#, | 273 | enum A { One(One) }"#, |
@@ -269,7 +278,7 @@ enum A { One(One) }"#, | |||
269 | fn test_extract_struct_one_field_named() { | 278 | fn test_extract_struct_one_field_named() { |
270 | check_assist( | 279 | check_assist( |
271 | extract_struct_from_enum_variant, | 280 | extract_struct_from_enum_variant, |
272 | "enum A { <|>One { foo: u32 } }", | 281 | "enum A { $0One { foo: u32 } }", |
273 | r#"struct One{ pub foo: u32 } | 282 | r#"struct One{ pub foo: u32 } |
274 | 283 | ||
275 | enum A { One(One) }"#, | 284 | enum A { One(One) }"#, |
@@ -281,7 +290,7 @@ enum A { One(One) }"#, | |||
281 | check_assist( | 290 | check_assist( |
282 | extract_struct_from_enum_variant, | 291 | extract_struct_from_enum_variant, |
283 | r#"const One: () = (); | 292 | r#"const One: () = (); |
284 | enum A { <|>One(u32, u32) }"#, | 293 | enum A { $0One(u32, u32) }"#, |
285 | r#"const One: () = (); | 294 | r#"const One: () = (); |
286 | struct One(pub u32, pub u32); | 295 | struct One(pub u32, pub u32); |
287 | 296 | ||
@@ -293,7 +302,7 @@ enum A { One(One) }"#, | |||
293 | fn test_extract_struct_pub_visibility() { | 302 | fn test_extract_struct_pub_visibility() { |
294 | check_assist( | 303 | check_assist( |
295 | extract_struct_from_enum_variant, | 304 | extract_struct_from_enum_variant, |
296 | "pub enum A { <|>One(u32, u32) }", | 305 | "pub enum A { $0One(u32, u32) }", |
297 | r#"pub struct One(pub u32, pub u32); | 306 | r#"pub struct One(pub u32, pub u32); |
298 | 307 | ||
299 | pub enum A { One(One) }"#, | 308 | pub enum A { One(One) }"#, |
@@ -315,7 +324,7 @@ pub enum A { One(One) }"#, | |||
315 | } | 324 | } |
316 | 325 | ||
317 | pub enum MyEnum { | 326 | pub enum MyEnum { |
318 | <|>MyField(u8, u8), | 327 | $0MyField(u8, u8), |
319 | } | 328 | } |
320 | } | 329 | } |
321 | } | 330 | } |
@@ -357,7 +366,7 @@ fn another_fn() { | |||
357 | extract_struct_from_enum_variant, | 366 | extract_struct_from_enum_variant, |
358 | r#" | 367 | r#" |
359 | enum E { | 368 | enum E { |
360 | <|>V { i: i32, j: i32 } | 369 | $0V { i: i32, j: i32 } |
361 | } | 370 | } |
362 | 371 | ||
363 | fn f() { | 372 | fn f() { |
@@ -385,7 +394,7 @@ fn f() { | |||
385 | r#" | 394 | r#" |
386 | //- /main.rs | 395 | //- /main.rs |
387 | enum E { | 396 | enum E { |
388 | <|>V(i32, i32) | 397 | $0V(i32, i32) |
389 | } | 398 | } |
390 | mod foo; | 399 | mod foo; |
391 | 400 | ||
@@ -420,7 +429,7 @@ fn f() { | |||
420 | r#" | 429 | r#" |
421 | //- /main.rs | 430 | //- /main.rs |
422 | enum E { | 431 | enum E { |
423 | <|>V { i: i32, j: i32 } | 432 | $0V { i: i32, j: i32 } |
424 | } | 433 | } |
425 | mod foo; | 434 | mod foo; |
426 | 435 | ||
@@ -453,7 +462,7 @@ fn f() { | |||
453 | check_assist( | 462 | check_assist( |
454 | extract_struct_from_enum_variant, | 463 | extract_struct_from_enum_variant, |
455 | r#" | 464 | r#" |
456 | enum A { <|>One { a: u32, b: u32 } } | 465 | enum A { $0One { a: u32, b: u32 } } |
457 | 466 | ||
458 | struct B(A); | 467 | struct B(A); |
459 | 468 | ||
@@ -483,29 +492,29 @@ fn foo() { | |||
483 | 492 | ||
484 | #[test] | 493 | #[test] |
485 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { | 494 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { |
486 | check_not_applicable("enum A { <|>One }"); | 495 | check_not_applicable("enum A { $0One }"); |
487 | } | 496 | } |
488 | 497 | ||
489 | #[test] | 498 | #[test] |
490 | fn test_extract_enum_not_applicable_if_struct_exists() { | 499 | fn test_extract_enum_not_applicable_if_struct_exists() { |
491 | check_not_applicable( | 500 | check_not_applicable( |
492 | r#"struct One; | 501 | r#"struct One; |
493 | enum A { <|>One(u8, u32) }"#, | 502 | enum A { $0One(u8, u32) }"#, |
494 | ); | 503 | ); |
495 | } | 504 | } |
496 | 505 | ||
497 | #[test] | 506 | #[test] |
498 | fn test_extract_not_applicable_one_field() { | 507 | fn test_extract_not_applicable_one_field() { |
499 | check_not_applicable(r"enum A { <|>One(u32) }"); | 508 | check_not_applicable(r"enum A { $0One(u32) }"); |
500 | } | 509 | } |
501 | 510 | ||
502 | #[test] | 511 | #[test] |
503 | fn test_extract_not_applicable_no_field_tuple() { | 512 | fn test_extract_not_applicable_no_field_tuple() { |
504 | check_not_applicable(r"enum A { <|>None() }"); | 513 | check_not_applicable(r"enum A { $0None() }"); |
505 | } | 514 | } |
506 | 515 | ||
507 | #[test] | 516 | #[test] |
508 | fn test_extract_not_applicable_no_field_named() { | 517 | fn test_extract_not_applicable_no_field_named() { |
509 | check_not_applicable(r"enum A { <|>None {} }"); | 518 | check_not_applicable(r"enum A { $0None {} }"); |
510 | } | 519 | } |
511 | } | 520 | } |
diff --git a/crates/assists/src/handlers/extract_variable.rs b/crates/assists/src/handlers/extract_variable.rs index 9957012fe..98f3dc6ca 100644 --- a/crates/assists/src/handlers/extract_variable.rs +++ b/crates/assists/src/handlers/extract_variable.rs | |||
@@ -16,7 +16,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
16 | // | 16 | // |
17 | // ``` | 17 | // ``` |
18 | // fn main() { | 18 | // fn main() { |
19 | // <|>(1 + 2)<|> * 4; | 19 | // $0(1 + 2)$0 * 4; |
20 | // } | 20 | // } |
21 | // ``` | 21 | // ``` |
22 | // -> | 22 | // -> |
@@ -139,7 +139,7 @@ impl Anchor { | |||
139 | fn from(to_extract: &ast::Expr) -> Option<Anchor> { | 139 | fn from(to_extract: &ast::Expr) -> Option<Anchor> { |
140 | to_extract.syntax().ancestors().find_map(|node| { | 140 | to_extract.syntax().ancestors().find_map(|node| { |
141 | if let Some(expr) = | 141 | if let Some(expr) = |
142 | node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) | 142 | node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr()) |
143 | { | 143 | { |
144 | if expr.syntax() == &node { | 144 | if expr.syntax() == &node { |
145 | mark::hit!(test_extract_var_last_expr); | 145 | mark::hit!(test_extract_var_last_expr); |
@@ -187,7 +187,7 @@ mod tests { | |||
187 | extract_variable, | 187 | extract_variable, |
188 | r#" | 188 | r#" |
189 | fn foo() { | 189 | fn foo() { |
190 | foo(<|>1 + 1<|>); | 190 | foo($01 + 1$0); |
191 | }"#, | 191 | }"#, |
192 | r#" | 192 | r#" |
193 | fn foo() { | 193 | fn foo() { |
@@ -200,7 +200,7 @@ fn foo() { | |||
200 | #[test] | 200 | #[test] |
201 | fn extract_var_in_comment_is_not_applicable() { | 201 | fn extract_var_in_comment_is_not_applicable() { |
202 | mark::check!(extract_var_in_comment_is_not_applicable); | 202 | mark::check!(extract_var_in_comment_is_not_applicable); |
203 | check_assist_not_applicable(extract_variable, "fn main() { 1 + /* <|>comment<|> */ 1; }"); | 203 | check_assist_not_applicable(extract_variable, "fn main() { 1 + /* $0comment$0 */ 1; }"); |
204 | } | 204 | } |
205 | 205 | ||
206 | #[test] | 206 | #[test] |
@@ -210,7 +210,7 @@ fn foo() { | |||
210 | extract_variable, | 210 | extract_variable, |
211 | r#" | 211 | r#" |
212 | fn foo() { | 212 | fn foo() { |
213 | <|>1 + 1<|>; | 213 | $01 + 1$0; |
214 | }"#, | 214 | }"#, |
215 | r#" | 215 | r#" |
216 | fn foo() { | 216 | fn foo() { |
@@ -221,7 +221,7 @@ fn foo() { | |||
221 | extract_variable, | 221 | extract_variable, |
222 | " | 222 | " |
223 | fn foo() { | 223 | fn foo() { |
224 | <|>{ let x = 0; x }<|> | 224 | $0{ let x = 0; x }$0 |
225 | something_else(); | 225 | something_else(); |
226 | }", | 226 | }", |
227 | " | 227 | " |
@@ -238,7 +238,7 @@ fn foo() { | |||
238 | extract_variable, | 238 | extract_variable, |
239 | " | 239 | " |
240 | fn foo() { | 240 | fn foo() { |
241 | <|>1<|> + 1; | 241 | $01$0 + 1; |
242 | }", | 242 | }", |
243 | " | 243 | " |
244 | fn foo() { | 244 | fn foo() { |
@@ -255,7 +255,7 @@ fn foo() { | |||
255 | extract_variable, | 255 | extract_variable, |
256 | r#" | 256 | r#" |
257 | fn foo() { | 257 | fn foo() { |
258 | bar(<|>1 + 1<|>) | 258 | bar($01 + 1$0) |
259 | } | 259 | } |
260 | "#, | 260 | "#, |
261 | r#" | 261 | r#" |
@@ -269,7 +269,7 @@ fn foo() { | |||
269 | extract_variable, | 269 | extract_variable, |
270 | r#" | 270 | r#" |
271 | fn foo() { | 271 | fn foo() { |
272 | <|>bar(1 + 1)<|> | 272 | $0bar(1 + 1)$0 |
273 | } | 273 | } |
274 | "#, | 274 | "#, |
275 | r#" | 275 | r#" |
@@ -289,7 +289,7 @@ fn foo() { | |||
289 | fn main() { | 289 | fn main() { |
290 | let x = true; | 290 | let x = true; |
291 | let tuple = match x { | 291 | let tuple = match x { |
292 | true => (<|>2 + 2<|>, true) | 292 | true => ($02 + 2$0, true) |
293 | _ => (0, false) | 293 | _ => (0, false) |
294 | }; | 294 | }; |
295 | } | 295 | } |
@@ -316,7 +316,7 @@ fn main() { | |||
316 | let tuple = match x { | 316 | let tuple = match x { |
317 | true => { | 317 | true => { |
318 | let y = 1; | 318 | let y = 1; |
319 | (<|>2 + y<|>, true) | 319 | ($02 + y$0, true) |
320 | } | 320 | } |
321 | _ => (0, false) | 321 | _ => (0, false) |
322 | }; | 322 | }; |
@@ -344,7 +344,7 @@ fn main() { | |||
344 | extract_variable, | 344 | extract_variable, |
345 | " | 345 | " |
346 | fn main() { | 346 | fn main() { |
347 | let lambda = |x: u32| <|>x * 2<|>; | 347 | let lambda = |x: u32| $0x * 2$0; |
348 | } | 348 | } |
349 | ", | 349 | ", |
350 | " | 350 | " |
@@ -361,7 +361,7 @@ fn main() { | |||
361 | extract_variable, | 361 | extract_variable, |
362 | " | 362 | " |
363 | fn main() { | 363 | fn main() { |
364 | let lambda = |x: u32| { <|>x * 2<|> }; | 364 | let lambda = |x: u32| { $0x * 2$0 }; |
365 | } | 365 | } |
366 | ", | 366 | ", |
367 | " | 367 | " |
@@ -378,7 +378,7 @@ fn main() { | |||
378 | extract_variable, | 378 | extract_variable, |
379 | " | 379 | " |
380 | fn main() { | 380 | fn main() { |
381 | let o = <|>Some(true)<|>; | 381 | let o = $0Some(true)$0; |
382 | } | 382 | } |
383 | ", | 383 | ", |
384 | " | 384 | " |
@@ -396,7 +396,7 @@ fn main() { | |||
396 | extract_variable, | 396 | extract_variable, |
397 | " | 397 | " |
398 | fn main() { | 398 | fn main() { |
399 | let v = <|>bar.foo()<|>; | 399 | let v = $0bar.foo()$0; |
400 | } | 400 | } |
401 | ", | 401 | ", |
402 | " | 402 | " |
@@ -414,7 +414,7 @@ fn main() { | |||
414 | extract_variable, | 414 | extract_variable, |
415 | " | 415 | " |
416 | fn foo() -> u32 { | 416 | fn foo() -> u32 { |
417 | <|>return 2 + 2<|>; | 417 | $0return 2 + 2$0; |
418 | } | 418 | } |
419 | ", | 419 | ", |
420 | " | 420 | " |
@@ -434,7 +434,7 @@ fn foo() -> u32 { | |||
434 | fn foo() -> u32 { | 434 | fn foo() -> u32 { |
435 | 435 | ||
436 | 436 | ||
437 | <|>return 2 + 2<|>; | 437 | $0return 2 + 2$0; |
438 | } | 438 | } |
439 | ", | 439 | ", |
440 | " | 440 | " |
@@ -452,7 +452,7 @@ fn foo() -> u32 { | |||
452 | " | 452 | " |
453 | fn foo() -> u32 { | 453 | fn foo() -> u32 { |
454 | 454 | ||
455 | <|>return 2 + 2<|>; | 455 | $0return 2 + 2$0; |
456 | } | 456 | } |
457 | ", | 457 | ", |
458 | " | 458 | " |
@@ -473,7 +473,7 @@ fn foo() -> u32 { | |||
473 | // bar | 473 | // bar |
474 | 474 | ||
475 | 475 | ||
476 | <|>return 2 + 2<|>; | 476 | $0return 2 + 2$0; |
477 | } | 477 | } |
478 | ", | 478 | ", |
479 | " | 479 | " |
@@ -497,7 +497,7 @@ fn foo() -> u32 { | |||
497 | " | 497 | " |
498 | fn main() { | 498 | fn main() { |
499 | let result = loop { | 499 | let result = loop { |
500 | <|>break 2 + 2<|>; | 500 | $0break 2 + 2$0; |
501 | }; | 501 | }; |
502 | } | 502 | } |
503 | ", | 503 | ", |
@@ -518,7 +518,7 @@ fn main() { | |||
518 | extract_variable, | 518 | extract_variable, |
519 | " | 519 | " |
520 | fn main() { | 520 | fn main() { |
521 | let v = <|>0f32 as u32<|>; | 521 | let v = $00f32 as u32$0; |
522 | } | 522 | } |
523 | ", | 523 | ", |
524 | " | 524 | " |
@@ -540,7 +540,7 @@ struct S { | |||
540 | } | 540 | } |
541 | 541 | ||
542 | fn main() { | 542 | fn main() { |
543 | S { foo: <|>1 + 1<|> } | 543 | S { foo: $01 + 1$0 } |
544 | } | 544 | } |
545 | "#, | 545 | "#, |
546 | r#" | 546 | r#" |
@@ -558,18 +558,18 @@ fn main() { | |||
558 | 558 | ||
559 | #[test] | 559 | #[test] |
560 | fn test_extract_var_for_return_not_applicable() { | 560 | fn test_extract_var_for_return_not_applicable() { |
561 | check_assist_not_applicable(extract_variable, "fn foo() { <|>return<|>; } "); | 561 | check_assist_not_applicable(extract_variable, "fn foo() { $0return$0; } "); |
562 | } | 562 | } |
563 | 563 | ||
564 | #[test] | 564 | #[test] |
565 | fn test_extract_var_for_break_not_applicable() { | 565 | fn test_extract_var_for_break_not_applicable() { |
566 | check_assist_not_applicable(extract_variable, "fn main() { loop { <|>break<|>; }; }"); | 566 | check_assist_not_applicable(extract_variable, "fn main() { loop { $0break$0; }; }"); |
567 | } | 567 | } |
568 | 568 | ||
569 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic | 569 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic |
570 | #[test] | 570 | #[test] |
571 | fn extract_var_target() { | 571 | fn extract_var_target() { |
572 | check_assist_target(extract_variable, "fn foo() -> u32 { <|>return 2 + 2<|>; }", "2 + 2"); | 572 | check_assist_target(extract_variable, "fn foo() -> u32 { $0return 2 + 2$0; }", "2 + 2"); |
573 | 573 | ||
574 | check_assist_target( | 574 | check_assist_target( |
575 | extract_variable, | 575 | extract_variable, |
@@ -577,7 +577,7 @@ fn main() { | |||
577 | fn main() { | 577 | fn main() { |
578 | let x = true; | 578 | let x = true; |
579 | let tuple = match x { | 579 | let tuple = match x { |
580 | true => (<|>2 + 2<|>, true) | 580 | true => ($02 + 2$0, true) |
581 | _ => (0, false) | 581 | _ => (0, false) |
582 | }; | 582 | }; |
583 | } | 583 | } |
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs index cb60a3128..da47187e4 100644 --- a/crates/assists/src/handlers/fill_match_arms.rs +++ b/crates/assists/src/handlers/fill_match_arms.rs | |||
@@ -21,7 +21,7 @@ use crate::{ | |||
21 | // | 21 | // |
22 | // fn handle(action: Action) { | 22 | // fn handle(action: Action) { |
23 | // match action { | 23 | // match action { |
24 | // <|> | 24 | // $0 |
25 | // } | 25 | // } |
26 | // } | 26 | // } |
27 | // ``` | 27 | // ``` |
@@ -196,7 +196,7 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio | |||
196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); | 196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); |
197 | 197 | ||
198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
199 | let pat: ast::Pat = match var.source(db).value.kind() { | 199 | let pat: ast::Pat = match var.source(db)?.value.kind() { |
200 | ast::StructKind::Tuple(field_list) => { | 200 | ast::StructKind::Tuple(field_list) => { |
201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); | 201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); |
202 | make::tuple_struct_pat(path, pats).into() | 202 | make::tuple_struct_pat(path, pats).into() |
@@ -231,7 +231,7 @@ mod tests { | |||
231 | Cs(i32, Option<i32>), | 231 | Cs(i32, Option<i32>), |
232 | } | 232 | } |
233 | fn main() { | 233 | fn main() { |
234 | match A::As<|> { | 234 | match A::As$0 { |
235 | A::As, | 235 | A::As, |
236 | A::Bs{x,y:Some(_)} => {} | 236 | A::Bs{x,y:Some(_)} => {} |
237 | A::Cs(_, Some(_)) => {} | 237 | A::Cs(_, Some(_)) => {} |
@@ -249,7 +249,7 @@ mod tests { | |||
249 | fill_match_arms, | 249 | fill_match_arms, |
250 | r#" | 250 | r#" |
251 | fn main() { | 251 | fn main() { |
252 | match (0, false)<|> { | 252 | match (0, false)$0 { |
253 | } | 253 | } |
254 | } | 254 | } |
255 | "#, | 255 | "#, |
@@ -267,7 +267,7 @@ mod tests { | |||
267 | Cs(i32, Option<i32>), | 267 | Cs(i32, Option<i32>), |
268 | } | 268 | } |
269 | fn main() { | 269 | fn main() { |
270 | match A::As<|> { | 270 | match A::As$0 { |
271 | A::Bs { x, y: Some(_) } => {} | 271 | A::Bs { x, y: Some(_) } => {} |
272 | A::Cs(_, Some(_)) => {} | 272 | A::Cs(_, Some(_)) => {} |
273 | } | 273 | } |
@@ -297,7 +297,7 @@ mod tests { | |||
297 | r#" | 297 | r#" |
298 | enum A { As, Bs, Cs(Option<i32>) } | 298 | enum A { As, Bs, Cs(Option<i32>) } |
299 | fn main() { | 299 | fn main() { |
300 | match A::As<|> { | 300 | match A::As$0 { |
301 | A::Cs(_) | A::Bs => {} | 301 | A::Cs(_) | A::Bs => {} |
302 | } | 302 | } |
303 | } | 303 | } |
@@ -322,7 +322,7 @@ fn main() { | |||
322 | enum A { As, Bs, Cs, Ds(String), Es(B) } | 322 | enum A { As, Bs, Cs, Ds(String), Es(B) } |
323 | enum B { Xs, Ys } | 323 | enum B { Xs, Ys } |
324 | fn main() { | 324 | fn main() { |
325 | match A::As<|> { | 325 | match A::As$0 { |
326 | A::Bs if 0 < 1 => {} | 326 | A::Bs if 0 < 1 => {} |
327 | A::Ds(_value) => { let x = 1; } | 327 | A::Ds(_value) => { let x = 1; } |
328 | A::Es(B::Xs) => (), | 328 | A::Es(B::Xs) => (), |
@@ -352,7 +352,7 @@ fn main() { | |||
352 | r#" | 352 | r#" |
353 | enum A { As, Bs, Cs(Option<i32>) } | 353 | enum A { As, Bs, Cs(Option<i32>) } |
354 | fn main() { | 354 | fn main() { |
355 | match A::As<|> { | 355 | match A::As$0 { |
356 | A::As(_) => {} | 356 | A::As(_) => {} |
357 | a @ A::Bs(_) => {} | 357 | a @ A::Bs(_) => {} |
358 | } | 358 | } |
@@ -380,7 +380,7 @@ enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } } | |||
380 | 380 | ||
381 | fn main() { | 381 | fn main() { |
382 | let a = A::As; | 382 | let a = A::As; |
383 | match a<|> {} | 383 | match a$0 {} |
384 | } | 384 | } |
385 | "#, | 385 | "#, |
386 | r#" | 386 | r#" |
@@ -411,7 +411,7 @@ fn main() { | |||
411 | fn main() { | 411 | fn main() { |
412 | let a = A::One; | 412 | let a = A::One; |
413 | let b = B::One; | 413 | let b = B::One; |
414 | match (a<|>, b) {} | 414 | match (a$0, b) {} |
415 | } | 415 | } |
416 | "#, | 416 | "#, |
417 | r#" | 417 | r#" |
@@ -443,7 +443,7 @@ fn main() { | |||
443 | fn main() { | 443 | fn main() { |
444 | let a = A::One; | 444 | let a = A::One; |
445 | let b = B::One; | 445 | let b = B::One; |
446 | match (&a<|>, &b) {} | 446 | match (&a$0, &b) {} |
447 | } | 447 | } |
448 | "#, | 448 | "#, |
449 | r#" | 449 | r#" |
@@ -475,7 +475,7 @@ fn main() { | |||
475 | fn main() { | 475 | fn main() { |
476 | let a = A::One; | 476 | let a = A::One; |
477 | let b = B::One; | 477 | let b = B::One; |
478 | match (a<|>, b) { | 478 | match (a$0, b) { |
479 | (A::Two, B::One) => {} | 479 | (A::Two, B::One) => {} |
480 | } | 480 | } |
481 | } | 481 | } |
@@ -494,7 +494,7 @@ fn main() { | |||
494 | fn main() { | 494 | fn main() { |
495 | let a = A::One; | 495 | let a = A::One; |
496 | let b = B::One; | 496 | let b = B::One; |
497 | match (a<|>, b) { | 497 | match (a$0, b) { |
498 | (A::Two, B::One) => {} | 498 | (A::Two, B::One) => {} |
499 | (A::One, B::One) => {} | 499 | (A::One, B::One) => {} |
500 | (A::One, B::Two) => {} | 500 | (A::One, B::Two) => {} |
@@ -517,7 +517,7 @@ fn main() { | |||
517 | 517 | ||
518 | fn main() { | 518 | fn main() { |
519 | let a = A::One; | 519 | let a = A::One; |
520 | match (a<|>, ) { | 520 | match (a$0, ) { |
521 | } | 521 | } |
522 | } | 522 | } |
523 | "#, | 523 | "#, |
@@ -532,7 +532,7 @@ fn main() { | |||
532 | enum A { As } | 532 | enum A { As } |
533 | 533 | ||
534 | fn foo(a: &A) { | 534 | fn foo(a: &A) { |
535 | match a<|> { | 535 | match a$0 { |
536 | } | 536 | } |
537 | } | 537 | } |
538 | "#, | 538 | "#, |
@@ -555,7 +555,7 @@ fn main() { | |||
555 | } | 555 | } |
556 | 556 | ||
557 | fn foo(a: &mut A) { | 557 | fn foo(a: &mut A) { |
558 | match a<|> { | 558 | match a$0 { |
559 | } | 559 | } |
560 | } | 560 | } |
561 | "#, | 561 | "#, |
@@ -581,7 +581,7 @@ fn main() { | |||
581 | enum E { X, Y } | 581 | enum E { X, Y } |
582 | 582 | ||
583 | fn main() { | 583 | fn main() { |
584 | match E::X<|> {} | 584 | match E::X$0 {} |
585 | } | 585 | } |
586 | "#, | 586 | "#, |
587 | "match E::X {}", | 587 | "match E::X {}", |
@@ -597,7 +597,7 @@ fn main() { | |||
597 | 597 | ||
598 | fn main() { | 598 | fn main() { |
599 | match E::X { | 599 | match E::X { |
600 | <|>_ => {} | 600 | $0_ => {} |
601 | } | 601 | } |
602 | } | 602 | } |
603 | "#, | 603 | "#, |
@@ -624,7 +624,7 @@ fn main() { | |||
624 | 624 | ||
625 | fn main() { | 625 | fn main() { |
626 | match X { | 626 | match X { |
627 | <|> | 627 | $0 |
628 | } | 628 | } |
629 | } | 629 | } |
630 | "#, | 630 | "#, |
@@ -650,7 +650,7 @@ fn main() { | |||
650 | enum A { One, Two } | 650 | enum A { One, Two } |
651 | fn foo(a: A) { | 651 | fn foo(a: A) { |
652 | match a { | 652 | match a { |
653 | // foo bar baz<|> | 653 | // foo bar baz$0 |
654 | A::One => {} | 654 | A::One => {} |
655 | // This is where the rest should be | 655 | // This is where the rest should be |
656 | } | 656 | } |
@@ -678,7 +678,7 @@ fn main() { | |||
678 | enum A { One, Two } | 678 | enum A { One, Two } |
679 | fn foo(a: A) { | 679 | fn foo(a: A) { |
680 | match a { | 680 | match a { |
681 | // foo bar baz<|> | 681 | // foo bar baz$0 |
682 | } | 682 | } |
683 | } | 683 | } |
684 | "#, | 684 | "#, |
@@ -702,7 +702,7 @@ fn main() { | |||
702 | r#" | 702 | r#" |
703 | enum A { One, Two, } | 703 | enum A { One, Two, } |
704 | fn foo(a: A) { | 704 | fn foo(a: A) { |
705 | match a<|> { | 705 | match a$0 { |
706 | _ => (), | 706 | _ => (), |
707 | } | 707 | } |
708 | } | 708 | } |
@@ -724,7 +724,7 @@ fn main() { | |||
724 | mark::check!(option_order); | 724 | mark::check!(option_order); |
725 | let before = r#" | 725 | let before = r#" |
726 | fn foo(opt: Option<i32>) { | 726 | fn foo(opt: Option<i32>) { |
727 | match opt<|> { | 727 | match opt$0 { |
728 | } | 728 | } |
729 | } | 729 | } |
730 | "#; | 730 | "#; |
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs index 8558a8ff0..6c7824e55 100644 --- a/crates/assists/src/handlers/fix_visibility.rs +++ b/crates/assists/src/handlers/fix_visibility.rs | |||
@@ -18,7 +18,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; | |||
18 | // fn frobnicate() {} | 18 | // fn frobnicate() {} |
19 | // } | 19 | // } |
20 | // fn main() { | 20 | // fn main() { |
21 | // m::frobnicate<|>() {} | 21 | // m::frobnicate$0() {} |
22 | // } | 22 | // } |
23 | // ``` | 23 | // ``` |
24 | // -> | 24 | // -> |
@@ -97,7 +97,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> | |||
97 | let parent_name = parent.name(ctx.db()); | 97 | let parent_name = parent.name(ctx.db()); |
98 | let target_module = parent.module(ctx.db()); | 98 | let target_module = parent.module(ctx.db()); |
99 | 99 | ||
100 | let in_file_source = record_field_def.source(ctx.db()); | 100 | let in_file_source = record_field_def.source(ctx.db())?; |
101 | let (offset, current_visibility, target) = match in_file_source.value { | 101 | let (offset, current_visibility, target) = match in_file_source.value { |
102 | hir::FieldSource::Named(it) => { | 102 | hir::FieldSource::Named(it) => { |
103 | let s = it.syntax(); | 103 | let s = it.syntax(); |
@@ -145,53 +145,53 @@ fn target_data_for_def( | |||
145 | fn offset_target_and_file_id<S, Ast>( | 145 | fn offset_target_and_file_id<S, Ast>( |
146 | db: &dyn HirDatabase, | 146 | db: &dyn HirDatabase, |
147 | x: S, | 147 | x: S, |
148 | ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId) | 148 | ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)> |
149 | where | 149 | where |
150 | S: HasSource<Ast = Ast>, | 150 | S: HasSource<Ast = Ast>, |
151 | Ast: AstNode + ast::VisibilityOwner, | 151 | Ast: AstNode + ast::VisibilityOwner, |
152 | { | 152 | { |
153 | let source = x.source(db); | 153 | let source = x.source(db)?; |
154 | let in_file_syntax = source.syntax(); | 154 | let in_file_syntax = source.syntax(); |
155 | let file_id = in_file_syntax.file_id; | 155 | let file_id = in_file_syntax.file_id; |
156 | let syntax = in_file_syntax.value; | 156 | let syntax = in_file_syntax.value; |
157 | let current_visibility = source.value.visibility(); | 157 | let current_visibility = source.value.visibility(); |
158 | ( | 158 | Some(( |
159 | vis_offset(syntax), | 159 | vis_offset(syntax), |
160 | current_visibility, | 160 | current_visibility, |
161 | syntax.text_range(), | 161 | syntax.text_range(), |
162 | file_id.original_file(db.upcast()), | 162 | file_id.original_file(db.upcast()), |
163 | ) | 163 | )) |
164 | } | 164 | } |
165 | 165 | ||
166 | let target_name; | 166 | let target_name; |
167 | let (offset, current_visibility, target, target_file) = match def { | 167 | let (offset, current_visibility, target, target_file) = match def { |
168 | hir::ModuleDef::Function(f) => { | 168 | hir::ModuleDef::Function(f) => { |
169 | target_name = Some(f.name(db)); | 169 | target_name = Some(f.name(db)); |
170 | offset_target_and_file_id(db, f) | 170 | offset_target_and_file_id(db, f)? |
171 | } | 171 | } |
172 | hir::ModuleDef::Adt(adt) => { | 172 | hir::ModuleDef::Adt(adt) => { |
173 | target_name = Some(adt.name(db)); | 173 | target_name = Some(adt.name(db)); |
174 | match adt { | 174 | match adt { |
175 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s), | 175 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?, |
176 | hir::Adt::Union(u) => offset_target_and_file_id(db, u), | 176 | hir::Adt::Union(u) => offset_target_and_file_id(db, u)?, |
177 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e), | 177 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?, |
178 | } | 178 | } |
179 | } | 179 | } |
180 | hir::ModuleDef::Const(c) => { | 180 | hir::ModuleDef::Const(c) => { |
181 | target_name = c.name(db); | 181 | target_name = c.name(db); |
182 | offset_target_and_file_id(db, c) | 182 | offset_target_and_file_id(db, c)? |
183 | } | 183 | } |
184 | hir::ModuleDef::Static(s) => { | 184 | hir::ModuleDef::Static(s) => { |
185 | target_name = s.name(db); | 185 | target_name = s.name(db); |
186 | offset_target_and_file_id(db, s) | 186 | offset_target_and_file_id(db, s)? |
187 | } | 187 | } |
188 | hir::ModuleDef::Trait(t) => { | 188 | hir::ModuleDef::Trait(t) => { |
189 | target_name = Some(t.name(db)); | 189 | target_name = Some(t.name(db)); |
190 | offset_target_and_file_id(db, t) | 190 | offset_target_and_file_id(db, t)? |
191 | } | 191 | } |
192 | hir::ModuleDef::TypeAlias(t) => { | 192 | hir::ModuleDef::TypeAlias(t) => { |
193 | target_name = Some(t.name(db)); | 193 | target_name = Some(t.name(db)); |
194 | offset_target_and_file_id(db, t) | 194 | offset_target_and_file_id(db, t)? |
195 | } | 195 | } |
196 | hir::ModuleDef::Module(m) => { | 196 | hir::ModuleDef::Module(m) => { |
197 | target_name = m.name(db); | 197 | target_name = m.name(db); |
@@ -218,14 +218,14 @@ mod tests { | |||
218 | check_assist( | 218 | check_assist( |
219 | fix_visibility, | 219 | fix_visibility, |
220 | r"mod foo { fn foo() {} } | 220 | r"mod foo { fn foo() {} } |
221 | fn main() { foo::foo<|>() } ", | 221 | fn main() { foo::foo$0() } ", |
222 | r"mod foo { $0pub(crate) fn foo() {} } | 222 | r"mod foo { $0pub(crate) fn foo() {} } |
223 | fn main() { foo::foo() } ", | 223 | fn main() { foo::foo() } ", |
224 | ); | 224 | ); |
225 | check_assist_not_applicable( | 225 | check_assist_not_applicable( |
226 | fix_visibility, | 226 | fix_visibility, |
227 | r"mod foo { pub fn foo() {} } | 227 | r"mod foo { pub fn foo() {} } |
228 | fn main() { foo::foo<|>() } ", | 228 | fn main() { foo::foo$0() } ", |
229 | ) | 229 | ) |
230 | } | 230 | } |
231 | 231 | ||
@@ -234,38 +234,38 @@ mod tests { | |||
234 | check_assist( | 234 | check_assist( |
235 | fix_visibility, | 235 | fix_visibility, |
236 | r"mod foo { struct Foo; } | 236 | r"mod foo { struct Foo; } |
237 | fn main() { foo::Foo<|> } ", | 237 | fn main() { foo::Foo$0 } ", |
238 | r"mod foo { $0pub(crate) struct Foo; } | 238 | r"mod foo { $0pub(crate) struct Foo; } |
239 | fn main() { foo::Foo } ", | 239 | fn main() { foo::Foo } ", |
240 | ); | 240 | ); |
241 | check_assist_not_applicable( | 241 | check_assist_not_applicable( |
242 | fix_visibility, | 242 | fix_visibility, |
243 | r"mod foo { pub struct Foo; } | 243 | r"mod foo { pub struct Foo; } |
244 | fn main() { foo::Foo<|> } ", | 244 | fn main() { foo::Foo$0 } ", |
245 | ); | 245 | ); |
246 | check_assist( | 246 | check_assist( |
247 | fix_visibility, | 247 | fix_visibility, |
248 | r"mod foo { enum Foo; } | 248 | r"mod foo { enum Foo; } |
249 | fn main() { foo::Foo<|> } ", | 249 | fn main() { foo::Foo$0 } ", |
250 | r"mod foo { $0pub(crate) enum Foo; } | 250 | r"mod foo { $0pub(crate) enum Foo; } |
251 | fn main() { foo::Foo } ", | 251 | fn main() { foo::Foo } ", |
252 | ); | 252 | ); |
253 | check_assist_not_applicable( | 253 | check_assist_not_applicable( |
254 | fix_visibility, | 254 | fix_visibility, |
255 | r"mod foo { pub enum Foo; } | 255 | r"mod foo { pub enum Foo; } |
256 | fn main() { foo::Foo<|> } ", | 256 | fn main() { foo::Foo$0 } ", |
257 | ); | 257 | ); |
258 | check_assist( | 258 | check_assist( |
259 | fix_visibility, | 259 | fix_visibility, |
260 | r"mod foo { union Foo; } | 260 | r"mod foo { union Foo; } |
261 | fn main() { foo::Foo<|> } ", | 261 | fn main() { foo::Foo$0 } ", |
262 | r"mod foo { $0pub(crate) union Foo; } | 262 | r"mod foo { $0pub(crate) union Foo; } |
263 | fn main() { foo::Foo } ", | 263 | fn main() { foo::Foo } ", |
264 | ); | 264 | ); |
265 | check_assist_not_applicable( | 265 | check_assist_not_applicable( |
266 | fix_visibility, | 266 | fix_visibility, |
267 | r"mod foo { pub union Foo; } | 267 | r"mod foo { pub union Foo; } |
268 | fn main() { foo::Foo<|> } ", | 268 | fn main() { foo::Foo$0 } ", |
269 | ); | 269 | ); |
270 | } | 270 | } |
271 | 271 | ||
@@ -276,7 +276,7 @@ mod tests { | |||
276 | r" | 276 | r" |
277 | //- /main.rs | 277 | //- /main.rs |
278 | mod foo; | 278 | mod foo; |
279 | fn main() { foo::Foo<|> } | 279 | fn main() { foo::Foo$0 } |
280 | 280 | ||
281 | //- /foo.rs | 281 | //- /foo.rs |
282 | struct Foo; | 282 | struct Foo; |
@@ -291,7 +291,7 @@ struct Foo; | |||
291 | check_assist( | 291 | check_assist( |
292 | fix_visibility, | 292 | fix_visibility, |
293 | r"mod foo { pub struct Foo { bar: (), } } | 293 | r"mod foo { pub struct Foo { bar: (), } } |
294 | fn main() { foo::Foo { <|>bar: () }; } ", | 294 | fn main() { foo::Foo { $0bar: () }; } ", |
295 | r"mod foo { pub struct Foo { $0pub(crate) bar: (), } } | 295 | r"mod foo { pub struct Foo { $0pub(crate) bar: (), } } |
296 | fn main() { foo::Foo { bar: () }; } ", | 296 | fn main() { foo::Foo { bar: () }; } ", |
297 | ); | 297 | ); |
@@ -300,7 +300,7 @@ struct Foo; | |||
300 | r" | 300 | r" |
301 | //- /lib.rs | 301 | //- /lib.rs |
302 | mod foo; | 302 | mod foo; |
303 | fn main() { foo::Foo { <|>bar: () }; } | 303 | fn main() { foo::Foo { $0bar: () }; } |
304 | //- /foo.rs | 304 | //- /foo.rs |
305 | pub struct Foo { bar: () } | 305 | pub struct Foo { bar: () } |
306 | ", | 306 | ", |
@@ -310,14 +310,14 @@ pub struct Foo { bar: () } | |||
310 | check_assist_not_applicable( | 310 | check_assist_not_applicable( |
311 | fix_visibility, | 311 | fix_visibility, |
312 | r"mod foo { pub struct Foo { pub bar: (), } } | 312 | r"mod foo { pub struct Foo { pub bar: (), } } |
313 | fn main() { foo::Foo { <|>bar: () }; } ", | 313 | fn main() { foo::Foo { $0bar: () }; } ", |
314 | ); | 314 | ); |
315 | check_assist_not_applicable( | 315 | check_assist_not_applicable( |
316 | fix_visibility, | 316 | fix_visibility, |
317 | r" | 317 | r" |
318 | //- /lib.rs | 318 | //- /lib.rs |
319 | mod foo; | 319 | mod foo; |
320 | fn main() { foo::Foo { <|>bar: () }; } | 320 | fn main() { foo::Foo { $0bar: () }; } |
321 | //- /foo.rs | 321 | //- /foo.rs |
322 | pub struct Foo { pub bar: () } | 322 | pub struct Foo { pub bar: () } |
323 | ", | 323 | ", |
@@ -331,14 +331,14 @@ pub struct Foo { pub bar: () } | |||
331 | check_assist_not_applicable( | 331 | check_assist_not_applicable( |
332 | fix_visibility, | 332 | fix_visibility, |
333 | r"mod foo { pub enum Foo { Bar { bar: () } } } | 333 | r"mod foo { pub enum Foo { Bar { bar: () } } } |
334 | fn main() { foo::Foo::Bar { <|>bar: () }; } ", | 334 | fn main() { foo::Foo::Bar { $0bar: () }; } ", |
335 | ); | 335 | ); |
336 | check_assist_not_applicable( | 336 | check_assist_not_applicable( |
337 | fix_visibility, | 337 | fix_visibility, |
338 | r" | 338 | r" |
339 | //- /lib.rs | 339 | //- /lib.rs |
340 | mod foo; | 340 | mod foo; |
341 | fn main() { foo::Foo::Bar { <|>bar: () }; } | 341 | fn main() { foo::Foo::Bar { $0bar: () }; } |
342 | //- /foo.rs | 342 | //- /foo.rs |
343 | pub enum Foo { Bar { bar: () } } | 343 | pub enum Foo { Bar { bar: () } } |
344 | ", | 344 | ", |
@@ -346,14 +346,14 @@ pub enum Foo { Bar { bar: () } } | |||
346 | check_assist_not_applicable( | 346 | check_assist_not_applicable( |
347 | fix_visibility, | 347 | fix_visibility, |
348 | r"mod foo { pub struct Foo { pub bar: (), } } | 348 | r"mod foo { pub struct Foo { pub bar: (), } } |
349 | fn main() { foo::Foo { <|>bar: () }; } ", | 349 | fn main() { foo::Foo { $0bar: () }; } ", |
350 | ); | 350 | ); |
351 | check_assist_not_applicable( | 351 | check_assist_not_applicable( |
352 | fix_visibility, | 352 | fix_visibility, |
353 | r" | 353 | r" |
354 | //- /lib.rs | 354 | //- /lib.rs |
355 | mod foo; | 355 | mod foo; |
356 | fn main() { foo::Foo { <|>bar: () }; } | 356 | fn main() { foo::Foo { $0bar: () }; } |
357 | //- /foo.rs | 357 | //- /foo.rs |
358 | pub struct Foo { pub bar: () } | 358 | pub struct Foo { pub bar: () } |
359 | ", | 359 | ", |
@@ -367,7 +367,7 @@ pub struct Foo { pub bar: () } | |||
367 | check_assist( | 367 | check_assist( |
368 | fix_visibility, | 368 | fix_visibility, |
369 | r"mod foo { pub union Foo { bar: (), } } | 369 | r"mod foo { pub union Foo { bar: (), } } |
370 | fn main() { foo::Foo { <|>bar: () }; } ", | 370 | fn main() { foo::Foo { $0bar: () }; } ", |
371 | r"mod foo { pub union Foo { $0pub(crate) bar: (), } } | 371 | r"mod foo { pub union Foo { $0pub(crate) bar: (), } } |
372 | fn main() { foo::Foo { bar: () }; } ", | 372 | fn main() { foo::Foo { bar: () }; } ", |
373 | ); | 373 | ); |
@@ -376,7 +376,7 @@ pub struct Foo { pub bar: () } | |||
376 | r" | 376 | r" |
377 | //- /lib.rs | 377 | //- /lib.rs |
378 | mod foo; | 378 | mod foo; |
379 | fn main() { foo::Foo { <|>bar: () }; } | 379 | fn main() { foo::Foo { $0bar: () }; } |
380 | //- /foo.rs | 380 | //- /foo.rs |
381 | pub union Foo { bar: () } | 381 | pub union Foo { bar: () } |
382 | ", | 382 | ", |
@@ -386,14 +386,14 @@ pub union Foo { bar: () } | |||
386 | check_assist_not_applicable( | 386 | check_assist_not_applicable( |
387 | fix_visibility, | 387 | fix_visibility, |
388 | r"mod foo { pub union Foo { pub bar: (), } } | 388 | r"mod foo { pub union Foo { pub bar: (), } } |
389 | fn main() { foo::Foo { <|>bar: () }; } ", | 389 | fn main() { foo::Foo { $0bar: () }; } ", |
390 | ); | 390 | ); |
391 | check_assist_not_applicable( | 391 | check_assist_not_applicable( |
392 | fix_visibility, | 392 | fix_visibility, |
393 | r" | 393 | r" |
394 | //- /lib.rs | 394 | //- /lib.rs |
395 | mod foo; | 395 | mod foo; |
396 | fn main() { foo::Foo { <|>bar: () }; } | 396 | fn main() { foo::Foo { $0bar: () }; } |
397 | //- /foo.rs | 397 | //- /foo.rs |
398 | pub union Foo { pub bar: () } | 398 | pub union Foo { pub bar: () } |
399 | ", | 399 | ", |
@@ -405,14 +405,14 @@ pub union Foo { pub bar: () } | |||
405 | check_assist( | 405 | check_assist( |
406 | fix_visibility, | 406 | fix_visibility, |
407 | r"mod foo { const FOO: () = (); } | 407 | r"mod foo { const FOO: () = (); } |
408 | fn main() { foo::FOO<|> } ", | 408 | fn main() { foo::FOO$0 } ", |
409 | r"mod foo { $0pub(crate) const FOO: () = (); } | 409 | r"mod foo { $0pub(crate) const FOO: () = (); } |
410 | fn main() { foo::FOO } ", | 410 | fn main() { foo::FOO } ", |
411 | ); | 411 | ); |
412 | check_assist_not_applicable( | 412 | check_assist_not_applicable( |
413 | fix_visibility, | 413 | fix_visibility, |
414 | r"mod foo { pub const FOO: () = (); } | 414 | r"mod foo { pub const FOO: () = (); } |
415 | fn main() { foo::FOO<|> } ", | 415 | fn main() { foo::FOO$0 } ", |
416 | ); | 416 | ); |
417 | } | 417 | } |
418 | 418 | ||
@@ -421,14 +421,14 @@ pub union Foo { pub bar: () } | |||
421 | check_assist( | 421 | check_assist( |
422 | fix_visibility, | 422 | fix_visibility, |
423 | r"mod foo { static FOO: () = (); } | 423 | r"mod foo { static FOO: () = (); } |
424 | fn main() { foo::FOO<|> } ", | 424 | fn main() { foo::FOO$0 } ", |
425 | r"mod foo { $0pub(crate) static FOO: () = (); } | 425 | r"mod foo { $0pub(crate) static FOO: () = (); } |
426 | fn main() { foo::FOO } ", | 426 | fn main() { foo::FOO } ", |
427 | ); | 427 | ); |
428 | check_assist_not_applicable( | 428 | check_assist_not_applicable( |
429 | fix_visibility, | 429 | fix_visibility, |
430 | r"mod foo { pub static FOO: () = (); } | 430 | r"mod foo { pub static FOO: () = (); } |
431 | fn main() { foo::FOO<|> } ", | 431 | fn main() { foo::FOO$0 } ", |
432 | ); | 432 | ); |
433 | } | 433 | } |
434 | 434 | ||
@@ -437,14 +437,14 @@ pub union Foo { pub bar: () } | |||
437 | check_assist( | 437 | check_assist( |
438 | fix_visibility, | 438 | fix_visibility, |
439 | r"mod foo { trait Foo { fn foo(&self) {} } } | 439 | r"mod foo { trait Foo { fn foo(&self) {} } } |
440 | fn main() { let x: &dyn foo::<|>Foo; } ", | 440 | fn main() { let x: &dyn foo::$0Foo; } ", |
441 | r"mod foo { $0pub(crate) trait Foo { fn foo(&self) {} } } | 441 | r"mod foo { $0pub(crate) trait Foo { fn foo(&self) {} } } |
442 | fn main() { let x: &dyn foo::Foo; } ", | 442 | fn main() { let x: &dyn foo::Foo; } ", |
443 | ); | 443 | ); |
444 | check_assist_not_applicable( | 444 | check_assist_not_applicable( |
445 | fix_visibility, | 445 | fix_visibility, |
446 | r"mod foo { pub trait Foo { fn foo(&self) {} } } | 446 | r"mod foo { pub trait Foo { fn foo(&self) {} } } |
447 | fn main() { let x: &dyn foo::Foo<|>; } ", | 447 | fn main() { let x: &dyn foo::Foo$0; } ", |
448 | ); | 448 | ); |
449 | } | 449 | } |
450 | 450 | ||
@@ -453,14 +453,14 @@ pub union Foo { pub bar: () } | |||
453 | check_assist( | 453 | check_assist( |
454 | fix_visibility, | 454 | fix_visibility, |
455 | r"mod foo { type Foo = (); } | 455 | r"mod foo { type Foo = (); } |
456 | fn main() { let x: foo::Foo<|>; } ", | 456 | fn main() { let x: foo::Foo$0; } ", |
457 | r"mod foo { $0pub(crate) type Foo = (); } | 457 | r"mod foo { $0pub(crate) type Foo = (); } |
458 | fn main() { let x: foo::Foo; } ", | 458 | fn main() { let x: foo::Foo; } ", |
459 | ); | 459 | ); |
460 | check_assist_not_applicable( | 460 | check_assist_not_applicable( |
461 | fix_visibility, | 461 | fix_visibility, |
462 | r"mod foo { pub type Foo = (); } | 462 | r"mod foo { pub type Foo = (); } |
463 | fn main() { let x: foo::Foo<|>; } ", | 463 | fn main() { let x: foo::Foo$0; } ", |
464 | ); | 464 | ); |
465 | } | 465 | } |
466 | 466 | ||
@@ -469,7 +469,7 @@ pub union Foo { pub bar: () } | |||
469 | check_assist( | 469 | check_assist( |
470 | fix_visibility, | 470 | fix_visibility, |
471 | r"mod foo { mod bar { fn bar() {} } } | 471 | r"mod foo { mod bar { fn bar() {} } } |
472 | fn main() { foo::bar<|>::bar(); } ", | 472 | fn main() { foo::bar$0::bar(); } ", |
473 | r"mod foo { $0pub(crate) mod bar { fn bar() {} } } | 473 | r"mod foo { $0pub(crate) mod bar { fn bar() {} } } |
474 | fn main() { foo::bar::bar(); } ", | 474 | fn main() { foo::bar::bar(); } ", |
475 | ); | 475 | ); |
@@ -479,7 +479,7 @@ pub union Foo { pub bar: () } | |||
479 | r" | 479 | r" |
480 | //- /main.rs | 480 | //- /main.rs |
481 | mod foo; | 481 | mod foo; |
482 | fn main() { foo::bar<|>::baz(); } | 482 | fn main() { foo::bar$0::baz(); } |
483 | 483 | ||
484 | //- /foo.rs | 484 | //- /foo.rs |
485 | mod bar { | 485 | mod bar { |
@@ -495,7 +495,7 @@ mod bar { | |||
495 | check_assist_not_applicable( | 495 | check_assist_not_applicable( |
496 | fix_visibility, | 496 | fix_visibility, |
497 | r"mod foo { pub mod bar { pub fn bar() {} } } | 497 | r"mod foo { pub mod bar { pub fn bar() {} } } |
498 | fn main() { foo::bar<|>::bar(); } ", | 498 | fn main() { foo::bar$0::bar(); } ", |
499 | ); | 499 | ); |
500 | } | 500 | } |
501 | 501 | ||
@@ -506,7 +506,7 @@ mod bar { | |||
506 | r" | 506 | r" |
507 | //- /main.rs | 507 | //- /main.rs |
508 | mod foo; | 508 | mod foo; |
509 | fn main() { foo::bar<|>::baz(); } | 509 | fn main() { foo::bar$0::baz(); } |
510 | 510 | ||
511 | //- /foo.rs | 511 | //- /foo.rs |
512 | mod bar; | 512 | mod bar; |
@@ -525,7 +525,7 @@ pub fn baz() {} | |||
525 | r" | 525 | r" |
526 | //- /main.rs | 526 | //- /main.rs |
527 | mod foo; | 527 | mod foo; |
528 | fn main() { foo::bar<|>>::baz(); } | 528 | fn main() { foo::bar$0>::baz(); } |
529 | 529 | ||
530 | //- /foo.rs | 530 | //- /foo.rs |
531 | mod bar { | 531 | mod bar { |
@@ -545,7 +545,7 @@ mod bar { | |||
545 | fix_visibility, | 545 | fix_visibility, |
546 | r" | 546 | r" |
547 | //- /main.rs crate:a deps:foo | 547 | //- /main.rs crate:a deps:foo |
548 | foo::Bar<|> | 548 | foo::Bar$0 |
549 | //- /lib.rs crate:foo | 549 | //- /lib.rs crate:foo |
550 | struct Bar; | 550 | struct Bar; |
551 | ", | 551 | ", |
@@ -560,7 +560,7 @@ struct Bar; | |||
560 | fix_visibility, | 560 | fix_visibility, |
561 | r" | 561 | r" |
562 | //- /main.rs crate:a deps:foo | 562 | //- /main.rs crate:a deps:foo |
563 | foo::Bar<|> | 563 | foo::Bar$0 |
564 | //- /lib.rs crate:foo | 564 | //- /lib.rs crate:foo |
565 | pub(crate) struct Bar; | 565 | pub(crate) struct Bar; |
566 | ", | 566 | ", |
@@ -572,7 +572,7 @@ pub(crate) struct Bar; | |||
572 | r" | 572 | r" |
573 | //- /main.rs crate:a deps:foo | 573 | //- /main.rs crate:a deps:foo |
574 | fn main() { | 574 | fn main() { |
575 | foo::Foo { <|>bar: () }; | 575 | foo::Foo { $0bar: () }; |
576 | } | 576 | } |
577 | //- /lib.rs crate:foo | 577 | //- /lib.rs crate:foo |
578 | pub struct Foo { pub(crate) bar: () } | 578 | pub struct Foo { pub(crate) bar: () } |
@@ -593,7 +593,7 @@ pub struct Foo { pub(crate) bar: () } | |||
593 | use bar::Baz; | 593 | use bar::Baz; |
594 | mod bar { pub(super) struct Baz; } | 594 | mod bar { pub(super) struct Baz; } |
595 | } | 595 | } |
596 | foo::Baz<|> | 596 | foo::Baz$0 |
597 | ", | 597 | ", |
598 | r" | 598 | r" |
599 | mod foo { | 599 | mod foo { |
diff --git a/crates/assists/src/handlers/flip_binexpr.rs b/crates/assists/src/handlers/flip_binexpr.rs index 404f06133..209e5d43c 100644 --- a/crates/assists/src/handlers/flip_binexpr.rs +++ b/crates/assists/src/handlers/flip_binexpr.rs | |||
@@ -8,7 +8,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
8 | // | 8 | // |
9 | // ``` | 9 | // ``` |
10 | // fn main() { | 10 | // fn main() { |
11 | // let _ = 90 +<|> 2; | 11 | // let _ = 90 +$0 2; |
12 | // } | 12 | // } |
13 | // ``` | 13 | // ``` |
14 | // -> | 14 | // -> |
@@ -77,42 +77,34 @@ mod tests { | |||
77 | 77 | ||
78 | #[test] | 78 | #[test] |
79 | fn flip_binexpr_target_is_the_op() { | 79 | fn flip_binexpr_target_is_the_op() { |
80 | check_assist_target(flip_binexpr, "fn f() { let res = 1 ==<|> 2; }", "==") | 80 | check_assist_target(flip_binexpr, "fn f() { let res = 1 ==$0 2; }", "==") |
81 | } | 81 | } |
82 | 82 | ||
83 | #[test] | 83 | #[test] |
84 | fn flip_binexpr_not_applicable_for_assignment() { | 84 | fn flip_binexpr_not_applicable_for_assignment() { |
85 | check_assist_not_applicable(flip_binexpr, "fn f() { let mut _x = 1; _x +=<|> 2 }") | 85 | check_assist_not_applicable(flip_binexpr, "fn f() { let mut _x = 1; _x +=$0 2 }") |
86 | } | 86 | } |
87 | 87 | ||
88 | #[test] | 88 | #[test] |
89 | fn flip_binexpr_works_for_eq() { | 89 | fn flip_binexpr_works_for_eq() { |
90 | check_assist( | 90 | check_assist(flip_binexpr, "fn f() { let res = 1 ==$0 2; }", "fn f() { let res = 2 == 1; }") |
91 | flip_binexpr, | ||
92 | "fn f() { let res = 1 ==<|> 2; }", | ||
93 | "fn f() { let res = 2 == 1; }", | ||
94 | ) | ||
95 | } | 91 | } |
96 | 92 | ||
97 | #[test] | 93 | #[test] |
98 | fn flip_binexpr_works_for_gt() { | 94 | fn flip_binexpr_works_for_gt() { |
99 | check_assist(flip_binexpr, "fn f() { let res = 1 ><|> 2; }", "fn f() { let res = 2 < 1; }") | 95 | check_assist(flip_binexpr, "fn f() { let res = 1 >$0 2; }", "fn f() { let res = 2 < 1; }") |
100 | } | 96 | } |
101 | 97 | ||
102 | #[test] | 98 | #[test] |
103 | fn flip_binexpr_works_for_lteq() { | 99 | fn flip_binexpr_works_for_lteq() { |
104 | check_assist( | 100 | check_assist(flip_binexpr, "fn f() { let res = 1 <=$0 2; }", "fn f() { let res = 2 >= 1; }") |
105 | flip_binexpr, | ||
106 | "fn f() { let res = 1 <=<|> 2; }", | ||
107 | "fn f() { let res = 2 >= 1; }", | ||
108 | ) | ||
109 | } | 101 | } |
110 | 102 | ||
111 | #[test] | 103 | #[test] |
112 | fn flip_binexpr_works_for_complex_expr() { | 104 | fn flip_binexpr_works_for_complex_expr() { |
113 | check_assist( | 105 | check_assist( |
114 | flip_binexpr, | 106 | flip_binexpr, |
115 | "fn f() { let res = (1 + 1) ==<|> (2 + 2); }", | 107 | "fn f() { let res = (1 + 1) ==$0 (2 + 2); }", |
116 | "fn f() { let res = (2 + 2) == (1 + 1); }", | 108 | "fn f() { let res = (2 + 2) == (1 + 1); }", |
117 | ) | 109 | ) |
118 | } | 110 | } |
@@ -125,7 +117,7 @@ mod tests { | |||
125 | fn dyn_eq(&self, other: &dyn Diagnostic) -> bool { | 117 | fn dyn_eq(&self, other: &dyn Diagnostic) -> bool { |
126 | match other.downcast_ref::<Self>() { | 118 | match other.downcast_ref::<Self>() { |
127 | None => false, | 119 | None => false, |
128 | Some(it) => it ==<|> self, | 120 | Some(it) => it ==$0 self, |
129 | } | 121 | } |
130 | } | 122 | } |
131 | "#, | 123 | "#, |
diff --git a/crates/assists/src/handlers/flip_comma.rs b/crates/assists/src/handlers/flip_comma.rs index 64b4b1a76..18cf64a34 100644 --- a/crates/assists/src/handlers/flip_comma.rs +++ b/crates/assists/src/handlers/flip_comma.rs | |||
@@ -8,7 +8,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
8 | // | 8 | // |
9 | // ``` | 9 | // ``` |
10 | // fn main() { | 10 | // fn main() { |
11 | // ((1, 2),<|> (3, 4)); | 11 | // ((1, 2),$0 (3, 4)); |
12 | // } | 12 | // } |
13 | // ``` | 13 | // ``` |
14 | // -> | 14 | // -> |
@@ -49,14 +49,14 @@ mod tests { | |||
49 | fn flip_comma_works_for_function_parameters() { | 49 | fn flip_comma_works_for_function_parameters() { |
50 | check_assist( | 50 | check_assist( |
51 | flip_comma, | 51 | flip_comma, |
52 | "fn foo(x: i32,<|> y: Result<(), ()>) {}", | 52 | r#"fn foo(x: i32,$0 y: Result<(), ()>) {}"#, |
53 | "fn foo(y: Result<(), ()>, x: i32) {}", | 53 | r#"fn foo(y: Result<(), ()>, x: i32) {}"#, |
54 | ) | 54 | ) |
55 | } | 55 | } |
56 | 56 | ||
57 | #[test] | 57 | #[test] |
58 | fn flip_comma_target() { | 58 | fn flip_comma_target() { |
59 | check_assist_target(flip_comma, "fn foo(x: i32,<|> y: Result<(), ()>) {}", ",") | 59 | check_assist_target(flip_comma, r#"fn foo(x: i32,$0 y: Result<(), ()>) {}"#, ",") |
60 | } | 60 | } |
61 | 61 | ||
62 | #[test] | 62 | #[test] |
@@ -68,7 +68,7 @@ mod tests { | |||
68 | check_assist_target( | 68 | check_assist_target( |
69 | flip_comma, | 69 | flip_comma, |
70 | "pub enum Test { \ | 70 | "pub enum Test { \ |
71 | A,<|> \ | 71 | A,$0 \ |
72 | }", | 72 | }", |
73 | ",", | 73 | ",", |
74 | ); | 74 | ); |
@@ -76,7 +76,7 @@ mod tests { | |||
76 | check_assist_target( | 76 | check_assist_target( |
77 | flip_comma, | 77 | flip_comma, |
78 | "pub struct Test { \ | 78 | "pub struct Test { \ |
79 | foo: usize,<|> \ | 79 | foo: usize,$0 \ |
80 | }", | 80 | }", |
81 | ",", | 81 | ",", |
82 | ); | 82 | ); |
diff --git a/crates/assists/src/handlers/flip_trait_bound.rs b/crates/assists/src/handlers/flip_trait_bound.rs index 92ee42181..d419d263e 100644 --- a/crates/assists/src/handlers/flip_trait_bound.rs +++ b/crates/assists/src/handlers/flip_trait_bound.rs | |||
@@ -11,7 +11,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
11 | // Flips two trait bounds. | 11 | // Flips two trait bounds. |
12 | // | 12 | // |
13 | // ``` | 13 | // ``` |
14 | // fn foo<T: Clone +<|> Copy>() { } | 14 | // fn foo<T: Clone +$0 Copy>() { } |
15 | // ``` | 15 | // ``` |
16 | // -> | 16 | // -> |
17 | // ``` | 17 | // ``` |
@@ -52,19 +52,19 @@ mod tests { | |||
52 | 52 | ||
53 | #[test] | 53 | #[test] |
54 | fn flip_trait_bound_assist_available() { | 54 | fn flip_trait_bound_assist_available() { |
55 | check_assist_target(flip_trait_bound, "struct S<T> where T: A <|>+ B + C { }", "+") | 55 | check_assist_target(flip_trait_bound, "struct S<T> where T: A $0+ B + C { }", "+") |
56 | } | 56 | } |
57 | 57 | ||
58 | #[test] | 58 | #[test] |
59 | fn flip_trait_bound_not_applicable_for_single_trait_bound() { | 59 | fn flip_trait_bound_not_applicable_for_single_trait_bound() { |
60 | check_assist_not_applicable(flip_trait_bound, "struct S<T> where T: <|>A { }") | 60 | check_assist_not_applicable(flip_trait_bound, "struct S<T> where T: $0A { }") |
61 | } | 61 | } |
62 | 62 | ||
63 | #[test] | 63 | #[test] |
64 | fn flip_trait_bound_works_for_struct() { | 64 | fn flip_trait_bound_works_for_struct() { |
65 | check_assist( | 65 | check_assist( |
66 | flip_trait_bound, | 66 | flip_trait_bound, |
67 | "struct S<T> where T: A <|>+ B { }", | 67 | "struct S<T> where T: A $0+ B { }", |
68 | "struct S<T> where T: B + A { }", | 68 | "struct S<T> where T: B + A { }", |
69 | ) | 69 | ) |
70 | } | 70 | } |
@@ -73,21 +73,21 @@ mod tests { | |||
73 | fn flip_trait_bound_works_for_trait_impl() { | 73 | fn flip_trait_bound_works_for_trait_impl() { |
74 | check_assist( | 74 | check_assist( |
75 | flip_trait_bound, | 75 | flip_trait_bound, |
76 | "impl X for S<T> where T: A +<|> B { }", | 76 | "impl X for S<T> where T: A +$0 B { }", |
77 | "impl X for S<T> where T: B + A { }", | 77 | "impl X for S<T> where T: B + A { }", |
78 | ) | 78 | ) |
79 | } | 79 | } |
80 | 80 | ||
81 | #[test] | 81 | #[test] |
82 | fn flip_trait_bound_works_for_fn() { | 82 | fn flip_trait_bound_works_for_fn() { |
83 | check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B + A>(t: T) { }") | 83 | check_assist(flip_trait_bound, "fn f<T: A $0+ B>(t: T) { }", "fn f<T: B + A>(t: T) { }") |
84 | } | 84 | } |
85 | 85 | ||
86 | #[test] | 86 | #[test] |
87 | fn flip_trait_bound_works_for_fn_where_clause() { | 87 | fn flip_trait_bound_works_for_fn_where_clause() { |
88 | check_assist( | 88 | check_assist( |
89 | flip_trait_bound, | 89 | flip_trait_bound, |
90 | "fn f<T>(t: T) where T: A +<|> B { }", | 90 | "fn f<T>(t: T) where T: A +$0 B { }", |
91 | "fn f<T>(t: T) where T: B + A { }", | 91 | "fn f<T>(t: T) where T: B + A { }", |
92 | ) | 92 | ) |
93 | } | 93 | } |
@@ -96,7 +96,7 @@ mod tests { | |||
96 | fn flip_trait_bound_works_for_lifetime() { | 96 | fn flip_trait_bound_works_for_lifetime() { |
97 | check_assist( | 97 | check_assist( |
98 | flip_trait_bound, | 98 | flip_trait_bound, |
99 | "fn f<T>(t: T) where T: A <|>+ 'static { }", | 99 | "fn f<T>(t: T) where T: A $0+ 'static { }", |
100 | "fn f<T>(t: T) where T: 'static + A { }", | 100 | "fn f<T>(t: T) where T: 'static + A { }", |
101 | ) | 101 | ) |
102 | } | 102 | } |
@@ -105,7 +105,7 @@ mod tests { | |||
105 | fn flip_trait_bound_works_for_complex_bounds() { | 105 | fn flip_trait_bound_works_for_complex_bounds() { |
106 | check_assist( | 106 | check_assist( |
107 | flip_trait_bound, | 107 | flip_trait_bound, |
108 | "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }", | 108 | "struct S<T> where T: A<T> $0+ b_mod::B<T> + C<T> { }", |
109 | "struct S<T> where T: b_mod::B<T> + A<T> + C<T> { }", | 109 | "struct S<T> where T: b_mod::B<T> + A<T> + C<T> { }", |
110 | ) | 110 | ) |
111 | } | 111 | } |
@@ -114,7 +114,7 @@ mod tests { | |||
114 | fn flip_trait_bound_works_for_long_bounds() { | 114 | fn flip_trait_bound_works_for_long_bounds() { |
115 | check_assist( | 115 | check_assist( |
116 | flip_trait_bound, | 116 | flip_trait_bound, |
117 | "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }", | 117 | "struct S<T> where T: A + B + C + D + E + F +$0 G + H + I + J { }", |
118 | "struct S<T> where T: A + B + C + D + E + G + F + H + I + J { }", | 118 | "struct S<T> where T: A + B + C + D + E + G + F + H + I + J { }", |
119 | ) | 119 | ) |
120 | } | 120 | } |
diff --git a/crates/assists/src/handlers/generate_default_from_enum_variant.rs b/crates/assists/src/handlers/generate_default_from_enum_variant.rs index bcea46735..6a2ab9596 100644 --- a/crates/assists/src/handlers/generate_default_from_enum_variant.rs +++ b/crates/assists/src/handlers/generate_default_from_enum_variant.rs | |||
@@ -12,7 +12,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
12 | // ``` | 12 | // ``` |
13 | // enum Version { | 13 | // enum Version { |
14 | // Undefined, | 14 | // Undefined, |
15 | // Minor<|>, | 15 | // Minor$0, |
16 | // Major, | 16 | // Major, |
17 | // } | 17 | // } |
18 | // ``` | 18 | // ``` |
@@ -108,7 +108,7 @@ mod tests { | |||
108 | r#" | 108 | r#" |
109 | enum Variant { | 109 | enum Variant { |
110 | Undefined, | 110 | Undefined, |
111 | Minor<|>, | 111 | Minor$0, |
112 | Major, | 112 | Major, |
113 | }"#, | 113 | }"#, |
114 | r#"enum Variant { | 114 | r#"enum Variant { |
@@ -132,7 +132,7 @@ impl Default for Variant { | |||
132 | r#" | 132 | r#" |
133 | enum Variant { | 133 | enum Variant { |
134 | Undefined, | 134 | Undefined, |
135 | Minor<|>, | 135 | Minor$0, |
136 | Major, | 136 | Major, |
137 | } | 137 | } |
138 | 138 | ||
@@ -151,7 +151,7 @@ impl Default for Variant { | |||
151 | r#" | 151 | r#" |
152 | enum Variant { | 152 | enum Variant { |
153 | Undefined, | 153 | Undefined, |
154 | Minor(u32)<|>, | 154 | Minor(u32)$0, |
155 | Major, | 155 | Major, |
156 | }"#, | 156 | }"#, |
157 | ); | 157 | ); |
@@ -161,7 +161,7 @@ enum Variant { | |||
161 | fn test_generate_default_from_variant_with_one_variant() { | 161 | fn test_generate_default_from_variant_with_one_variant() { |
162 | check_assist( | 162 | check_assist( |
163 | generate_default_from_enum_variant, | 163 | generate_default_from_enum_variant, |
164 | r#"enum Variant { Undefi<|>ned }"#, | 164 | r#"enum Variant { Undefi$0ned }"#, |
165 | r#" | 165 | r#" |
166 | enum Variant { Undefined } | 166 | enum Variant { Undefined } |
167 | 167 | ||
diff --git a/crates/assists/src/handlers/generate_derive.rs b/crates/assists/src/handlers/generate_derive.rs index 314504e15..f876b7684 100644 --- a/crates/assists/src/handlers/generate_derive.rs +++ b/crates/assists/src/handlers/generate_derive.rs | |||
@@ -13,7 +13,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
13 | // ``` | 13 | // ``` |
14 | // struct Point { | 14 | // struct Point { |
15 | // x: u32, | 15 | // x: u32, |
16 | // y: u32,<|> | 16 | // y: u32,$0 |
17 | // } | 17 | // } |
18 | // ``` | 18 | // ``` |
19 | // -> | 19 | // -> |
@@ -76,12 +76,12 @@ mod tests { | |||
76 | fn add_derive_new() { | 76 | fn add_derive_new() { |
77 | check_assist( | 77 | check_assist( |
78 | generate_derive, | 78 | generate_derive, |
79 | "struct Foo { a: i32, <|>}", | 79 | "struct Foo { a: i32, $0}", |
80 | "#[derive($0)]\nstruct Foo { a: i32, }", | 80 | "#[derive($0)]\nstruct Foo { a: i32, }", |
81 | ); | 81 | ); |
82 | check_assist( | 82 | check_assist( |
83 | generate_derive, | 83 | generate_derive, |
84 | "struct Foo { <|> a: i32, }", | 84 | "struct Foo { $0 a: i32, }", |
85 | "#[derive($0)]\nstruct Foo { a: i32, }", | 85 | "#[derive($0)]\nstruct Foo { a: i32, }", |
86 | ); | 86 | ); |
87 | } | 87 | } |
@@ -90,7 +90,7 @@ mod tests { | |||
90 | fn add_derive_existing() { | 90 | fn add_derive_existing() { |
91 | check_assist( | 91 | check_assist( |
92 | generate_derive, | 92 | generate_derive, |
93 | "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", | 93 | "#[derive(Clone)]\nstruct Foo { a: i32$0, }", |
94 | "#[derive(Clone$0)]\nstruct Foo { a: i32, }", | 94 | "#[derive(Clone$0)]\nstruct Foo { a: i32, }", |
95 | ); | 95 | ); |
96 | } | 96 | } |
@@ -102,7 +102,7 @@ mod tests { | |||
102 | " | 102 | " |
103 | /// `Foo` is a pretty important struct. | 103 | /// `Foo` is a pretty important struct. |
104 | /// It does stuff. | 104 | /// It does stuff. |
105 | struct Foo { a: i32<|>, } | 105 | struct Foo { a: i32$0, } |
106 | ", | 106 | ", |
107 | " | 107 | " |
108 | /// `Foo` is a pretty important struct. | 108 | /// `Foo` is a pretty important struct. |
@@ -121,7 +121,7 @@ struct Foo { a: i32, } | |||
121 | struct SomeThingIrrelevant; | 121 | struct SomeThingIrrelevant; |
122 | /// `Foo` is a pretty important struct. | 122 | /// `Foo` is a pretty important struct. |
123 | /// It does stuff. | 123 | /// It does stuff. |
124 | struct Foo { a: i32<|>, } | 124 | struct Foo { a: i32$0, } |
125 | struct EvenMoreIrrelevant; | 125 | struct EvenMoreIrrelevant; |
126 | ", | 126 | ", |
127 | "/// `Foo` is a pretty important struct. | 127 | "/// `Foo` is a pretty important struct. |
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 3c374e5d9..d9af6ab11 100644 --- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs | |||
@@ -10,7 +10,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
10 | // Adds a From impl for an enum variant with one tuple field. | 10 | // Adds a From impl for an enum variant with one tuple field. |
11 | // | 11 | // |
12 | // ``` | 12 | // ``` |
13 | // enum A { <|>One(u32) } | 13 | // enum A { $0One(u32) } |
14 | // ``` | 14 | // ``` |
15 | // -> | 15 | // -> |
16 | // ``` | 16 | // ``` |
@@ -101,7 +101,7 @@ mod tests { | |||
101 | fn test_generate_from_impl_for_enum() { | 101 | fn test_generate_from_impl_for_enum() { |
102 | check_assist( | 102 | check_assist( |
103 | generate_from_impl_for_enum, | 103 | generate_from_impl_for_enum, |
104 | "enum A { <|>One(u32) }", | 104 | "enum A { $0One(u32) }", |
105 | r#"enum A { One(u32) } | 105 | r#"enum A { One(u32) } |
106 | 106 | ||
107 | impl From<u32> for A { | 107 | impl From<u32> for A { |
@@ -116,7 +116,7 @@ impl From<u32> for A { | |||
116 | fn test_generate_from_impl_for_enum_complicated_path() { | 116 | fn test_generate_from_impl_for_enum_complicated_path() { |
117 | check_assist( | 117 | check_assist( |
118 | generate_from_impl_for_enum, | 118 | generate_from_impl_for_enum, |
119 | r#"enum A { <|>One(foo::bar::baz::Boo) }"#, | 119 | r#"enum A { $0One(foo::bar::baz::Boo) }"#, |
120 | r#"enum A { One(foo::bar::baz::Boo) } | 120 | r#"enum A { One(foo::bar::baz::Boo) } |
121 | 121 | ||
122 | impl From<foo::bar::baz::Boo> for A { | 122 | impl From<foo::bar::baz::Boo> for A { |
@@ -135,17 +135,17 @@ impl From<foo::bar::baz::Boo> for A { | |||
135 | 135 | ||
136 | #[test] | 136 | #[test] |
137 | fn test_add_from_impl_no_element() { | 137 | fn test_add_from_impl_no_element() { |
138 | check_not_applicable("enum A { <|>One }"); | 138 | check_not_applicable("enum A { $0One }"); |
139 | } | 139 | } |
140 | 140 | ||
141 | #[test] | 141 | #[test] |
142 | fn test_add_from_impl_more_than_one_element_in_tuple() { | 142 | fn test_add_from_impl_more_than_one_element_in_tuple() { |
143 | check_not_applicable("enum A { <|>One(u32, String) }"); | 143 | check_not_applicable("enum A { $0One(u32, String) }"); |
144 | } | 144 | } |
145 | 145 | ||
146 | #[test] | 146 | #[test] |
147 | fn test_add_from_impl_struct_variant() { | 147 | fn test_add_from_impl_struct_variant() { |
148 | check_not_applicable("enum A { <|>One { x: u32 } }"); | 148 | check_not_applicable("enum A { $0One { x: u32 } }"); |
149 | } | 149 | } |
150 | 150 | ||
151 | #[test] | 151 | #[test] |
@@ -153,7 +153,7 @@ impl From<foo::bar::baz::Boo> for A { | |||
153 | mark::check!(test_add_from_impl_already_exists); | 153 | mark::check!(test_add_from_impl_already_exists); |
154 | check_not_applicable( | 154 | check_not_applicable( |
155 | r#" | 155 | r#" |
156 | enum A { <|>One(u32), } | 156 | enum A { $0One(u32), } |
157 | 157 | ||
158 | impl From<u32> for A { | 158 | impl From<u32> for A { |
159 | fn from(v: u32) -> Self { | 159 | fn from(v: u32) -> Self { |
@@ -168,7 +168,7 @@ impl From<u32> for A { | |||
168 | fn test_add_from_impl_different_variant_impl_exists() { | 168 | fn test_add_from_impl_different_variant_impl_exists() { |
169 | check_assist( | 169 | check_assist( |
170 | generate_from_impl_for_enum, | 170 | generate_from_impl_for_enum, |
171 | r#"enum A { <|>One(u32), Two(String), } | 171 | r#"enum A { $0One(u32), Two(String), } |
172 | 172 | ||
173 | impl From<String> for A { | 173 | impl From<String> for A { |
174 | fn from(v: String) -> Self { | 174 | fn from(v: String) -> Self { |
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs index f4cf155b6..06ac85f67 100644 --- a/crates/assists/src/handlers/generate_function.rs +++ b/crates/assists/src/handlers/generate_function.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use hir::HirDisplay; | 1 | use hir::HirDisplay; |
2 | use ide_db::base_db::FileId; | 2 | use ide_db::{base_db::FileId, helpers::SnippetCap}; |
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::{FxHashMap, FxHashSet}; |
4 | use syntax::{ | 4 | use syntax::{ |
5 | ast::{ | 5 | ast::{ |
@@ -11,7 +11,6 @@ use syntax::{ | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | assist_config::SnippetCap, | ||
15 | utils::{render_snippet, Cursor}, | 14 | utils::{render_snippet, Cursor}, |
16 | AssistContext, AssistId, AssistKind, Assists, | 15 | AssistContext, AssistId, AssistKind, Assists, |
17 | }; | 16 | }; |
@@ -24,7 +23,7 @@ use crate::{ | |||
24 | // struct Baz; | 23 | // struct Baz; |
25 | // fn baz() -> Baz { Baz } | 24 | // fn baz() -> Baz { Baz } |
26 | // fn foo() { | 25 | // fn foo() { |
27 | // bar<|>("", baz()); | 26 | // bar$0("", baz()); |
28 | // } | 27 | // } |
29 | // | 28 | // |
30 | // ``` | 29 | // ``` |
@@ -343,7 +342,7 @@ mod tests { | |||
343 | generate_function, | 342 | generate_function, |
344 | r" | 343 | r" |
345 | fn foo() { | 344 | fn foo() { |
346 | bar<|>(); | 345 | bar$0(); |
347 | } | 346 | } |
348 | ", | 347 | ", |
349 | r" | 348 | r" |
@@ -367,7 +366,7 @@ fn bar() ${0:-> ()} { | |||
367 | r" | 366 | r" |
368 | impl Foo { | 367 | impl Foo { |
369 | fn foo() { | 368 | fn foo() { |
370 | bar<|>(); | 369 | bar$0(); |
371 | } | 370 | } |
372 | } | 371 | } |
373 | ", | 372 | ", |
@@ -392,7 +391,7 @@ fn bar() ${0:-> ()} { | |||
392 | generate_function, | 391 | generate_function, |
393 | r" | 392 | r" |
394 | fn foo1() { | 393 | fn foo1() { |
395 | bar<|>(); | 394 | bar$0(); |
396 | } | 395 | } |
397 | 396 | ||
398 | fn foo2() {} | 397 | fn foo2() {} |
@@ -418,7 +417,7 @@ fn foo2() {} | |||
418 | r" | 417 | r" |
419 | mod baz { | 418 | mod baz { |
420 | fn foo() { | 419 | fn foo() { |
421 | bar<|>(); | 420 | bar$0(); |
422 | } | 421 | } |
423 | } | 422 | } |
424 | ", | 423 | ", |
@@ -444,7 +443,7 @@ mod baz { | |||
444 | struct Baz; | 443 | struct Baz; |
445 | fn baz() -> Baz { todo!() } | 444 | fn baz() -> Baz { todo!() } |
446 | fn foo() { | 445 | fn foo() { |
447 | bar<|>(baz()); | 446 | bar$0(baz()); |
448 | } | 447 | } |
449 | ", | 448 | ", |
450 | r" | 449 | r" |
@@ -469,7 +468,7 @@ fn bar(baz: Baz) ${0:-> ()} { | |||
469 | struct Baz; | 468 | struct Baz; |
470 | impl Baz { | 469 | impl Baz { |
471 | fn foo(&self) -> Baz { | 470 | fn foo(&self) -> Baz { |
472 | ba<|>r(self.baz()) | 471 | ba$0r(self.baz()) |
473 | } | 472 | } |
474 | fn baz(&self) -> Baz { | 473 | fn baz(&self) -> Baz { |
475 | Baz | 474 | Baz |
@@ -500,7 +499,7 @@ fn bar(baz: Baz) ${0:-> ()} { | |||
500 | generate_function, | 499 | generate_function, |
501 | r#" | 500 | r#" |
502 | fn foo() { | 501 | fn foo() { |
503 | <|>bar("bar") | 502 | $0bar("bar") |
504 | } | 503 | } |
505 | "#, | 504 | "#, |
506 | r#" | 505 | r#" |
@@ -521,7 +520,7 @@ fn bar(arg: &str) ${0:-> ()} { | |||
521 | generate_function, | 520 | generate_function, |
522 | r#" | 521 | r#" |
523 | fn foo() { | 522 | fn foo() { |
524 | <|>bar('x') | 523 | $0bar('x') |
525 | } | 524 | } |
526 | "#, | 525 | "#, |
527 | r#" | 526 | r#" |
@@ -542,7 +541,7 @@ fn bar(arg: char) ${0:-> ()} { | |||
542 | generate_function, | 541 | generate_function, |
543 | r" | 542 | r" |
544 | fn foo() { | 543 | fn foo() { |
545 | <|>bar(42) | 544 | $0bar(42) |
546 | } | 545 | } |
547 | ", | 546 | ", |
548 | r" | 547 | r" |
@@ -563,7 +562,7 @@ fn bar(arg: i32) ${0:-> ()} { | |||
563 | generate_function, | 562 | generate_function, |
564 | r" | 563 | r" |
565 | fn foo() { | 564 | fn foo() { |
566 | <|>bar(42 as u8) | 565 | $0bar(42 as u8) |
567 | } | 566 | } |
568 | ", | 567 | ", |
569 | r" | 568 | r" |
@@ -587,7 +586,7 @@ fn bar(arg: u8) ${0:-> ()} { | |||
587 | r" | 586 | r" |
588 | fn foo() { | 587 | fn foo() { |
589 | let x = 42; | 588 | let x = 42; |
590 | bar<|>(x as u8) | 589 | bar$0(x as u8) |
591 | } | 590 | } |
592 | ", | 591 | ", |
593 | r" | 592 | r" |
@@ -610,7 +609,7 @@ fn bar(x: u8) ${0:-> ()} { | |||
610 | r" | 609 | r" |
611 | fn foo() { | 610 | fn foo() { |
612 | let worble = (); | 611 | let worble = (); |
613 | <|>bar(worble) | 612 | $0bar(worble) |
614 | } | 613 | } |
615 | ", | 614 | ", |
616 | r" | 615 | r" |
@@ -636,7 +635,7 @@ fn foo() -> impl Foo { | |||
636 | todo!() | 635 | todo!() |
637 | } | 636 | } |
638 | fn baz() { | 637 | fn baz() { |
639 | <|>bar(foo()) | 638 | $0bar(foo()) |
640 | } | 639 | } |
641 | ", | 640 | ", |
642 | r" | 641 | r" |
@@ -664,7 +663,7 @@ struct Baz; | |||
664 | fn baz() -> Baz { todo!() } | 663 | fn baz() -> Baz { todo!() } |
665 | 664 | ||
666 | fn foo() { | 665 | fn foo() { |
667 | bar<|>(&baz()) | 666 | bar$0(&baz()) |
668 | } | 667 | } |
669 | ", | 668 | ", |
670 | r" | 669 | r" |
@@ -692,7 +691,7 @@ mod Baz { | |||
692 | pub fn baz() -> Bof { Bof } | 691 | pub fn baz() -> Bof { Bof } |
693 | } | 692 | } |
694 | fn foo() { | 693 | fn foo() { |
695 | <|>bar(Baz::baz()) | 694 | $0bar(Baz::baz()) |
696 | } | 695 | } |
697 | ", | 696 | ", |
698 | r" | 697 | r" |
@@ -719,7 +718,7 @@ fn bar(baz: Baz::Bof) ${0:-> ()} { | |||
719 | generate_function, | 718 | generate_function, |
720 | r" | 719 | r" |
721 | fn foo<T>(t: T) { | 720 | fn foo<T>(t: T) { |
722 | <|>bar(t) | 721 | $0bar(t) |
723 | } | 722 | } |
724 | ", | 723 | ", |
725 | r" | 724 | r" |
@@ -746,7 +745,7 @@ impl Baz { | |||
746 | fn new() -> Self { Baz } | 745 | fn new() -> Self { Baz } |
747 | } | 746 | } |
748 | fn foo() { | 747 | fn foo() { |
749 | <|>bar(Baz::new); | 748 | $0bar(Baz::new); |
750 | } | 749 | } |
751 | ", | 750 | ", |
752 | r" | 751 | r" |
@@ -774,7 +773,7 @@ fn bar(arg: fn() -> Baz) ${0:-> ()} { | |||
774 | r" | 773 | r" |
775 | fn foo() { | 774 | fn foo() { |
776 | let closure = |x: i64| x - 1; | 775 | let closure = |x: i64| x - 1; |
777 | <|>bar(closure) | 776 | $0bar(closure) |
778 | } | 777 | } |
779 | ", | 778 | ", |
780 | r" | 779 | r" |
@@ -796,7 +795,7 @@ fn bar(closure: impl Fn(i64) -> i64) ${0:-> ()} { | |||
796 | generate_function, | 795 | generate_function, |
797 | r" | 796 | r" |
798 | fn foo() { | 797 | fn foo() { |
799 | <|>bar(baz) | 798 | $0bar(baz) |
800 | } | 799 | } |
801 | ", | 800 | ", |
802 | r" | 801 | r" |
@@ -819,7 +818,7 @@ fn bar(baz: ()) ${0:-> ()} { | |||
819 | struct Baz; | 818 | struct Baz; |
820 | fn baz() -> Baz { Baz } | 819 | fn baz() -> Baz { Baz } |
821 | fn foo() { | 820 | fn foo() { |
822 | <|>bar(baz(), baz()) | 821 | $0bar(baz(), baz()) |
823 | } | 822 | } |
824 | ", | 823 | ", |
825 | r" | 824 | r" |
@@ -844,7 +843,7 @@ fn bar(baz_1: Baz, baz_2: Baz) ${0:-> ()} { | |||
844 | struct Baz; | 843 | struct Baz; |
845 | fn baz() -> Baz { Baz } | 844 | fn baz() -> Baz { Baz } |
846 | fn foo() { | 845 | fn foo() { |
847 | <|>bar(baz(), baz(), "foo", "bar") | 846 | $0bar(baz(), baz(), "foo", "bar") |
848 | } | 847 | } |
849 | "#, | 848 | "#, |
850 | r#" | 849 | r#" |
@@ -869,7 +868,7 @@ fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) ${0:-> ()} { | |||
869 | mod bar {} | 868 | mod bar {} |
870 | 869 | ||
871 | fn foo() { | 870 | fn foo() { |
872 | bar::my_fn<|>() | 871 | bar::my_fn$0() |
873 | } | 872 | } |
874 | ", | 873 | ", |
875 | r" | 874 | r" |
@@ -900,7 +899,7 @@ mod foo { | |||
900 | fn bar() { | 899 | fn bar() { |
901 | use foo::Foo; | 900 | use foo::Foo; |
902 | let foo = Foo; | 901 | let foo = Foo; |
903 | baz<|>(foo) | 902 | baz$0(foo) |
904 | } | 903 | } |
905 | ", | 904 | ", |
906 | " | 905 | " |
@@ -930,7 +929,7 @@ mod bar { | |||
930 | } | 929 | } |
931 | 930 | ||
932 | fn foo() { | 931 | fn foo() { |
933 | bar::my_fn<|>() | 932 | bar::my_fn$0() |
934 | } | 933 | } |
935 | ", | 934 | ", |
936 | r" | 935 | r" |
@@ -959,7 +958,7 @@ mod bar { | |||
959 | } | 958 | } |
960 | 959 | ||
961 | fn foo() { | 960 | fn foo() { |
962 | bar::baz::my_fn<|>() | 961 | bar::baz::my_fn$0() |
963 | } | 962 | } |
964 | ", | 963 | ", |
965 | r" | 964 | r" |
@@ -987,7 +986,7 @@ fn foo() { | |||
987 | mod foo; | 986 | mod foo; |
988 | 987 | ||
989 | fn main() { | 988 | fn main() { |
990 | foo::bar<|>() | 989 | foo::bar$0() |
991 | } | 990 | } |
992 | //- /foo.rs | 991 | //- /foo.rs |
993 | ", | 992 | ", |
@@ -1006,7 +1005,7 @@ pub(crate) fn bar() ${0:-> ()} { | |||
1006 | generate_function, | 1005 | generate_function, |
1007 | r" | 1006 | r" |
1008 | fn foo() { | 1007 | fn foo() { |
1009 | bar<|>(); | 1008 | bar$0(); |
1010 | } | 1009 | } |
1011 | 1010 | ||
1012 | fn bar() {} | 1011 | fn bar() {} |
@@ -1023,7 +1022,7 @@ fn bar() {} | |||
1023 | generate_function, | 1022 | generate_function, |
1024 | r" | 1023 | r" |
1025 | fn foo() { | 1024 | fn foo() { |
1026 | bar(b<|>az); | 1025 | bar(b$0az); |
1027 | } | 1026 | } |
1028 | 1027 | ||
1029 | fn bar(baz: ()) {} | 1028 | fn bar(baz: ()) {} |
@@ -1040,7 +1039,7 @@ fn bar(baz: ()) {} | |||
1040 | struct Foo; | 1039 | struct Foo; |
1041 | impl Foo { | 1040 | impl Foo { |
1042 | fn foo(&self) { | 1041 | fn foo(&self) { |
1043 | self.bar()<|>; | 1042 | self.bar()$0; |
1044 | } | 1043 | } |
1045 | } | 1044 | } |
1046 | ", | 1045 | ", |
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs index 960af5ab3..9af45192b 100644 --- a/crates/assists/src/handlers/generate_impl.rs +++ b/crates/assists/src/handlers/generate_impl.rs | |||
@@ -10,7 +10,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
10 | // | 10 | // |
11 | // ``` | 11 | // ``` |
12 | // struct Ctx<T: Clone> { | 12 | // struct Ctx<T: Clone> { |
13 | // data: T,<|> | 13 | // data: T,$0 |
14 | // } | 14 | // } |
15 | // ``` | 15 | // ``` |
16 | // -> | 16 | // -> |
@@ -87,24 +87,24 @@ mod tests { | |||
87 | fn test_add_impl() { | 87 | fn test_add_impl() { |
88 | check_assist( | 88 | check_assist( |
89 | generate_impl, | 89 | generate_impl, |
90 | "struct Foo {<|>}\n", | 90 | "struct Foo {$0}\n", |
91 | "struct Foo {}\n\nimpl Foo {\n $0\n}\n", | 91 | "struct Foo {}\n\nimpl Foo {\n $0\n}\n", |
92 | ); | 92 | ); |
93 | check_assist( | 93 | check_assist( |
94 | generate_impl, | 94 | generate_impl, |
95 | "struct Foo<T: Clone> {<|>}", | 95 | "struct Foo<T: Clone> {$0}", |
96 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}", | 96 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}", |
97 | ); | 97 | ); |
98 | check_assist( | 98 | check_assist( |
99 | generate_impl, | 99 | generate_impl, |
100 | "struct Foo<'a, T: Foo<'a>> {<|>}", | 100 | "struct Foo<'a, T: Foo<'a>> {$0}", |
101 | "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}", | 101 | "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}", |
102 | ); | 102 | ); |
103 | check_assist( | 103 | check_assist( |
104 | generate_impl, | 104 | generate_impl, |
105 | r#" | 105 | r#" |
106 | #[cfg(feature = "foo")] | 106 | #[cfg(feature = "foo")] |
107 | struct Foo<'a, T: Foo<'a>> {<|>}"#, | 107 | struct Foo<'a, T: Foo<'a>> {$0}"#, |
108 | r#" | 108 | r#" |
109 | #[cfg(feature = "foo")] | 109 | #[cfg(feature = "foo")] |
110 | struct Foo<'a, T: Foo<'a>> {} | 110 | struct Foo<'a, T: Foo<'a>> {} |
@@ -119,7 +119,7 @@ mod tests { | |||
119 | generate_impl, | 119 | generate_impl, |
120 | r#" | 120 | r#" |
121 | #[cfg(not(feature = "foo"))] | 121 | #[cfg(not(feature = "foo"))] |
122 | struct Foo<'a, T: Foo<'a>> {<|>}"#, | 122 | struct Foo<'a, T: Foo<'a>> {$0}"#, |
123 | r#" | 123 | r#" |
124 | #[cfg(not(feature = "foo"))] | 124 | #[cfg(not(feature = "foo"))] |
125 | struct Foo<'a, T: Foo<'a>> {} | 125 | struct Foo<'a, T: Foo<'a>> {} |
@@ -138,7 +138,7 @@ mod tests { | |||
138 | " | 138 | " |
139 | struct SomeThingIrrelevant; | 139 | struct SomeThingIrrelevant; |
140 | /// Has a lifetime parameter | 140 | /// Has a lifetime parameter |
141 | struct Foo<'a, T: Foo<'a>> {<|>} | 141 | struct Foo<'a, T: Foo<'a>> {$0} |
142 | struct EvenMoreIrrelevant; | 142 | struct EvenMoreIrrelevant; |
143 | ", | 143 | ", |
144 | "/// Has a lifetime parameter | 144 | "/// Has a lifetime parameter |
diff --git a/crates/assists/src/handlers/generate_new.rs b/crates/assists/src/handlers/generate_new.rs index c5fec4e0a..5c52b2bc8 100644 --- a/crates/assists/src/handlers/generate_new.rs +++ b/crates/assists/src/handlers/generate_new.rs | |||
@@ -14,7 +14,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
14 | // | 14 | // |
15 | // ``` | 15 | // ``` |
16 | // struct Ctx<T: Clone> { | 16 | // struct Ctx<T: Clone> { |
17 | // data: T,<|> | 17 | // data: T,$0 |
18 | // } | 18 | // } |
19 | // ``` | 19 | // ``` |
20 | // -> | 20 | // -> |
@@ -182,7 +182,7 @@ mod tests { | |||
182 | // Check output of generation | 182 | // Check output of generation |
183 | check_assist( | 183 | check_assist( |
184 | generate_new, | 184 | generate_new, |
185 | "struct Foo {<|>}", | 185 | "struct Foo {$0}", |
186 | "struct Foo {} | 186 | "struct Foo {} |
187 | 187 | ||
188 | impl Foo { | 188 | impl Foo { |
@@ -192,7 +192,7 @@ impl Foo { | |||
192 | ); | 192 | ); |
193 | check_assist( | 193 | check_assist( |
194 | generate_new, | 194 | generate_new, |
195 | "struct Foo<T: Clone> {<|>}", | 195 | "struct Foo<T: Clone> {$0}", |
196 | "struct Foo<T: Clone> {} | 196 | "struct Foo<T: Clone> {} |
197 | 197 | ||
198 | impl<T: Clone> Foo<T> { | 198 | impl<T: Clone> Foo<T> { |
@@ -202,7 +202,7 @@ impl<T: Clone> Foo<T> { | |||
202 | ); | 202 | ); |
203 | check_assist( | 203 | check_assist( |
204 | generate_new, | 204 | generate_new, |
205 | "struct Foo<'a, T: Foo<'a>> {<|>}", | 205 | "struct Foo<'a, T: Foo<'a>> {$0}", |
206 | "struct Foo<'a, T: Foo<'a>> {} | 206 | "struct Foo<'a, T: Foo<'a>> {} |
207 | 207 | ||
208 | impl<'a, T: Foo<'a>> Foo<'a, T> { | 208 | impl<'a, T: Foo<'a>> Foo<'a, T> { |
@@ -212,7 +212,7 @@ impl<'a, T: Foo<'a>> Foo<'a, T> { | |||
212 | ); | 212 | ); |
213 | check_assist( | 213 | check_assist( |
214 | generate_new, | 214 | generate_new, |
215 | "struct Foo { baz: String <|>}", | 215 | "struct Foo { baz: String $0}", |
216 | "struct Foo { baz: String } | 216 | "struct Foo { baz: String } |
217 | 217 | ||
218 | impl Foo { | 218 | impl Foo { |
@@ -222,7 +222,7 @@ impl Foo { | |||
222 | ); | 222 | ); |
223 | check_assist( | 223 | check_assist( |
224 | generate_new, | 224 | generate_new, |
225 | "struct Foo { baz: String, qux: Vec<i32> <|>}", | 225 | "struct Foo { baz: String, qux: Vec<i32> $0}", |
226 | "struct Foo { baz: String, qux: Vec<i32> } | 226 | "struct Foo { baz: String, qux: Vec<i32> } |
227 | 227 | ||
228 | impl Foo { | 228 | impl Foo { |
@@ -234,7 +234,7 @@ impl Foo { | |||
234 | // Check that visibility modifiers don't get brought in for fields | 234 | // Check that visibility modifiers don't get brought in for fields |
235 | check_assist( | 235 | check_assist( |
236 | generate_new, | 236 | generate_new, |
237 | "struct Foo { pub baz: String, pub qux: Vec<i32> <|>}", | 237 | "struct Foo { pub baz: String, pub qux: Vec<i32> $0}", |
238 | "struct Foo { pub baz: String, pub qux: Vec<i32> } | 238 | "struct Foo { pub baz: String, pub qux: Vec<i32> } |
239 | 239 | ||
240 | impl Foo { | 240 | impl Foo { |
@@ -246,7 +246,7 @@ impl Foo { | |||
246 | // Check that it reuses existing impls | 246 | // Check that it reuses existing impls |
247 | check_assist( | 247 | check_assist( |
248 | generate_new, | 248 | generate_new, |
249 | "struct Foo {<|>} | 249 | "struct Foo {$0} |
250 | 250 | ||
251 | impl Foo {} | 251 | impl Foo {} |
252 | ", | 252 | ", |
@@ -259,7 +259,7 @@ impl Foo { | |||
259 | ); | 259 | ); |
260 | check_assist( | 260 | check_assist( |
261 | generate_new, | 261 | generate_new, |
262 | "struct Foo {<|>} | 262 | "struct Foo {$0} |
263 | 263 | ||
264 | impl Foo { | 264 | impl Foo { |
265 | fn qux(&self) {} | 265 | fn qux(&self) {} |
@@ -277,7 +277,7 @@ impl Foo { | |||
277 | 277 | ||
278 | check_assist( | 278 | check_assist( |
279 | generate_new, | 279 | generate_new, |
280 | "struct Foo {<|>} | 280 | "struct Foo {$0} |
281 | 281 | ||
282 | impl Foo { | 282 | impl Foo { |
283 | fn qux(&self) {} | 283 | fn qux(&self) {} |
@@ -302,7 +302,7 @@ impl Foo { | |||
302 | // Check visibility of new fn based on struct | 302 | // Check visibility of new fn based on struct |
303 | check_assist( | 303 | check_assist( |
304 | generate_new, | 304 | generate_new, |
305 | "pub struct Foo {<|>}", | 305 | "pub struct Foo {$0}", |
306 | "pub struct Foo {} | 306 | "pub struct Foo {} |
307 | 307 | ||
308 | impl Foo { | 308 | impl Foo { |
@@ -312,7 +312,7 @@ impl Foo { | |||
312 | ); | 312 | ); |
313 | check_assist( | 313 | check_assist( |
314 | generate_new, | 314 | generate_new, |
315 | "pub(crate) struct Foo {<|>}", | 315 | "pub(crate) struct Foo {$0}", |
316 | "pub(crate) struct Foo {} | 316 | "pub(crate) struct Foo {} |
317 | 317 | ||
318 | impl Foo { | 318 | impl Foo { |
@@ -327,7 +327,7 @@ impl Foo { | |||
327 | check_assist_not_applicable( | 327 | check_assist_not_applicable( |
328 | generate_new, | 328 | generate_new, |
329 | " | 329 | " |
330 | struct Foo {<|>} | 330 | struct Foo {$0} |
331 | 331 | ||
332 | impl Foo { | 332 | impl Foo { |
333 | fn new() -> Self { | 333 | fn new() -> Self { |
@@ -339,7 +339,7 @@ impl Foo { | |||
339 | check_assist_not_applicable( | 339 | check_assist_not_applicable( |
340 | generate_new, | 340 | generate_new, |
341 | " | 341 | " |
342 | struct Foo {<|>} | 342 | struct Foo {$0} |
343 | 343 | ||
344 | impl Foo { | 344 | impl Foo { |
345 | fn New() -> Self { | 345 | fn New() -> Self { |
@@ -356,7 +356,7 @@ impl Foo { | |||
356 | " | 356 | " |
357 | struct SomeThingIrrelevant; | 357 | struct SomeThingIrrelevant; |
358 | /// Has a lifetime parameter | 358 | /// Has a lifetime parameter |
359 | struct Foo<'a, T: Foo<'a>> {<|>} | 359 | struct Foo<'a, T: Foo<'a>> {$0} |
360 | struct EvenMoreIrrelevant; | 360 | struct EvenMoreIrrelevant; |
361 | ", | 361 | ", |
362 | "/// Has a lifetime parameter | 362 | "/// Has a lifetime parameter |
@@ -381,7 +381,7 @@ impl<N: AstNode> AstId<N> { | |||
381 | } | 381 | } |
382 | 382 | ||
383 | pub struct Source<T> { | 383 | pub struct Source<T> { |
384 | pub file_id: HirFileId,<|> | 384 | pub file_id: HirFileId,$0 |
385 | pub ast: T, | 385 | pub ast: T, |
386 | } | 386 | } |
387 | 387 | ||
diff --git a/crates/assists/src/handlers/infer_function_return_type.rs b/crates/assists/src/handlers/infer_function_return_type.rs index aa584eb03..5279af1f3 100644 --- a/crates/assists/src/handlers/infer_function_return_type.rs +++ b/crates/assists/src/handlers/infer_function_return_type.rs | |||
@@ -10,7 +10,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
10 | // type specified. This assists is useable in a functions or closures tail expression or return type position. | 10 | // type specified. This assists is useable in a functions or closures tail expression or return type position. |
11 | // | 11 | // |
12 | // ``` | 12 | // ``` |
13 | // fn foo() { 4<|>2i32 } | 13 | // fn foo() { 4$02i32 } |
14 | // ``` | 14 | // ``` |
15 | // -> | 15 | // -> |
16 | // ``` | 16 | // ``` |
@@ -89,7 +89,7 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla | |||
89 | let body = closure.body()?; | 89 | let body = closure.body()?; |
90 | let body_start = body.syntax().first_token()?.text_range().start(); | 90 | let body_start = body.syntax().first_token()?.text_range().start(); |
91 | let (tail_expr, wrap_expr) = match body { | 91 | let (tail_expr, wrap_expr) = match body { |
92 | ast::Expr::BlockExpr(block) => (block.expr()?, false), | 92 | ast::Expr::BlockExpr(block) => (block.tail_expr()?, false), |
93 | body => (body, true), | 93 | body => (body, true), |
94 | }; | 94 | }; |
95 | 95 | ||
@@ -101,7 +101,7 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla | |||
101 | let action = ret_ty_to_action(func.ret_type(), rparen_pos)?; | 101 | let action = ret_ty_to_action(func.ret_type(), rparen_pos)?; |
102 | 102 | ||
103 | let body = func.body()?; | 103 | let body = func.body()?; |
104 | let tail_expr = body.expr()?; | 104 | let tail_expr = body.tail_expr()?; |
105 | 105 | ||
106 | let ret_range_end = body.l_curly_token()?.text_range().start(); | 106 | let ret_range_end = body.l_curly_token()?.text_range().start(); |
107 | let ret_range = TextRange::new(rparen_pos, ret_range_end); | 107 | let ret_range = TextRange::new(rparen_pos, ret_range_end); |
@@ -131,7 +131,7 @@ mod tests { | |||
131 | mark::check!(existing_infer_ret_type); | 131 | mark::check!(existing_infer_ret_type); |
132 | check_assist( | 132 | check_assist( |
133 | infer_function_return_type, | 133 | infer_function_return_type, |
134 | r#"fn foo() -> <|>_ { | 134 | r#"fn foo() -> $0_ { |
135 | 45 | 135 | 45 |
136 | }"#, | 136 | }"#, |
137 | r#"fn foo() -> i32 { | 137 | r#"fn foo() -> i32 { |
@@ -146,7 +146,7 @@ mod tests { | |||
146 | check_assist( | 146 | check_assist( |
147 | infer_function_return_type, | 147 | infer_function_return_type, |
148 | r#"fn foo() { | 148 | r#"fn foo() { |
149 | || -> _ {<|>45}; | 149 | || -> _ {$045}; |
150 | }"#, | 150 | }"#, |
151 | r#"fn foo() { | 151 | r#"fn foo() { |
152 | || -> i32 {45}; | 152 | || -> i32 {45}; |
@@ -159,7 +159,7 @@ mod tests { | |||
159 | mark::check!(cursor_in_ret_position); | 159 | mark::check!(cursor_in_ret_position); |
160 | check_assist( | 160 | check_assist( |
161 | infer_function_return_type, | 161 | infer_function_return_type, |
162 | r#"fn foo() <|>{ | 162 | r#"fn foo() $0{ |
163 | 45 | 163 | 45 |
164 | }"#, | 164 | }"#, |
165 | r#"fn foo() -> i32 { | 165 | r#"fn foo() -> i32 { |
@@ -174,7 +174,7 @@ mod tests { | |||
174 | check_assist( | 174 | check_assist( |
175 | infer_function_return_type, | 175 | infer_function_return_type, |
176 | r#"fn foo() { | 176 | r#"fn foo() { |
177 | || <|>45 | 177 | || $045 |
178 | }"#, | 178 | }"#, |
179 | r#"fn foo() { | 179 | r#"fn foo() { |
180 | || -> i32 {45} | 180 | || -> i32 {45} |
@@ -188,7 +188,7 @@ mod tests { | |||
188 | check_assist( | 188 | check_assist( |
189 | infer_function_return_type, | 189 | infer_function_return_type, |
190 | r#"fn foo() { | 190 | r#"fn foo() { |
191 | 45<|> | 191 | 45$0 |
192 | }"#, | 192 | }"#, |
193 | r#"fn foo() -> i32 { | 193 | r#"fn foo() -> i32 { |
194 | 45 | 194 | 45 |
@@ -202,7 +202,7 @@ mod tests { | |||
202 | infer_function_return_type, | 202 | infer_function_return_type, |
203 | r#"fn foo() { | 203 | r#"fn foo() { |
204 | if true { | 204 | if true { |
205 | 3<|> | 205 | 3$0 |
206 | } else { | 206 | } else { |
207 | 5 | 207 | 5 |
208 | } | 208 | } |
@@ -223,7 +223,7 @@ mod tests { | |||
223 | check_assist_not_applicable( | 223 | check_assist_not_applicable( |
224 | infer_function_return_type, | 224 | infer_function_return_type, |
225 | r#"fn foo() -> i32 { | 225 | r#"fn foo() -> i32 { |
226 | ( 45<|> + 32 ) * 123 | 226 | ( 45$0 + 32 ) * 123 |
227 | }"#, | 227 | }"#, |
228 | ); | 228 | ); |
229 | } | 229 | } |
@@ -233,7 +233,7 @@ mod tests { | |||
233 | check_assist_not_applicable( | 233 | check_assist_not_applicable( |
234 | infer_function_return_type, | 234 | infer_function_return_type, |
235 | r#"fn foo() { | 235 | r#"fn foo() { |
236 | let x = <|>3; | 236 | let x = $03; |
237 | ( 45 + 32 ) * 123 | 237 | ( 45 + 32 ) * 123 |
238 | }"#, | 238 | }"#, |
239 | ); | 239 | ); |
@@ -244,7 +244,7 @@ mod tests { | |||
244 | check_assist_not_applicable( | 244 | check_assist_not_applicable( |
245 | infer_function_return_type, | 245 | infer_function_return_type, |
246 | r#"fn foo() { | 246 | r#"fn foo() { |
247 | (<|>) | 247 | ($0) |
248 | }"#, | 248 | }"#, |
249 | ); | 249 | ); |
250 | } | 250 | } |
@@ -256,7 +256,7 @@ mod tests { | |||
256 | infer_function_return_type, | 256 | infer_function_return_type, |
257 | r#"fn foo() { | 257 | r#"fn foo() { |
258 | |x: i32| { | 258 | |x: i32| { |
259 | x<|> | 259 | x$0 |
260 | }; | 260 | }; |
261 | }"#, | 261 | }"#, |
262 | r#"fn foo() { | 262 | r#"fn foo() { |
@@ -272,7 +272,7 @@ mod tests { | |||
272 | check_assist( | 272 | check_assist( |
273 | infer_function_return_type, | 273 | infer_function_return_type, |
274 | r#"fn foo() { | 274 | r#"fn foo() { |
275 | |x: i32| { x<|> }; | 275 | |x: i32| { x$0 }; |
276 | }"#, | 276 | }"#, |
277 | r#"fn foo() { | 277 | r#"fn foo() { |
278 | |x: i32| -> i32 { x }; | 278 | |x: i32| -> i32 { x }; |
@@ -286,7 +286,7 @@ mod tests { | |||
286 | check_assist( | 286 | check_assist( |
287 | infer_function_return_type, | 287 | infer_function_return_type, |
288 | r#"fn foo() { | 288 | r#"fn foo() { |
289 | |x: i32| x<|>; | 289 | |x: i32| x$0; |
290 | }"#, | 290 | }"#, |
291 | r#"fn foo() { | 291 | r#"fn foo() { |
292 | |x: i32| -> i32 {x}; | 292 | |x: i32| -> i32 {x}; |
@@ -301,7 +301,7 @@ mod tests { | |||
301 | r#"fn foo() { | 301 | r#"fn foo() { |
302 | || { | 302 | || { |
303 | if true { | 303 | if true { |
304 | 3<|> | 304 | 3$0 |
305 | } else { | 305 | } else { |
306 | 5 | 306 | 5 |
307 | } | 307 | } |
@@ -325,7 +325,7 @@ mod tests { | |||
325 | check_assist_not_applicable( | 325 | check_assist_not_applicable( |
326 | infer_function_return_type, | 326 | infer_function_return_type, |
327 | r#"fn foo() { | 327 | r#"fn foo() { |
328 | || -> i32 { 3<|> } | 328 | || -> i32 { 3$0 } |
329 | }"#, | 329 | }"#, |
330 | ); | 330 | ); |
331 | } | 331 | } |
@@ -336,7 +336,7 @@ mod tests { | |||
336 | infer_function_return_type, | 336 | infer_function_return_type, |
337 | r#"fn foo() { | 337 | r#"fn foo() { |
338 | || -> i32 { | 338 | || -> i32 { |
339 | let x = 3<|>; | 339 | let x = 3$0; |
340 | 6 | 340 | 6 |
341 | } | 341 | } |
342 | }"#, | 342 | }"#, |
diff --git a/crates/assists/src/handlers/inline_function.rs b/crates/assists/src/handlers/inline_function.rs new file mode 100644 index 000000000..6ec99b09b --- /dev/null +++ b/crates/assists/src/handlers/inline_function.rs | |||
@@ -0,0 +1,202 @@ | |||
1 | use ast::make; | ||
2 | use hir::{HasSource, PathResolution}; | ||
3 | use syntax::{ | ||
4 | ast::{self, edit::AstNodeEdit, ArgListOwner}, | ||
5 | AstNode, | ||
6 | }; | ||
7 | use test_utils::mark; | ||
8 | |||
9 | use crate::{ | ||
10 | assist_context::{AssistContext, Assists}, | ||
11 | AssistId, AssistKind, | ||
12 | }; | ||
13 | |||
14 | // Assist: inline_function | ||
15 | // | ||
16 | // Inlines a function body. | ||
17 | // | ||
18 | // ``` | ||
19 | // fn add(a: u32, b: u32) -> u32 { a + b } | ||
20 | // fn main() { | ||
21 | // let x = add$0(1, 2); | ||
22 | // } | ||
23 | // ``` | ||
24 | // -> | ||
25 | // ``` | ||
26 | // fn add(a: u32, b: u32) -> u32 { a + b } | ||
27 | // fn main() { | ||
28 | // let x = { | ||
29 | // let a = 1; | ||
30 | // let b = 2; | ||
31 | // a + b | ||
32 | // }; | ||
33 | // } | ||
34 | // ``` | ||
35 | pub(crate) fn inline_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
36 | let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; | ||
37 | let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; | ||
38 | let path = path_expr.path()?; | ||
39 | |||
40 | let function = match ctx.sema.resolve_path(&path)? { | ||
41 | PathResolution::Def(hir::ModuleDef::Function(f)) => f, | ||
42 | _ => return None, | ||
43 | }; | ||
44 | |||
45 | let function_source = function.source(ctx.db())?; | ||
46 | let arguments: Vec<_> = call.arg_list()?.args().collect(); | ||
47 | let parameters = function_parameter_patterns(&function_source.value)?; | ||
48 | |||
49 | if arguments.len() != parameters.len() { | ||
50 | // Can't inline the function because they've passed the wrong number of | ||
51 | // arguments to this function | ||
52 | mark::hit!(inline_function_incorrect_number_of_arguments); | ||
53 | return None; | ||
54 | } | ||
55 | |||
56 | let new_bindings = parameters.into_iter().zip(arguments); | ||
57 | |||
58 | let body = function_source.value.body()?; | ||
59 | |||
60 | acc.add( | ||
61 | AssistId("inline_function", AssistKind::RefactorInline), | ||
62 | format!("Inline `{}`", path), | ||
63 | call.syntax().text_range(), | ||
64 | |builder| { | ||
65 | let mut statements: Vec<ast::Stmt> = Vec::new(); | ||
66 | |||
67 | for (pattern, value) in new_bindings { | ||
68 | statements.push(make::let_stmt(pattern, Some(value)).into()); | ||
69 | } | ||
70 | |||
71 | statements.extend(body.statements()); | ||
72 | |||
73 | let original_indentation = call.indent_level(); | ||
74 | let replacement = make::block_expr(statements, body.tail_expr()) | ||
75 | .reset_indent() | ||
76 | .indent(original_indentation); | ||
77 | |||
78 | builder.replace_ast(ast::Expr::CallExpr(call), ast::Expr::BlockExpr(replacement)); | ||
79 | }, | ||
80 | ) | ||
81 | } | ||
82 | |||
83 | fn function_parameter_patterns(value: &ast::Fn) -> Option<Vec<ast::Pat>> { | ||
84 | let mut patterns = Vec::new(); | ||
85 | |||
86 | for param in value.param_list()?.params() { | ||
87 | let pattern = param.pat()?; | ||
88 | patterns.push(pattern); | ||
89 | } | ||
90 | |||
91 | Some(patterns) | ||
92 | } | ||
93 | |||
94 | #[cfg(test)] | ||
95 | mod tests { | ||
96 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
97 | |||
98 | use super::*; | ||
99 | |||
100 | #[test] | ||
101 | fn no_args_or_return_value_gets_inlined_without_block() { | ||
102 | check_assist( | ||
103 | inline_function, | ||
104 | r#" | ||
105 | fn foo() { println!("Hello, World!"); } | ||
106 | fn main() { | ||
107 | fo$0o(); | ||
108 | } | ||
109 | "#, | ||
110 | r#" | ||
111 | fn foo() { println!("Hello, World!"); } | ||
112 | fn main() { | ||
113 | { | ||
114 | println!("Hello, World!"); | ||
115 | }; | ||
116 | } | ||
117 | "#, | ||
118 | ); | ||
119 | } | ||
120 | |||
121 | #[test] | ||
122 | fn args_with_side_effects() { | ||
123 | check_assist( | ||
124 | inline_function, | ||
125 | r#" | ||
126 | fn foo(name: String) { println!("Hello, {}!", name); } | ||
127 | fn main() { | ||
128 | foo$0(String::from("Michael")); | ||
129 | } | ||
130 | "#, | ||
131 | r#" | ||
132 | fn foo(name: String) { println!("Hello, {}!", name); } | ||
133 | fn main() { | ||
134 | { | ||
135 | let name = String::from("Michael"); | ||
136 | println!("Hello, {}!", name); | ||
137 | }; | ||
138 | } | ||
139 | "#, | ||
140 | ); | ||
141 | } | ||
142 | |||
143 | #[test] | ||
144 | fn method_inlining_isnt_supported() { | ||
145 | check_assist_not_applicable( | ||
146 | inline_function, | ||
147 | r" | ||
148 | struct Foo; | ||
149 | impl Foo { fn bar(&self) {} } | ||
150 | |||
151 | fn main() { Foo.bar$0(); } | ||
152 | ", | ||
153 | ); | ||
154 | } | ||
155 | |||
156 | #[test] | ||
157 | fn not_applicable_when_incorrect_number_of_parameters_are_provided() { | ||
158 | mark::check!(inline_function_incorrect_number_of_arguments); | ||
159 | check_assist_not_applicable( | ||
160 | inline_function, | ||
161 | r#" | ||
162 | fn add(a: u32, b: u32) -> u32 { a + b } | ||
163 | fn main() { let x = add$0(42); } | ||
164 | "#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
169 | fn function_with_multiple_statements() { | ||
170 | check_assist( | ||
171 | inline_function, | ||
172 | r#" | ||
173 | fn foo(a: u32, b: u32) -> u32 { | ||
174 | let x = a + b; | ||
175 | let y = x - b; | ||
176 | x * y | ||
177 | } | ||
178 | |||
179 | fn main() { | ||
180 | let x = foo$0(1, 2); | ||
181 | } | ||
182 | "#, | ||
183 | r#" | ||
184 | fn foo(a: u32, b: u32) -> u32 { | ||
185 | let x = a + b; | ||
186 | let y = x - b; | ||
187 | x * y | ||
188 | } | ||
189 | |||
190 | fn main() { | ||
191 | let x = { | ||
192 | let a = 1; | ||
193 | let b = 2; | ||
194 | let x = a + b; | ||
195 | let y = x - b; | ||
196 | x * y | ||
197 | }; | ||
198 | } | ||
199 | "#, | ||
200 | ); | ||
201 | } | ||
202 | } | ||
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs index 587eb5feb..dc798daaa 100644 --- a/crates/assists/src/handlers/inline_local_variable.rs +++ b/crates/assists/src/handlers/inline_local_variable.rs | |||
@@ -1,4 +1,7 @@ | |||
1 | use ide_db::{defs::Definition, search::ReferenceKind}; | 1 | use ide_db::{ |
2 | defs::Definition, | ||
3 | search::{FileReference, ReferenceKind}, | ||
4 | }; | ||
2 | use syntax::{ | 5 | use syntax::{ |
3 | ast::{self, AstNode, AstToken}, | 6 | ast::{self, AstNode, AstToken}, |
4 | TextRange, | 7 | TextRange, |
@@ -16,7 +19,7 @@ use crate::{ | |||
16 | // | 19 | // |
17 | // ``` | 20 | // ``` |
18 | // fn main() { | 21 | // fn main() { |
19 | // let x<|> = 1 + 2; | 22 | // let x$0 = 1 + 2; |
20 | // x * 4; | 23 | // x * 4; |
21 | // } | 24 | // } |
22 | // ``` | 25 | // ``` |
@@ -44,8 +47,8 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
44 | 47 | ||
45 | let def = ctx.sema.to_def(&bind_pat)?; | 48 | let def = ctx.sema.to_def(&bind_pat)?; |
46 | let def = Definition::Local(def); | 49 | let def = Definition::Local(def); |
47 | let refs = def.usages(&ctx.sema).all(); | 50 | let usages = def.usages(&ctx.sema).all(); |
48 | if refs.is_empty() { | 51 | if usages.is_empty() { |
49 | mark::hit!(test_not_applicable_if_variable_unused); | 52 | mark::hit!(test_not_applicable_if_variable_unused); |
50 | return None; | 53 | return None; |
51 | }; | 54 | }; |
@@ -63,48 +66,45 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
63 | let_stmt.syntax().text_range() | 66 | let_stmt.syntax().text_range() |
64 | }; | 67 | }; |
65 | 68 | ||
66 | let mut wrap_in_parens = vec![true; refs.len()]; | 69 | let wrap_in_parens = usages |
67 | 70 | .references | |
68 | for (i, desc) in refs.iter().enumerate() { | 71 | .values() |
69 | let usage_node = ctx | 72 | .flatten() |
70 | .covering_node_for_range(desc.file_range.range) | 73 | .map(|&FileReference { range, .. }| { |
71 | .ancestors() | 74 | let usage_node = |
72 | .find_map(ast::PathExpr::cast)?; | 75 | ctx.covering_node_for_range(range).ancestors().find_map(ast::PathExpr::cast)?; |
73 | let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); | 76 | let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); |
74 | let usage_parent = match usage_parent_option { | 77 | let usage_parent = match usage_parent_option { |
75 | Some(u) => u, | 78 | Some(u) => u, |
76 | None => { | 79 | None => return Ok(false), |
77 | wrap_in_parens[i] = false; | 80 | }; |
78 | continue; | 81 | |
79 | } | 82 | Ok(!matches!((&initializer_expr, usage_parent), |
80 | }; | 83 | (ast::Expr::CallExpr(_), _) |
81 | 84 | | (ast::Expr::IndexExpr(_), _) | |
82 | wrap_in_parens[i] = match (&initializer_expr, usage_parent) { | 85 | | (ast::Expr::MethodCallExpr(_), _) |
83 | (ast::Expr::CallExpr(_), _) | 86 | | (ast::Expr::FieldExpr(_), _) |
84 | | (ast::Expr::IndexExpr(_), _) | 87 | | (ast::Expr::TryExpr(_), _) |
85 | | (ast::Expr::MethodCallExpr(_), _) | 88 | | (ast::Expr::RefExpr(_), _) |
86 | | (ast::Expr::FieldExpr(_), _) | 89 | | (ast::Expr::Literal(_), _) |
87 | | (ast::Expr::TryExpr(_), _) | 90 | | (ast::Expr::TupleExpr(_), _) |
88 | | (ast::Expr::RefExpr(_), _) | 91 | | (ast::Expr::ArrayExpr(_), _) |
89 | | (ast::Expr::Literal(_), _) | 92 | | (ast::Expr::ParenExpr(_), _) |
90 | | (ast::Expr::TupleExpr(_), _) | 93 | | (ast::Expr::PathExpr(_), _) |
91 | | (ast::Expr::ArrayExpr(_), _) | 94 | | (ast::Expr::BlockExpr(_), _) |
92 | | (ast::Expr::ParenExpr(_), _) | 95 | | (ast::Expr::EffectExpr(_), _) |
93 | | (ast::Expr::PathExpr(_), _) | 96 | | (_, ast::Expr::CallExpr(_)) |
94 | | (ast::Expr::BlockExpr(_), _) | 97 | | (_, ast::Expr::TupleExpr(_)) |
95 | | (ast::Expr::EffectExpr(_), _) | 98 | | (_, ast::Expr::ArrayExpr(_)) |
96 | | (_, ast::Expr::CallExpr(_)) | 99 | | (_, ast::Expr::ParenExpr(_)) |
97 | | (_, ast::Expr::TupleExpr(_)) | 100 | | (_, ast::Expr::ForExpr(_)) |
98 | | (_, ast::Expr::ArrayExpr(_)) | 101 | | (_, ast::Expr::WhileExpr(_)) |
99 | | (_, ast::Expr::ParenExpr(_)) | 102 | | (_, ast::Expr::BreakExpr(_)) |
100 | | (_, ast::Expr::ForExpr(_)) | 103 | | (_, ast::Expr::ReturnExpr(_)) |
101 | | (_, ast::Expr::WhileExpr(_)) | 104 | | (_, ast::Expr::MatchExpr(_)) |
102 | | (_, ast::Expr::BreakExpr(_)) | 105 | )) |
103 | | (_, ast::Expr::ReturnExpr(_)) | 106 | }) |
104 | | (_, ast::Expr::MatchExpr(_)) => false, | 107 | .collect::<Result<Vec<_>, _>>()?; |
105 | _ => true, | ||
106 | }; | ||
107 | } | ||
108 | 108 | ||
109 | let init_str = initializer_expr.syntax().text().to_string(); | 109 | let init_str = initializer_expr.syntax().text().to_string(); |
110 | let init_in_paren = format!("({})", &init_str); | 110 | let init_in_paren = format!("({})", &init_str); |
@@ -116,15 +116,16 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
116 | target, | 116 | target, |
117 | move |builder| { | 117 | move |builder| { |
118 | builder.delete(delete_range); | 118 | builder.delete(delete_range); |
119 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { | 119 | for (reference, should_wrap) in usages.references.values().flatten().zip(wrap_in_parens) |
120 | { | ||
120 | let replacement = | 121 | let replacement = |
121 | if should_wrap { init_in_paren.clone() } else { init_str.clone() }; | 122 | if should_wrap { init_in_paren.clone() } else { init_str.clone() }; |
122 | match desc.kind { | 123 | match reference.kind { |
123 | ReferenceKind::FieldShorthandForLocal => { | 124 | ReferenceKind::FieldShorthandForLocal => { |
124 | mark::hit!(inline_field_shorthand); | 125 | mark::hit!(inline_field_shorthand); |
125 | builder.insert(desc.file_range.range.end(), format!(": {}", replacement)) | 126 | builder.insert(reference.range.end(), format!(": {}", replacement)) |
126 | } | 127 | } |
127 | _ => builder.replace(desc.file_range.range, replacement), | 128 | _ => builder.replace(reference.range, replacement), |
128 | } | 129 | } |
129 | } | 130 | } |
130 | }, | 131 | }, |
@@ -146,7 +147,7 @@ mod tests { | |||
146 | r" | 147 | r" |
147 | fn bar(a: usize) {} | 148 | fn bar(a: usize) {} |
148 | fn foo() { | 149 | fn foo() { |
149 | let a<|> = 1; | 150 | let a$0 = 1; |
150 | a + 1; | 151 | a + 1; |
151 | if a > 10 { | 152 | if a > 10 { |
152 | } | 153 | } |
@@ -180,7 +181,7 @@ fn foo() { | |||
180 | r" | 181 | r" |
181 | fn bar(a: usize) {} | 182 | fn bar(a: usize) {} |
182 | fn foo() { | 183 | fn foo() { |
183 | let a<|> = 1 + 1; | 184 | let a$0 = 1 + 1; |
184 | a + 1; | 185 | a + 1; |
185 | if a > 10 { | 186 | if a > 10 { |
186 | } | 187 | } |
@@ -214,7 +215,7 @@ fn foo() { | |||
214 | r" | 215 | r" |
215 | fn bar(a: usize) {} | 216 | fn bar(a: usize) {} |
216 | fn foo() { | 217 | fn foo() { |
217 | let a<|> = bar(1); | 218 | let a$0 = bar(1); |
218 | a + 1; | 219 | a + 1; |
219 | if a > 10 { | 220 | if a > 10 { |
220 | } | 221 | } |
@@ -248,7 +249,7 @@ fn foo() { | |||
248 | r" | 249 | r" |
249 | fn bar(a: usize): usize { a } | 250 | fn bar(a: usize): usize { a } |
250 | fn foo() { | 251 | fn foo() { |
251 | let a<|> = bar(1) as u64; | 252 | let a$0 = bar(1) as u64; |
252 | a + 1; | 253 | a + 1; |
253 | if a > 10 { | 254 | if a > 10 { |
254 | } | 255 | } |
@@ -281,7 +282,7 @@ fn foo() { | |||
281 | inline_local_variable, | 282 | inline_local_variable, |
282 | r" | 283 | r" |
283 | fn foo() { | 284 | fn foo() { |
284 | let a<|> = { 10 + 1 }; | 285 | let a$0 = { 10 + 1 }; |
285 | a + 1; | 286 | a + 1; |
286 | if a > 10 { | 287 | if a > 10 { |
287 | } | 288 | } |
@@ -313,7 +314,7 @@ fn foo() { | |||
313 | inline_local_variable, | 314 | inline_local_variable, |
314 | r" | 315 | r" |
315 | fn foo() { | 316 | fn foo() { |
316 | let a<|> = ( 10 + 1 ); | 317 | let a$0 = ( 10 + 1 ); |
317 | a + 1; | 318 | a + 1; |
318 | if a > 10 { | 319 | if a > 10 { |
319 | } | 320 | } |
@@ -346,7 +347,7 @@ fn foo() { | |||
346 | inline_local_variable, | 347 | inline_local_variable, |
347 | r" | 348 | r" |
348 | fn foo() { | 349 | fn foo() { |
349 | let mut a<|> = 1 + 1; | 350 | let mut a$0 = 1 + 1; |
350 | a + 1; | 351 | a + 1; |
351 | }", | 352 | }", |
352 | ); | 353 | ); |
@@ -358,7 +359,7 @@ fn foo() { | |||
358 | inline_local_variable, | 359 | inline_local_variable, |
359 | r" | 360 | r" |
360 | fn foo() { | 361 | fn foo() { |
361 | let a<|> = bar(10 + 1); | 362 | let a$0 = bar(10 + 1); |
362 | let b = a * 10; | 363 | let b = a * 10; |
363 | let c = a as usize; | 364 | let c = a as usize; |
364 | }", | 365 | }", |
@@ -377,7 +378,7 @@ fn foo() { | |||
377 | r" | 378 | r" |
378 | fn foo() { | 379 | fn foo() { |
379 | let x = vec![1, 2, 3]; | 380 | let x = vec![1, 2, 3]; |
380 | let a<|> = x[0]; | 381 | let a$0 = x[0]; |
381 | let b = a * 10; | 382 | let b = a * 10; |
382 | let c = a as usize; | 383 | let c = a as usize; |
383 | }", | 384 | }", |
@@ -397,7 +398,7 @@ fn foo() { | |||
397 | r" | 398 | r" |
398 | fn foo() { | 399 | fn foo() { |
399 | let bar = vec![1]; | 400 | let bar = vec![1]; |
400 | let a<|> = bar.len(); | 401 | let a$0 = bar.len(); |
401 | let b = a * 10; | 402 | let b = a * 10; |
402 | let c = a as usize; | 403 | let c = a as usize; |
403 | }", | 404 | }", |
@@ -421,7 +422,7 @@ struct Bar { | |||
421 | 422 | ||
422 | fn foo() { | 423 | fn foo() { |
423 | let bar = Bar { foo: 1 }; | 424 | let bar = Bar { foo: 1 }; |
424 | let a<|> = bar.foo; | 425 | let a$0 = bar.foo; |
425 | let b = a * 10; | 426 | let b = a * 10; |
426 | let c = a as usize; | 427 | let c = a as usize; |
427 | }", | 428 | }", |
@@ -445,7 +446,7 @@ fn foo() { | |||
445 | r" | 446 | r" |
446 | fn foo() -> Option<usize> { | 447 | fn foo() -> Option<usize> { |
447 | let bar = Some(1); | 448 | let bar = Some(1); |
448 | let a<|> = bar?; | 449 | let a$0 = bar?; |
449 | let b = a * 10; | 450 | let b = a * 10; |
450 | let c = a as usize; | 451 | let c = a as usize; |
451 | None | 452 | None |
@@ -467,7 +468,7 @@ fn foo() -> Option<usize> { | |||
467 | r" | 468 | r" |
468 | fn foo() { | 469 | fn foo() { |
469 | let bar = 10; | 470 | let bar = 10; |
470 | let a<|> = &bar; | 471 | let a$0 = &bar; |
471 | let b = a * 10; | 472 | let b = a * 10; |
472 | }", | 473 | }", |
473 | r" | 474 | r" |
@@ -484,7 +485,7 @@ fn foo() { | |||
484 | inline_local_variable, | 485 | inline_local_variable, |
485 | r" | 486 | r" |
486 | fn foo() { | 487 | fn foo() { |
487 | let a<|> = (10, 20); | 488 | let a$0 = (10, 20); |
488 | let b = a[0]; | 489 | let b = a[0]; |
489 | }", | 490 | }", |
490 | r" | 491 | r" |
@@ -500,7 +501,7 @@ fn foo() { | |||
500 | inline_local_variable, | 501 | inline_local_variable, |
501 | r" | 502 | r" |
502 | fn foo() { | 503 | fn foo() { |
503 | let a<|> = [1, 2, 3]; | 504 | let a$0 = [1, 2, 3]; |
504 | let b = a.len(); | 505 | let b = a.len(); |
505 | }", | 506 | }", |
506 | r" | 507 | r" |
@@ -516,7 +517,7 @@ fn foo() { | |||
516 | inline_local_variable, | 517 | inline_local_variable, |
517 | r" | 518 | r" |
518 | fn foo() { | 519 | fn foo() { |
519 | let a<|> = (10 + 20); | 520 | let a$0 = (10 + 20); |
520 | let b = a * 10; | 521 | let b = a * 10; |
521 | let c = a as usize; | 522 | let c = a as usize; |
522 | }", | 523 | }", |
@@ -535,7 +536,7 @@ fn foo() { | |||
535 | r" | 536 | r" |
536 | fn foo() { | 537 | fn foo() { |
537 | let d = 10; | 538 | let d = 10; |
538 | let a<|> = d; | 539 | let a$0 = d; |
539 | let b = a * 10; | 540 | let b = a * 10; |
540 | let c = a as usize; | 541 | let c = a as usize; |
541 | }", | 542 | }", |
@@ -554,7 +555,7 @@ fn foo() { | |||
554 | inline_local_variable, | 555 | inline_local_variable, |
555 | r" | 556 | r" |
556 | fn foo() { | 557 | fn foo() { |
557 | let a<|> = { 10 }; | 558 | let a$0 = { 10 }; |
558 | let b = a * 10; | 559 | let b = a * 10; |
559 | let c = a as usize; | 560 | let c = a as usize; |
560 | }", | 561 | }", |
@@ -572,7 +573,7 @@ fn foo() { | |||
572 | inline_local_variable, | 573 | inline_local_variable, |
573 | r" | 574 | r" |
574 | fn foo() { | 575 | fn foo() { |
575 | let a<|> = 10 + 20; | 576 | let a$0 = 10 + 20; |
576 | let b = a * 10; | 577 | let b = a * 10; |
577 | let c = (a, 20); | 578 | let c = (a, 20); |
578 | let d = [a, 10]; | 579 | let d = [a, 10]; |
@@ -594,7 +595,7 @@ fn foo() { | |||
594 | inline_local_variable, | 595 | inline_local_variable, |
595 | r" | 596 | r" |
596 | fn foo() { | 597 | fn foo() { |
597 | let a<|> = vec![10, 20]; | 598 | let a$0 = vec![10, 20]; |
598 | for i in a {} | 599 | for i in a {} |
599 | }", | 600 | }", |
600 | r" | 601 | r" |
@@ -610,7 +611,7 @@ fn foo() { | |||
610 | inline_local_variable, | 611 | inline_local_variable, |
611 | r" | 612 | r" |
612 | fn foo() { | 613 | fn foo() { |
613 | let a<|> = 1 > 0; | 614 | let a$0 = 1 > 0; |
614 | while a {} | 615 | while a {} |
615 | }", | 616 | }", |
616 | r" | 617 | r" |
@@ -626,7 +627,7 @@ fn foo() { | |||
626 | inline_local_variable, | 627 | inline_local_variable, |
627 | r" | 628 | r" |
628 | fn foo() { | 629 | fn foo() { |
629 | let a<|> = 1 + 1; | 630 | let a$0 = 1 + 1; |
630 | loop { | 631 | loop { |
631 | break a; | 632 | break a; |
632 | } | 633 | } |
@@ -646,7 +647,7 @@ fn foo() { | |||
646 | inline_local_variable, | 647 | inline_local_variable, |
647 | r" | 648 | r" |
648 | fn foo() { | 649 | fn foo() { |
649 | let a<|> = 1 > 0; | 650 | let a$0 = 1 > 0; |
650 | return a; | 651 | return a; |
651 | }", | 652 | }", |
652 | r" | 653 | r" |
@@ -662,7 +663,7 @@ fn foo() { | |||
662 | inline_local_variable, | 663 | inline_local_variable, |
663 | r" | 664 | r" |
664 | fn foo() { | 665 | fn foo() { |
665 | let a<|> = 1 > 0; | 666 | let a$0 = 1 > 0; |
666 | match a {} | 667 | match a {} |
667 | }", | 668 | }", |
668 | r" | 669 | r" |
@@ -680,7 +681,7 @@ fn foo() { | |||
680 | r" | 681 | r" |
681 | struct S { foo: i32} | 682 | struct S { foo: i32} |
682 | fn main() { | 683 | fn main() { |
683 | let <|>foo = 92; | 684 | let $0foo = 92; |
684 | S { foo } | 685 | S { foo } |
685 | } | 686 | } |
686 | ", | 687 | ", |
@@ -700,7 +701,7 @@ fn main() { | |||
700 | inline_local_variable, | 701 | inline_local_variable, |
701 | r" | 702 | r" |
702 | fn foo() { | 703 | fn foo() { |
703 | let <|>a = 0; | 704 | let $0a = 0; |
704 | } | 705 | } |
705 | ", | 706 | ", |
706 | ) | 707 | ) |
@@ -713,7 +714,7 @@ fn foo() { | |||
713 | inline_local_variable, | 714 | inline_local_variable, |
714 | r" | 715 | r" |
715 | fn main() { | 716 | fn main() { |
716 | let x = <|>1 + 2; | 717 | let x = $01 + 2; |
717 | x * 4; | 718 | x * 4; |
718 | } | 719 | } |
719 | ", | 720 | ", |
diff --git a/crates/assists/src/handlers/introduce_named_lifetime.rs b/crates/assists/src/handlers/introduce_named_lifetime.rs index ab8fe3ea9..3f5f44d69 100644 --- a/crates/assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -14,7 +14,7 @@ static ASSIST_LABEL: &str = "Introduce named lifetime"; | |||
14 | // Change an anonymous lifetime to a named lifetime. | 14 | // Change an anonymous lifetime to a named lifetime. |
15 | // | 15 | // |
16 | // ``` | 16 | // ``` |
17 | // impl Cursor<'_<|>> { | 17 | // impl Cursor<'_$0> { |
18 | // fn node(self) -> &SyntaxNode { | 18 | // fn node(self) -> &SyntaxNode { |
19 | // match self { | 19 | // match self { |
20 | // Cursor::Replace(node) | Cursor::Before(node) => node, | 20 | // Cursor::Replace(node) | Cursor::Before(node) => node, |
@@ -33,7 +33,7 @@ static ASSIST_LABEL: &str = "Introduce named lifetime"; | |||
33 | // } | 33 | // } |
34 | // ``` | 34 | // ``` |
35 | // FIXME: How can we handle renaming any one of multiple anonymous lifetimes? | 35 | // FIXME: How can we handle renaming any one of multiple anonymous lifetimes? |
36 | // FIXME: should also add support for the case fun(f: &Foo) -> &<|>Foo | 36 | // FIXME: should also add support for the case fun(f: &Foo) -> &$0Foo |
37 | pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 37 | pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
38 | let lifetime = | 38 | let lifetime = |
39 | ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?; | 39 | ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?; |
@@ -150,7 +150,7 @@ mod tests { | |||
150 | fn test_example_case() { | 150 | fn test_example_case() { |
151 | check_assist( | 151 | check_assist( |
152 | introduce_named_lifetime, | 152 | introduce_named_lifetime, |
153 | r#"impl Cursor<'_<|>> { | 153 | r#"impl Cursor<'_$0> { |
154 | fn node(self) -> &SyntaxNode { | 154 | fn node(self) -> &SyntaxNode { |
155 | match self { | 155 | match self { |
156 | Cursor::Replace(node) | Cursor::Before(node) => node, | 156 | Cursor::Replace(node) | Cursor::Before(node) => node, |
@@ -171,7 +171,7 @@ mod tests { | |||
171 | fn test_example_case_simplified() { | 171 | fn test_example_case_simplified() { |
172 | check_assist( | 172 | check_assist( |
173 | introduce_named_lifetime, | 173 | introduce_named_lifetime, |
174 | r#"impl Cursor<'_<|>> {"#, | 174 | r#"impl Cursor<'_$0> {"#, |
175 | r#"impl<'a> Cursor<'a> {"#, | 175 | r#"impl<'a> Cursor<'a> {"#, |
176 | ); | 176 | ); |
177 | } | 177 | } |
@@ -180,7 +180,7 @@ mod tests { | |||
180 | fn test_example_case_cursor_after_tick() { | 180 | fn test_example_case_cursor_after_tick() { |
181 | check_assist( | 181 | check_assist( |
182 | introduce_named_lifetime, | 182 | introduce_named_lifetime, |
183 | r#"impl Cursor<'<|>_> {"#, | 183 | r#"impl Cursor<'$0_> {"#, |
184 | r#"impl<'a> Cursor<'a> {"#, | 184 | r#"impl<'a> Cursor<'a> {"#, |
185 | ); | 185 | ); |
186 | } | 186 | } |
@@ -189,7 +189,7 @@ mod tests { | |||
189 | fn test_impl_with_other_type_param() { | 189 | fn test_impl_with_other_type_param() { |
190 | check_assist( | 190 | check_assist( |
191 | introduce_named_lifetime, | 191 | introduce_named_lifetime, |
192 | "impl<I> fmt::Display for SepByBuilder<'_<|>, I> | 192 | "impl<I> fmt::Display for SepByBuilder<'_$0, I> |
193 | where | 193 | where |
194 | I: Iterator, | 194 | I: Iterator, |
195 | I::Item: fmt::Display, | 195 | I::Item: fmt::Display, |
@@ -206,28 +206,28 @@ mod tests { | |||
206 | fn test_example_case_cursor_before_tick() { | 206 | fn test_example_case_cursor_before_tick() { |
207 | check_assist( | 207 | check_assist( |
208 | introduce_named_lifetime, | 208 | introduce_named_lifetime, |
209 | r#"impl Cursor<<|>'_> {"#, | 209 | r#"impl Cursor<$0'_> {"#, |
210 | r#"impl<'a> Cursor<'a> {"#, | 210 | r#"impl<'a> Cursor<'a> {"#, |
211 | ); | 211 | ); |
212 | } | 212 | } |
213 | 213 | ||
214 | #[test] | 214 | #[test] |
215 | fn test_not_applicable_cursor_position() { | 215 | fn test_not_applicable_cursor_position() { |
216 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<'_><|> {"#); | 216 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<'_>$0 {"#); |
217 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<|><'_> {"#); | 217 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor$0<'_> {"#); |
218 | } | 218 | } |
219 | 219 | ||
220 | #[test] | 220 | #[test] |
221 | fn test_not_applicable_lifetime_already_name() { | 221 | fn test_not_applicable_lifetime_already_name() { |
222 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<'a<|>> {"#); | 222 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<'a$0> {"#); |
223 | check_assist_not_applicable(introduce_named_lifetime, r#"fn my_fun<'a>() -> X<'a<|>>"#); | 223 | check_assist_not_applicable(introduce_named_lifetime, r#"fn my_fun<'a>() -> X<'a$0>"#); |
224 | } | 224 | } |
225 | 225 | ||
226 | #[test] | 226 | #[test] |
227 | fn test_with_type_parameter() { | 227 | fn test_with_type_parameter() { |
228 | check_assist( | 228 | check_assist( |
229 | introduce_named_lifetime, | 229 | introduce_named_lifetime, |
230 | r#"impl<T> Cursor<T, '_<|>>"#, | 230 | r#"impl<T> Cursor<T, '_$0>"#, |
231 | r#"impl<T, 'a> Cursor<T, 'a>"#, | 231 | r#"impl<T, 'a> Cursor<T, 'a>"#, |
232 | ); | 232 | ); |
233 | } | 233 | } |
@@ -236,7 +236,7 @@ mod tests { | |||
236 | fn test_with_existing_lifetime_name_conflict() { | 236 | fn test_with_existing_lifetime_name_conflict() { |
237 | check_assist( | 237 | check_assist( |
238 | introduce_named_lifetime, | 238 | introduce_named_lifetime, |
239 | r#"impl<'a, 'b> Cursor<'a, 'b, '_<|>>"#, | 239 | r#"impl<'a, 'b> Cursor<'a, 'b, '_$0>"#, |
240 | r#"impl<'a, 'b, 'c> Cursor<'a, 'b, 'c>"#, | 240 | r#"impl<'a, 'b, 'c> Cursor<'a, 'b, 'c>"#, |
241 | ); | 241 | ); |
242 | } | 242 | } |
@@ -245,7 +245,7 @@ mod tests { | |||
245 | fn test_function_return_value_anon_lifetime_param() { | 245 | fn test_function_return_value_anon_lifetime_param() { |
246 | check_assist( | 246 | check_assist( |
247 | introduce_named_lifetime, | 247 | introduce_named_lifetime, |
248 | r#"fn my_fun() -> X<'_<|>>"#, | 248 | r#"fn my_fun() -> X<'_$0>"#, |
249 | r#"fn my_fun<'a>() -> X<'a>"#, | 249 | r#"fn my_fun<'a>() -> X<'a>"#, |
250 | ); | 250 | ); |
251 | } | 251 | } |
@@ -254,7 +254,7 @@ mod tests { | |||
254 | fn test_function_return_value_anon_reference_lifetime() { | 254 | fn test_function_return_value_anon_reference_lifetime() { |
255 | check_assist( | 255 | check_assist( |
256 | introduce_named_lifetime, | 256 | introduce_named_lifetime, |
257 | r#"fn my_fun() -> &'_<|> X"#, | 257 | r#"fn my_fun() -> &'_$0 X"#, |
258 | r#"fn my_fun<'a>() -> &'a X"#, | 258 | r#"fn my_fun<'a>() -> &'a X"#, |
259 | ); | 259 | ); |
260 | } | 260 | } |
@@ -263,7 +263,7 @@ mod tests { | |||
263 | fn test_function_param_anon_lifetime() { | 263 | fn test_function_param_anon_lifetime() { |
264 | check_assist( | 264 | check_assist( |
265 | introduce_named_lifetime, | 265 | introduce_named_lifetime, |
266 | r#"fn my_fun(x: X<'_<|>>)"#, | 266 | r#"fn my_fun(x: X<'_$0>)"#, |
267 | r#"fn my_fun<'a>(x: X<'a>)"#, | 267 | r#"fn my_fun<'a>(x: X<'a>)"#, |
268 | ); | 268 | ); |
269 | } | 269 | } |
@@ -272,7 +272,7 @@ mod tests { | |||
272 | fn test_function_add_lifetime_to_params() { | 272 | fn test_function_add_lifetime_to_params() { |
273 | check_assist( | 273 | check_assist( |
274 | introduce_named_lifetime, | 274 | introduce_named_lifetime, |
275 | r#"fn my_fun(f: &Foo) -> X<'_<|>>"#, | 275 | r#"fn my_fun(f: &Foo) -> X<'_$0>"#, |
276 | r#"fn my_fun<'a>(f: &'a Foo) -> X<'a>"#, | 276 | r#"fn my_fun<'a>(f: &'a Foo) -> X<'a>"#, |
277 | ); | 277 | ); |
278 | } | 278 | } |
@@ -281,7 +281,7 @@ mod tests { | |||
281 | fn test_function_add_lifetime_to_params_in_presence_of_other_lifetime() { | 281 | fn test_function_add_lifetime_to_params_in_presence_of_other_lifetime() { |
282 | check_assist( | 282 | check_assist( |
283 | introduce_named_lifetime, | 283 | introduce_named_lifetime, |
284 | r#"fn my_fun<'other>(f: &Foo, b: &'other Bar) -> X<'_<|>>"#, | 284 | r#"fn my_fun<'other>(f: &Foo, b: &'other Bar) -> X<'_$0>"#, |
285 | r#"fn my_fun<'other, 'a>(f: &'a Foo, b: &'other Bar) -> X<'a>"#, | 285 | r#"fn my_fun<'other, 'a>(f: &'a Foo, b: &'other Bar) -> X<'a>"#, |
286 | ); | 286 | ); |
287 | } | 287 | } |
@@ -291,7 +291,7 @@ mod tests { | |||
291 | // this is not permitted under lifetime elision rules | 291 | // this is not permitted under lifetime elision rules |
292 | check_assist_not_applicable( | 292 | check_assist_not_applicable( |
293 | introduce_named_lifetime, | 293 | introduce_named_lifetime, |
294 | r#"fn my_fun(f: &Foo, b: &Bar) -> X<'_<|>>"#, | 294 | r#"fn my_fun(f: &Foo, b: &Bar) -> X<'_$0>"#, |
295 | ); | 295 | ); |
296 | } | 296 | } |
297 | 297 | ||
@@ -299,7 +299,7 @@ mod tests { | |||
299 | fn test_function_add_lifetime_to_self_ref_param() { | 299 | fn test_function_add_lifetime_to_self_ref_param() { |
300 | check_assist( | 300 | check_assist( |
301 | introduce_named_lifetime, | 301 | introduce_named_lifetime, |
302 | r#"fn my_fun<'other>(&self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#, | 302 | r#"fn my_fun<'other>(&self, f: &Foo, b: &'other Bar) -> X<'_$0>"#, |
303 | r#"fn my_fun<'other, 'a>(&'a self, f: &Foo, b: &'other Bar) -> X<'a>"#, | 303 | r#"fn my_fun<'other, 'a>(&'a self, f: &Foo, b: &'other Bar) -> X<'a>"#, |
304 | ); | 304 | ); |
305 | } | 305 | } |
@@ -308,7 +308,7 @@ mod tests { | |||
308 | fn test_function_add_lifetime_to_param_with_non_ref_self() { | 308 | fn test_function_add_lifetime_to_param_with_non_ref_self() { |
309 | check_assist( | 309 | check_assist( |
310 | introduce_named_lifetime, | 310 | introduce_named_lifetime, |
311 | r#"fn my_fun<'other>(self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#, | 311 | r#"fn my_fun<'other>(self, f: &Foo, b: &'other Bar) -> X<'_$0>"#, |
312 | r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#, | 312 | r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#, |
313 | ); | 313 | ); |
314 | } | 314 | } |
diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs index f9c33b3f7..5b69dafd4 100644 --- a/crates/assists/src/handlers/invert_if.rs +++ b/crates/assists/src/handlers/invert_if.rs | |||
@@ -18,7 +18,7 @@ use crate::{ | |||
18 | // | 18 | // |
19 | // ``` | 19 | // ``` |
20 | // fn main() { | 20 | // fn main() { |
21 | // if<|> !y { A } else { B } | 21 | // if$0 !y { A } else { B } |
22 | // } | 22 | // } |
23 | // ``` | 23 | // ``` |
24 | // -> | 24 | // -> |
@@ -72,7 +72,7 @@ mod tests { | |||
72 | fn invert_if_composite_condition() { | 72 | fn invert_if_composite_condition() { |
73 | check_assist( | 73 | check_assist( |
74 | invert_if, | 74 | invert_if, |
75 | "fn f() { i<|>f x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }", | 75 | "fn f() { i$0f x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }", |
76 | "fn f() { if !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }", | 76 | "fn f() { if !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }", |
77 | ) | 77 | ) |
78 | } | 78 | } |
@@ -81,7 +81,7 @@ mod tests { | |||
81 | fn invert_if_remove_not_parentheses() { | 81 | fn invert_if_remove_not_parentheses() { |
82 | check_assist( | 82 | check_assist( |
83 | invert_if, | 83 | invert_if, |
84 | "fn f() { i<|>f !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }", | 84 | "fn f() { i$0f !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }", |
85 | "fn f() { if x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }", | 85 | "fn f() { if x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }", |
86 | ) | 86 | ) |
87 | } | 87 | } |
@@ -90,7 +90,7 @@ mod tests { | |||
90 | fn invert_if_remove_inequality() { | 90 | fn invert_if_remove_inequality() { |
91 | check_assist( | 91 | check_assist( |
92 | invert_if, | 92 | invert_if, |
93 | "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", | 93 | "fn f() { i$0f x != 3 { 1 } else { 3 + 2 } }", |
94 | "fn f() { if x == 3 { 3 + 2 } else { 1 } }", | 94 | "fn f() { if x == 3 { 3 + 2 } else { 1 } }", |
95 | ) | 95 | ) |
96 | } | 96 | } |
@@ -99,7 +99,7 @@ mod tests { | |||
99 | fn invert_if_remove_not() { | 99 | fn invert_if_remove_not() { |
100 | check_assist( | 100 | check_assist( |
101 | invert_if, | 101 | invert_if, |
102 | "fn f() { <|>if !cond { 3 * 2 } else { 1 } }", | 102 | "fn f() { $0if !cond { 3 * 2 } else { 1 } }", |
103 | "fn f() { if cond { 1 } else { 3 * 2 } }", | 103 | "fn f() { if cond { 1 } else { 3 * 2 } }", |
104 | ) | 104 | ) |
105 | } | 105 | } |
@@ -108,21 +108,21 @@ mod tests { | |||
108 | fn invert_if_general_case() { | 108 | fn invert_if_general_case() { |
109 | check_assist( | 109 | check_assist( |
110 | invert_if, | 110 | invert_if, |
111 | "fn f() { i<|>f cond { 3 * 2 } else { 1 } }", | 111 | "fn f() { i$0f cond { 3 * 2 } else { 1 } }", |
112 | "fn f() { if !cond { 1 } else { 3 * 2 } }", | 112 | "fn f() { if !cond { 1 } else { 3 * 2 } }", |
113 | ) | 113 | ) |
114 | } | 114 | } |
115 | 115 | ||
116 | #[test] | 116 | #[test] |
117 | fn invert_if_doesnt_apply_with_cursor_not_on_if() { | 117 | fn invert_if_doesnt_apply_with_cursor_not_on_if() { |
118 | check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }") | 118 | check_assist_not_applicable(invert_if, "fn f() { if !$0cond { 3 * 2 } else { 1 } }") |
119 | } | 119 | } |
120 | 120 | ||
121 | #[test] | 121 | #[test] |
122 | fn invert_if_doesnt_apply_with_if_let() { | 122 | fn invert_if_doesnt_apply_with_if_let() { |
123 | check_assist_not_applicable( | 123 | check_assist_not_applicable( |
124 | invert_if, | 124 | invert_if, |
125 | "fn f() { i<|>f let Some(_) = Some(1) { 1 } else { 0 } }", | 125 | "fn f() { i$0f let Some(_) = Some(1) { 1 } else { 0 } }", |
126 | ) | 126 | ) |
127 | } | 127 | } |
128 | 128 | ||
@@ -130,7 +130,7 @@ mod tests { | |||
130 | fn invert_if_option_case() { | 130 | fn invert_if_option_case() { |
131 | check_assist( | 131 | check_assist( |
132 | invert_if, | 132 | invert_if, |
133 | "fn f() { if<|> doc_style.is_some() { Class::DocComment } else { Class::Comment } }", | 133 | "fn f() { if$0 doc_style.is_some() { Class::DocComment } else { Class::Comment } }", |
134 | "fn f() { if doc_style.is_none() { Class::Comment } else { Class::DocComment } }", | 134 | "fn f() { if doc_style.is_none() { Class::Comment } else { Class::DocComment } }", |
135 | ) | 135 | ) |
136 | } | 136 | } |
@@ -139,7 +139,7 @@ mod tests { | |||
139 | fn invert_if_result_case() { | 139 | fn invert_if_result_case() { |
140 | check_assist( | 140 | check_assist( |
141 | invert_if, | 141 | invert_if, |
142 | "fn f() { i<|>f doc_style.is_err() { Class::Err } else { Class::Ok } }", | 142 | "fn f() { i$0f doc_style.is_err() { Class::Err } else { Class::Ok } }", |
143 | "fn f() { if doc_style.is_ok() { Class::Ok } else { Class::Err } }", | 143 | "fn f() { if doc_style.is_ok() { Class::Ok } else { Class::Err } }", |
144 | ) | 144 | ) |
145 | } | 145 | } |
diff --git a/crates/assists/src/handlers/merge_imports.rs b/crates/assists/src/handlers/merge_imports.rs index 2f0dc7831..7bd7e1e36 100644 --- a/crates/assists/src/handlers/merge_imports.rs +++ b/crates/assists/src/handlers/merge_imports.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | // Merges two imports with a common prefix. | 15 | // Merges two imports with a common prefix. |
16 | // | 16 | // |
17 | // ``` | 17 | // ``` |
18 | // use std::<|>fmt::Formatter; | 18 | // use std::$0fmt::Formatter; |
19 | // use std::io; | 19 | // use std::io; |
20 | // ``` | 20 | // ``` |
21 | // -> | 21 | // -> |
@@ -75,7 +75,7 @@ mod tests { | |||
75 | check_assist( | 75 | check_assist( |
76 | merge_imports, | 76 | merge_imports, |
77 | r" | 77 | r" |
78 | use std::fmt<|>::{Display, Debug}; | 78 | use std::fmt$0::{Display, Debug}; |
79 | use std::fmt::{Display, Debug}; | 79 | use std::fmt::{Display, Debug}; |
80 | ", | 80 | ", |
81 | r" | 81 | r" |
@@ -89,7 +89,7 @@ use std::fmt::{Debug, Display}; | |||
89 | check_assist( | 89 | check_assist( |
90 | merge_imports, | 90 | merge_imports, |
91 | r" | 91 | r" |
92 | use std::fmt<|>::Debug; | 92 | use std::fmt$0::Debug; |
93 | use std::fmt::Display; | 93 | use std::fmt::Display; |
94 | ", | 94 | ", |
95 | r" | 95 | r" |
@@ -104,7 +104,7 @@ use std::fmt::{Debug, Display}; | |||
104 | merge_imports, | 104 | merge_imports, |
105 | r" | 105 | r" |
106 | use std::fmt::Debug; | 106 | use std::fmt::Debug; |
107 | use std::fmt<|>::Display; | 107 | use std::fmt$0::Display; |
108 | ", | 108 | ", |
109 | r" | 109 | r" |
110 | use std::fmt::{Debug, Display}; | 110 | use std::fmt::{Debug, Display}; |
@@ -117,7 +117,7 @@ use std::fmt::{Debug, Display}; | |||
117 | check_assist( | 117 | check_assist( |
118 | merge_imports, | 118 | merge_imports, |
119 | r" | 119 | r" |
120 | use std::fmt<|>; | 120 | use std::fmt$0; |
121 | use std::fmt::Display; | 121 | use std::fmt::Display; |
122 | ", | 122 | ", |
123 | r" | 123 | r" |
@@ -131,7 +131,7 @@ use std::fmt::{self, Display}; | |||
131 | check_assist( | 131 | check_assist( |
132 | merge_imports, | 132 | merge_imports, |
133 | r" | 133 | r" |
134 | use std::{fmt, <|>fmt::Display}; | 134 | use std::{fmt, $0fmt::Display}; |
135 | ", | 135 | ", |
136 | r" | 136 | r" |
137 | use std::{fmt::{self, Display}}; | 137 | use std::{fmt::{self, Display}}; |
@@ -144,7 +144,7 @@ use std::{fmt::{self, Display}}; | |||
144 | check_assist_not_applicable( | 144 | check_assist_not_applicable( |
145 | merge_imports, | 145 | merge_imports, |
146 | r" | 146 | r" |
147 | pub use std::fmt<|>::Debug; | 147 | pub use std::fmt$0::Debug; |
148 | use std::fmt::Display; | 148 | use std::fmt::Display; |
149 | ", | 149 | ", |
150 | ); | 150 | ); |
@@ -155,7 +155,7 @@ use std::fmt::Display; | |||
155 | check_assist_not_applicable( | 155 | check_assist_not_applicable( |
156 | merge_imports, | 156 | merge_imports, |
157 | r" | 157 | r" |
158 | use std::fmt<|>::Debug; | 158 | use std::fmt$0::Debug; |
159 | pub use std::fmt::Display; | 159 | pub use std::fmt::Display; |
160 | ", | 160 | ", |
161 | ); | 161 | ); |
@@ -166,7 +166,7 @@ pub use std::fmt::Display; | |||
166 | check_assist_not_applicable( | 166 | check_assist_not_applicable( |
167 | merge_imports, | 167 | merge_imports, |
168 | r" | 168 | r" |
169 | pub(crate) use std::fmt<|>::Debug; | 169 | pub(crate) use std::fmt$0::Debug; |
170 | pub use std::fmt::Display; | 170 | pub use std::fmt::Display; |
171 | ", | 171 | ", |
172 | ); | 172 | ); |
@@ -177,7 +177,7 @@ pub use std::fmt::Display; | |||
177 | check_assist_not_applicable( | 177 | check_assist_not_applicable( |
178 | merge_imports, | 178 | merge_imports, |
179 | r" | 179 | r" |
180 | pub use std::fmt<|>::Debug; | 180 | pub use std::fmt$0::Debug; |
181 | pub(crate) use std::fmt::Display; | 181 | pub(crate) use std::fmt::Display; |
182 | ", | 182 | ", |
183 | ); | 183 | ); |
@@ -188,7 +188,7 @@ pub(crate) use std::fmt::Display; | |||
188 | check_assist( | 188 | check_assist( |
189 | merge_imports, | 189 | merge_imports, |
190 | r" | 190 | r" |
191 | pub use std::fmt<|>::Debug; | 191 | pub use std::fmt$0::Debug; |
192 | pub use std::fmt::Display; | 192 | pub use std::fmt::Display; |
193 | ", | 193 | ", |
194 | r" | 194 | r" |
@@ -202,7 +202,7 @@ pub use std::fmt::{Debug, Display}; | |||
202 | check_assist( | 202 | check_assist( |
203 | merge_imports, | 203 | merge_imports, |
204 | r" | 204 | r" |
205 | pub(crate) use std::fmt<|>::Debug; | 205 | pub(crate) use std::fmt$0::Debug; |
206 | pub(crate) use std::fmt::Display; | 206 | pub(crate) use std::fmt::Display; |
207 | ", | 207 | ", |
208 | r" | 208 | r" |
@@ -216,7 +216,7 @@ pub(crate) use std::fmt::{Debug, Display}; | |||
216 | check_assist( | 216 | check_assist( |
217 | merge_imports, | 217 | merge_imports, |
218 | r" | 218 | r" |
219 | use std::{fmt<|>::Debug, fmt::Display}; | 219 | use std::{fmt$0::Debug, fmt::Display}; |
220 | ", | 220 | ", |
221 | r" | 221 | r" |
222 | use std::{fmt::{Debug, Display}}; | 222 | use std::{fmt::{Debug, Display}}; |
@@ -229,7 +229,7 @@ use std::{fmt::{Debug, Display}}; | |||
229 | check_assist( | 229 | check_assist( |
230 | merge_imports, | 230 | merge_imports, |
231 | r" | 231 | r" |
232 | use std::{fmt::Debug, fmt<|>::Display}; | 232 | use std::{fmt::Debug, fmt$0::Display}; |
233 | ", | 233 | ", |
234 | r" | 234 | r" |
235 | use std::{fmt::{Debug, Display}}; | 235 | use std::{fmt::{Debug, Display}}; |
@@ -242,7 +242,7 @@ use std::{fmt::{Debug, Display}}; | |||
242 | check_assist( | 242 | check_assist( |
243 | merge_imports, | 243 | merge_imports, |
244 | r" | 244 | r" |
245 | use std<|>::cell::*; | 245 | use std$0::cell::*; |
246 | use std::str; | 246 | use std::str; |
247 | ", | 247 | ", |
248 | r" | 248 | r" |
@@ -256,7 +256,7 @@ use std::{cell::*, str}; | |||
256 | check_assist( | 256 | check_assist( |
257 | merge_imports, | 257 | merge_imports, |
258 | r" | 258 | r" |
259 | use std<|>::cell::*; | 259 | use std$0::cell::*; |
260 | use std::str::*; | 260 | use std::str::*; |
261 | ", | 261 | ", |
262 | r" | 262 | r" |
@@ -270,7 +270,7 @@ use std::{cell::*, str::*}; | |||
270 | check_assist( | 270 | check_assist( |
271 | merge_imports, | 271 | merge_imports, |
272 | r" | 272 | r" |
273 | use foo<|>::bar; | 273 | use foo$0::bar; |
274 | use foo::baz; | 274 | use foo::baz; |
275 | 275 | ||
276 | /// Doc comment | 276 | /// Doc comment |
@@ -289,7 +289,7 @@ use foo::{bar, baz}; | |||
289 | merge_imports, | 289 | merge_imports, |
290 | r" | 290 | r" |
291 | use { | 291 | use { |
292 | foo<|>::bar, | 292 | foo$0::bar, |
293 | foo::baz, | 293 | foo::baz, |
294 | }; | 294 | }; |
295 | ", | 295 | ", |
@@ -304,7 +304,7 @@ use { | |||
304 | r" | 304 | r" |
305 | use { | 305 | use { |
306 | foo::baz, | 306 | foo::baz, |
307 | foo<|>::bar, | 307 | foo$0::bar, |
308 | }; | 308 | }; |
309 | ", | 309 | ", |
310 | r" | 310 | r" |
@@ -321,7 +321,7 @@ use { | |||
321 | merge_imports, | 321 | merge_imports, |
322 | r" | 322 | r" |
323 | use foo::bar::baz; | 323 | use foo::bar::baz; |
324 | use foo::<|>{ | 324 | use foo::$0{ |
325 | FooBar, | 325 | FooBar, |
326 | }; | 326 | }; |
327 | ", | 327 | ", |
@@ -336,7 +336,7 @@ use foo::{FooBar, bar::baz}; | |||
336 | check_assist_not_applicable( | 336 | check_assist_not_applicable( |
337 | merge_imports, | 337 | merge_imports, |
338 | r" | 338 | r" |
339 | use std::<|> | 339 | use std::$0 |
340 | fn main() {}", | 340 | fn main() {}", |
341 | ); | 341 | ); |
342 | } | 342 | } |
diff --git a/crates/assists/src/handlers/merge_match_arms.rs b/crates/assists/src/handlers/merge_match_arms.rs index c347eb40e..9bf076cb9 100644 --- a/crates/assists/src/handlers/merge_match_arms.rs +++ b/crates/assists/src/handlers/merge_match_arms.rs | |||
@@ -17,7 +17,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange}; | |||
17 | // | 17 | // |
18 | // fn handle(action: Action) { | 18 | // fn handle(action: Action) { |
19 | // match action { | 19 | // match action { |
20 | // <|>Action::Move(..) => foo(), | 20 | // $0Action::Move(..) => foo(), |
21 | // Action::Stop => foo(), | 21 | // Action::Stop => foo(), |
22 | // } | 22 | // } |
23 | // } | 23 | // } |
@@ -106,7 +106,7 @@ mod tests { | |||
106 | fn main() { | 106 | fn main() { |
107 | let x = X::A; | 107 | let x = X::A; |
108 | let y = match x { | 108 | let y = match x { |
109 | X::A => { 1i32<|> } | 109 | X::A => { 1i32$0 } |
110 | X::B => { 1i32 } | 110 | X::B => { 1i32 } |
111 | X::C => { 2i32 } | 111 | X::C => { 2i32 } |
112 | } | 112 | } |
@@ -138,7 +138,7 @@ mod tests { | |||
138 | fn main() { | 138 | fn main() { |
139 | let x = X::A; | 139 | let x = X::A; |
140 | let y = match x { | 140 | let y = match x { |
141 | X::A | X::B => {<|> 1i32 }, | 141 | X::A | X::B => {$0 1i32 }, |
142 | X::C | X::D => { 1i32 }, | 142 | X::C | X::D => { 1i32 }, |
143 | X::E => { 2i32 }, | 143 | X::E => { 2i32 }, |
144 | } | 144 | } |
@@ -171,7 +171,7 @@ mod tests { | |||
171 | let x = X::A; | 171 | let x = X::A; |
172 | let y = match x { | 172 | let y = match x { |
173 | X::A => { 1i32 }, | 173 | X::A => { 1i32 }, |
174 | X::B => { 2i<|>32 }, | 174 | X::B => { 2i$032 }, |
175 | _ => { 2i32 } | 175 | _ => { 2i32 } |
176 | } | 176 | } |
177 | } | 177 | } |
@@ -200,7 +200,7 @@ mod tests { | |||
200 | 200 | ||
201 | fn main() { | 201 | fn main() { |
202 | match X::A { | 202 | match X::A { |
203 | X::A<|> => 92, | 203 | X::A$0 => 92, |
204 | X::B => 92, | 204 | X::B => 92, |
205 | X::C => 92, | 205 | X::C => 92, |
206 | X::D => 62, | 206 | X::D => 62, |
@@ -237,7 +237,7 @@ mod tests { | |||
237 | fn main() { | 237 | fn main() { |
238 | let x = X::A; | 238 | let x = X::A; |
239 | let y = match x { | 239 | let y = match x { |
240 | X::A(a) if a > 5 => { <|>1i32 }, | 240 | X::A(a) if a > 5 => { $01i32 }, |
241 | X::B => { 1i32 }, | 241 | X::B => { 1i32 }, |
242 | X::C => { 2i32 } | 242 | X::C => { 2i32 } |
243 | } | 243 | } |
diff --git a/crates/assists/src/handlers/move_bounds.rs b/crates/assists/src/handlers/move_bounds.rs index e2e461520..cf260c6f8 100644 --- a/crates/assists/src/handlers/move_bounds.rs +++ b/crates/assists/src/handlers/move_bounds.rs | |||
@@ -12,7 +12,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
12 | // Moves inline type bounds to a where clause. | 12 | // Moves inline type bounds to a where clause. |
13 | // | 13 | // |
14 | // ``` | 14 | // ``` |
15 | // fn apply<T, U, <|>F: FnOnce(T) -> U>(f: F, x: T) -> U { | 15 | // fn apply<T, U, $0F: FnOnce(T) -> U>(f: F, x: T) -> U { |
16 | // f(x) | 16 | // f(x) |
17 | // } | 17 | // } |
18 | // ``` | 18 | // ``` |
@@ -103,7 +103,7 @@ mod tests { | |||
103 | check_assist( | 103 | check_assist( |
104 | move_bounds_to_where_clause, | 104 | move_bounds_to_where_clause, |
105 | r#" | 105 | r#" |
106 | fn foo<T: u32, <|>F: FnOnce(T) -> T>() {} | 106 | fn foo<T: u32, $0F: FnOnce(T) -> T>() {} |
107 | "#, | 107 | "#, |
108 | r#" | 108 | r#" |
109 | fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} | 109 | fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} |
@@ -116,7 +116,7 @@ mod tests { | |||
116 | check_assist( | 116 | check_assist( |
117 | move_bounds_to_where_clause, | 117 | move_bounds_to_where_clause, |
118 | r#" | 118 | r#" |
119 | impl<U: u32, <|>T> A<U, T> {} | 119 | impl<U: u32, $0T> A<U, T> {} |
120 | "#, | 120 | "#, |
121 | r#" | 121 | r#" |
122 | impl<U, T> A<U, T> where U: u32 {} | 122 | impl<U, T> A<U, T> where U: u32 {} |
@@ -129,7 +129,7 @@ mod tests { | |||
129 | check_assist( | 129 | check_assist( |
130 | move_bounds_to_where_clause, | 130 | move_bounds_to_where_clause, |
131 | r#" | 131 | r#" |
132 | struct A<<|>T: Iterator<Item = u32>> {} | 132 | struct A<$0T: Iterator<Item = u32>> {} |
133 | "#, | 133 | "#, |
134 | r#" | 134 | r#" |
135 | struct A<T> where T: Iterator<Item = u32> {} | 135 | struct A<T> where T: Iterator<Item = u32> {} |
@@ -142,7 +142,7 @@ mod tests { | |||
142 | check_assist( | 142 | check_assist( |
143 | move_bounds_to_where_clause, | 143 | move_bounds_to_where_clause, |
144 | r#" | 144 | r#" |
145 | struct Pair<<|>T: u32>(T, T); | 145 | struct Pair<$0T: u32>(T, T); |
146 | "#, | 146 | "#, |
147 | r#" | 147 | r#" |
148 | struct Pair<T>(T, T) where T: u32; | 148 | struct Pair<T>(T, T) where T: u32; |
diff --git a/crates/assists/src/handlers/move_guard.rs b/crates/assists/src/handlers/move_guard.rs index eaffd80ce..3f22302a9 100644 --- a/crates/assists/src/handlers/move_guard.rs +++ b/crates/assists/src/handlers/move_guard.rs | |||
@@ -14,7 +14,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
14 | // | 14 | // |
15 | // fn handle(action: Action) { | 15 | // fn handle(action: Action) { |
16 | // match action { | 16 | // match action { |
17 | // Action::Move { distance } <|>if distance > 10 => foo(), | 17 | // Action::Move { distance } $0if distance > 10 => foo(), |
18 | // _ => (), | 18 | // _ => (), |
19 | // } | 19 | // } |
20 | // } | 20 | // } |
@@ -74,7 +74,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> | |||
74 | // | 74 | // |
75 | // fn handle(action: Action) { | 75 | // fn handle(action: Action) { |
76 | // match action { | 76 | // match action { |
77 | // Action::Move { distance } => <|>if distance > 10 { foo() }, | 77 | // Action::Move { distance } => $0if distance > 10 { foo() }, |
78 | // _ => (), | 78 | // _ => (), |
79 | // } | 79 | // } |
80 | // } | 80 | // } |
@@ -98,7 +98,7 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex | |||
98 | let mut replace_node = None; | 98 | let mut replace_node = None; |
99 | let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone()).or_else(|| { | 99 | let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone()).or_else(|| { |
100 | let block_expr = BlockExpr::cast(arm_body.syntax().clone())?; | 100 | let block_expr = BlockExpr::cast(arm_body.syntax().clone())?; |
101 | if let Expr::IfExpr(e) = block_expr.expr()? { | 101 | if let Expr::IfExpr(e) = block_expr.tail_expr()? { |
102 | replace_node = Some(block_expr.syntax().clone()); | 102 | replace_node = Some(block_expr.syntax().clone()); |
103 | Some(e) | 103 | Some(e) |
104 | } else { | 104 | } else { |
@@ -128,7 +128,7 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex | |||
128 | |edit| { | 128 | |edit| { |
129 | let then_only_expr = then_block.statements().next().is_none(); | 129 | let then_only_expr = then_block.statements().next().is_none(); |
130 | 130 | ||
131 | match &then_block.expr() { | 131 | match &then_block.tail_expr() { |
132 | Some(then_expr) if then_only_expr => { | 132 | Some(then_expr) if then_only_expr => { |
133 | edit.replace(replace_node.text_range(), then_expr.syntax().text()) | 133 | edit.replace(replace_node.text_range(), then_expr.syntax().text()) |
134 | } | 134 | } |
@@ -158,7 +158,7 @@ mod tests { | |||
158 | r#" | 158 | r#" |
159 | fn main() { | 159 | fn main() { |
160 | match 92 { | 160 | match 92 { |
161 | x <|>if x > 10 => false, | 161 | x $0if x > 10 => false, |
162 | _ => true | 162 | _ => true |
163 | } | 163 | } |
164 | } | 164 | } |
@@ -174,7 +174,7 @@ fn main() { | |||
174 | r#" | 174 | r#" |
175 | fn main() { | 175 | fn main() { |
176 | match 92 { | 176 | match 92 { |
177 | x <|>if x > 10 => false, | 177 | x $0if x > 10 => false, |
178 | _ => true | 178 | _ => true |
179 | } | 179 | } |
180 | } | 180 | } |
@@ -199,7 +199,7 @@ fn main() { | |||
199 | r#" | 199 | r#" |
200 | fn main() { | 200 | fn main() { |
201 | match 92 { | 201 | match 92 { |
202 | <|>x @ 4 | x @ 5 if x > 5 => true, | 202 | $0x @ 4 | x @ 5 if x > 5 => true, |
203 | _ => false | 203 | _ => false |
204 | } | 204 | } |
205 | } | 205 | } |
@@ -224,7 +224,7 @@ fn main() { | |||
224 | r#" | 224 | r#" |
225 | fn main() { | 225 | fn main() { |
226 | match 92 { | 226 | match 92 { |
227 | x => if x > 10 { <|>false }, | 227 | x => if x > 10 { $0false }, |
228 | _ => true | 228 | _ => true |
229 | } | 229 | } |
230 | } | 230 | } |
@@ -248,7 +248,7 @@ fn main() { | |||
248 | fn main() { | 248 | fn main() { |
249 | match 92 { | 249 | match 92 { |
250 | x => { | 250 | x => { |
251 | <|>if x > 10 { | 251 | $0if x > 10 { |
252 | false | 252 | false |
253 | } | 253 | } |
254 | }, | 254 | }, |
@@ -274,7 +274,7 @@ fn main() { | |||
274 | r#" | 274 | r#" |
275 | fn main() { | 275 | fn main() { |
276 | match 92 { | 276 | match 92 { |
277 | x => if let 62 = x { <|>false }, | 277 | x => if let 62 = x { $0false }, |
278 | _ => true | 278 | _ => true |
279 | } | 279 | } |
280 | } | 280 | } |
@@ -289,7 +289,7 @@ fn main() { | |||
289 | r#" | 289 | r#" |
290 | fn main() { | 290 | fn main() { |
291 | match 92 { | 291 | match 92 { |
292 | x => if x > 10 { <|> }, | 292 | x => if x > 10 { $0 }, |
293 | _ => true | 293 | _ => true |
294 | } | 294 | } |
295 | } | 295 | } |
@@ -313,7 +313,7 @@ fn main() { | |||
313 | fn main() { | 313 | fn main() { |
314 | match 92 { | 314 | match 92 { |
315 | x => if x > 10 { | 315 | x => if x > 10 { |
316 | 92;<|> | 316 | 92;$0 |
317 | false | 317 | false |
318 | }, | 318 | }, |
319 | _ => true | 319 | _ => true |
@@ -343,7 +343,7 @@ fn main() { | |||
343 | match 92 { | 343 | match 92 { |
344 | x => { | 344 | x => { |
345 | if x > 10 { | 345 | if x > 10 { |
346 | 92;<|> | 346 | 92;$0 |
347 | false | 347 | false |
348 | } | 348 | } |
349 | } | 349 | } |
diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/move_module_to_file.rs index 50bf67ef7..9d8579f47 100644 --- a/crates/assists/src/handlers/extract_module_to_file.rs +++ b/crates/assists/src/handlers/move_module_to_file.rs | |||
@@ -2,17 +2,18 @@ use ast::edit::IndentLevel; | |||
2 | use ide_db::base_db::AnchoredPathBuf; | 2 | use ide_db::base_db::AnchoredPathBuf; |
3 | use syntax::{ | 3 | use syntax::{ |
4 | ast::{self, edit::AstNodeEdit, NameOwner}, | 4 | ast::{self, edit::AstNodeEdit, NameOwner}, |
5 | AstNode, | 5 | AstNode, TextRange, |
6 | }; | 6 | }; |
7 | use test_utils::mark; | ||
7 | 8 | ||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 9 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
9 | 10 | ||
10 | // Assist: extract_module_to_file | 11 | // Assist: move_module_to_file |
11 | // | 12 | // |
12 | // This assist extract module to file. | 13 | // Moves inline module's contents to a separate file. |
13 | // | 14 | // |
14 | // ``` | 15 | // ``` |
15 | // mod foo {<|> | 16 | // mod $0foo { |
16 | // fn t() {} | 17 | // fn t() {} |
17 | // } | 18 | // } |
18 | // ``` | 19 | // ``` |
@@ -20,19 +21,24 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
20 | // ``` | 21 | // ``` |
21 | // mod foo; | 22 | // mod foo; |
22 | // ``` | 23 | // ``` |
23 | pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 24 | pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
24 | let module_ast = ctx.find_node_at_offset::<ast::Module>()?; | 25 | let module_ast = ctx.find_node_at_offset::<ast::Module>()?; |
26 | let module_items = module_ast.item_list()?; | ||
27 | |||
28 | let l_curly_offset = module_items.syntax().text_range().start(); | ||
29 | if l_curly_offset <= ctx.offset() { | ||
30 | mark::hit!(available_before_curly); | ||
31 | return None; | ||
32 | } | ||
33 | let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset); | ||
34 | |||
25 | let module_name = module_ast.name()?; | 35 | let module_name = module_ast.name()?; |
26 | 36 | ||
27 | let module_def = ctx.sema.to_def(&module_ast)?; | 37 | let module_def = ctx.sema.to_def(&module_ast)?; |
28 | let parent_module = module_def.parent(ctx.db())?; | 38 | let parent_module = module_def.parent(ctx.db())?; |
29 | 39 | ||
30 | let module_items = module_ast.item_list()?; | ||
31 | let target = module_ast.syntax().text_range(); | ||
32 | let anchor_file_id = ctx.frange.file_id; | ||
33 | |||
34 | acc.add( | 40 | acc.add( |
35 | AssistId("extract_module_to_file", AssistKind::RefactorExtract), | 41 | AssistId("move_module_to_file", AssistKind::RefactorExtract), |
36 | "Extract module to file", | 42 | "Extract module to file", |
37 | target, | 43 | target, |
38 | |builder| { | 44 | |builder| { |
@@ -53,9 +59,9 @@ pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> | |||
53 | items | 59 | items |
54 | }; | 60 | }; |
55 | 61 | ||
56 | builder.replace(target, format!("mod {};", module_name)); | 62 | builder.replace(module_ast.syntax().text_range(), format!("mod {};", module_name)); |
57 | 63 | ||
58 | let dst = AnchoredPathBuf { anchor: anchor_file_id, path }; | 64 | let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path }; |
59 | builder.create_file(dst, contents); | 65 | builder.create_file(dst, contents); |
60 | }, | 66 | }, |
61 | ) | 67 | ) |
@@ -63,16 +69,16 @@ pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> | |||
63 | 69 | ||
64 | #[cfg(test)] | 70 | #[cfg(test)] |
65 | mod tests { | 71 | mod tests { |
66 | use crate::tests::check_assist; | 72 | use crate::tests::{check_assist, check_assist_not_applicable}; |
67 | 73 | ||
68 | use super::*; | 74 | use super::*; |
69 | 75 | ||
70 | #[test] | 76 | #[test] |
71 | fn extract_from_root() { | 77 | fn extract_from_root() { |
72 | check_assist( | 78 | check_assist( |
73 | extract_module_to_file, | 79 | move_module_to_file, |
74 | r#" | 80 | r#" |
75 | mod tests {<|> | 81 | mod $0tests { |
76 | #[test] fn t() {} | 82 | #[test] fn t() {} |
77 | } | 83 | } |
78 | "#, | 84 | "#, |
@@ -88,12 +94,12 @@ mod tests; | |||
88 | #[test] | 94 | #[test] |
89 | fn extract_from_submodule() { | 95 | fn extract_from_submodule() { |
90 | check_assist( | 96 | check_assist( |
91 | extract_module_to_file, | 97 | move_module_to_file, |
92 | r#" | 98 | r#" |
93 | //- /main.rs | 99 | //- /main.rs |
94 | mod submod; | 100 | mod submod; |
95 | //- /submod.rs | 101 | //- /submod.rs |
96 | mod inner<|> { | 102 | $0mod inner { |
97 | fn f() {} | 103 | fn f() {} |
98 | } | 104 | } |
99 | fn g() {} | 105 | fn g() {} |
@@ -111,12 +117,12 @@ fn f() {} | |||
111 | #[test] | 117 | #[test] |
112 | fn extract_from_mod_rs() { | 118 | fn extract_from_mod_rs() { |
113 | check_assist( | 119 | check_assist( |
114 | extract_module_to_file, | 120 | move_module_to_file, |
115 | r#" | 121 | r#" |
116 | //- /main.rs | 122 | //- /main.rs |
117 | mod submodule; | 123 | mod submodule; |
118 | //- /submodule/mod.rs | 124 | //- /submodule/mod.rs |
119 | mod inner<|> { | 125 | mod inner$0 { |
120 | fn f() {} | 126 | fn f() {} |
121 | } | 127 | } |
122 | fn g() {} | 128 | fn g() {} |
@@ -130,4 +136,10 @@ fn f() {} | |||
130 | "#, | 136 | "#, |
131 | ); | 137 | ); |
132 | } | 138 | } |
139 | |||
140 | #[test] | ||
141 | fn available_before_curly() { | ||
142 | mark::check!(available_before_curly); | ||
143 | check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#); | ||
144 | } | ||
133 | } | 145 | } |
diff --git a/crates/assists/src/handlers/pull_assignment_up.rs b/crates/assists/src/handlers/pull_assignment_up.rs new file mode 100644 index 000000000..13e1cb754 --- /dev/null +++ b/crates/assists/src/handlers/pull_assignment_up.rs | |||
@@ -0,0 +1,400 @@ | |||
1 | use syntax::{ | ||
2 | ast::{self, edit::AstNodeEdit, make}, | ||
3 | AstNode, | ||
4 | }; | ||
5 | use test_utils::mark; | ||
6 | |||
7 | use crate::{ | ||
8 | assist_context::{AssistContext, Assists}, | ||
9 | AssistId, AssistKind, | ||
10 | }; | ||
11 | |||
12 | // Assist: pull_assignment_up | ||
13 | // | ||
14 | // Extracts variable assignment to outside an if or match statement. | ||
15 | // | ||
16 | // ``` | ||
17 | // fn main() { | ||
18 | // let mut foo = 6; | ||
19 | // | ||
20 | // if true { | ||
21 | // $0foo = 5; | ||
22 | // } else { | ||
23 | // foo = 4; | ||
24 | // } | ||
25 | // } | ||
26 | // ``` | ||
27 | // -> | ||
28 | // ``` | ||
29 | // fn main() { | ||
30 | // let mut foo = 6; | ||
31 | // | ||
32 | // foo = if true { | ||
33 | // 5 | ||
34 | // } else { | ||
35 | // 4 | ||
36 | // }; | ||
37 | // } | ||
38 | // ``` | ||
39 | pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
40 | let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; | ||
41 | let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { | ||
42 | assign_expr.lhs()? | ||
43 | } else { | ||
44 | return None; | ||
45 | }; | ||
46 | |||
47 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { | ||
48 | ( | ||
49 | ast::Expr::cast(if_expr.syntax().to_owned())?, | ||
50 | exprify_if(&if_expr, &ctx.sema, &name_expr)?.indent(if_expr.indent_level()), | ||
51 | ) | ||
52 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { | ||
53 | ( | ||
54 | ast::Expr::cast(match_expr.syntax().to_owned())?, | ||
55 | exprify_match(&match_expr, &ctx.sema, &name_expr)?, | ||
56 | ) | ||
57 | } else { | ||
58 | return None; | ||
59 | }; | ||
60 | |||
61 | let expr_stmt = make::expr_stmt(new_stmt); | ||
62 | |||
63 | acc.add( | ||
64 | AssistId("pull_assignment_up", AssistKind::RefactorExtract), | ||
65 | "Pull assignment up", | ||
66 | old_stmt.syntax().text_range(), | ||
67 | move |edit| { | ||
68 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); | ||
69 | }, | ||
70 | ) | ||
71 | } | ||
72 | |||
73 | fn exprify_match( | ||
74 | match_expr: &ast::MatchExpr, | ||
75 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
76 | name: &ast::Expr, | ||
77 | ) -> Option<ast::Expr> { | ||
78 | let new_arm_list = match_expr | ||
79 | .match_arm_list()? | ||
80 | .arms() | ||
81 | .map(|arm| { | ||
82 | if let ast::Expr::BlockExpr(block) = arm.expr()? { | ||
83 | let new_block = exprify_block(&block, sema, name)?.indent(block.indent_level()); | ||
84 | Some(arm.replace_descendant(block, new_block)) | ||
85 | } else { | ||
86 | None | ||
87 | } | ||
88 | }) | ||
89 | .collect::<Option<Vec<_>>>()?; | ||
90 | let new_arm_list = match_expr | ||
91 | .match_arm_list()? | ||
92 | .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list)); | ||
93 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) | ||
94 | } | ||
95 | |||
96 | fn exprify_if( | ||
97 | statement: &ast::IfExpr, | ||
98 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
99 | name: &ast::Expr, | ||
100 | ) -> Option<ast::Expr> { | ||
101 | let then_branch = exprify_block(&statement.then_branch()?, sema, name)?; | ||
102 | let else_branch = match statement.else_branch()? { | ||
103 | ast::ElseBranch::Block(ref block) => { | ||
104 | ast::ElseBranch::Block(exprify_block(block, sema, name)?) | ||
105 | } | ||
106 | ast::ElseBranch::IfExpr(expr) => { | ||
107 | mark::hit!(test_pull_assignment_up_chained_if); | ||
108 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( | ||
109 | exprify_if(&expr, sema, name)?.syntax().to_owned(), | ||
110 | )?) | ||
111 | } | ||
112 | }; | ||
113 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) | ||
114 | } | ||
115 | |||
116 | fn exprify_block( | ||
117 | block: &ast::BlockExpr, | ||
118 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
119 | name: &ast::Expr, | ||
120 | ) -> Option<ast::BlockExpr> { | ||
121 | if block.tail_expr().is_some() { | ||
122 | return None; | ||
123 | } | ||
124 | |||
125 | let mut stmts: Vec<_> = block.statements().collect(); | ||
126 | let stmt = stmts.pop()?; | ||
127 | |||
128 | if let ast::Stmt::ExprStmt(stmt) = stmt { | ||
129 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { | ||
130 | if expr.op_kind()? == ast::BinOp::Assignment && is_equivalent(sema, &expr.lhs()?, name) | ||
131 | { | ||
132 | // The last statement in the block is an assignment to the name we want | ||
133 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | None | ||
138 | } | ||
139 | |||
140 | fn is_equivalent( | ||
141 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
142 | expr0: &ast::Expr, | ||
143 | expr1: &ast::Expr, | ||
144 | ) -> bool { | ||
145 | match (expr0, expr1) { | ||
146 | (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { | ||
147 | mark::hit!(test_pull_assignment_up_field_assignment); | ||
148 | sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) | ||
149 | } | ||
150 | (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { | ||
151 | let path0 = path0.path(); | ||
152 | let path1 = path1.path(); | ||
153 | if let (Some(path0), Some(path1)) = (path0, path1) { | ||
154 | sema.resolve_path(&path0) == sema.resolve_path(&path1) | ||
155 | } else { | ||
156 | false | ||
157 | } | ||
158 | } | ||
159 | _ => false, | ||
160 | } | ||
161 | } | ||
162 | |||
163 | #[cfg(test)] | ||
164 | mod tests { | ||
165 | use super::*; | ||
166 | |||
167 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
168 | |||
169 | #[test] | ||
170 | fn test_pull_assignment_up_if() { | ||
171 | check_assist( | ||
172 | pull_assignment_up, | ||
173 | r#" | ||
174 | fn foo() { | ||
175 | let mut a = 1; | ||
176 | |||
177 | if true { | ||
178 | $0a = 2; | ||
179 | } else { | ||
180 | a = 3; | ||
181 | } | ||
182 | }"#, | ||
183 | r#" | ||
184 | fn foo() { | ||
185 | let mut a = 1; | ||
186 | |||
187 | a = if true { | ||
188 | 2 | ||
189 | } else { | ||
190 | 3 | ||
191 | }; | ||
192 | }"#, | ||
193 | ); | ||
194 | } | ||
195 | |||
196 | #[test] | ||
197 | fn test_pull_assignment_up_match() { | ||
198 | check_assist( | ||
199 | pull_assignment_up, | ||
200 | r#" | ||
201 | fn foo() { | ||
202 | let mut a = 1; | ||
203 | |||
204 | match 1 { | ||
205 | 1 => { | ||
206 | $0a = 2; | ||
207 | }, | ||
208 | 2 => { | ||
209 | a = 3; | ||
210 | }, | ||
211 | 3 => { | ||
212 | a = 4; | ||
213 | } | ||
214 | } | ||
215 | }"#, | ||
216 | r#" | ||
217 | fn foo() { | ||
218 | let mut a = 1; | ||
219 | |||
220 | a = match 1 { | ||
221 | 1 => { | ||
222 | 2 | ||
223 | }, | ||
224 | 2 => { | ||
225 | 3 | ||
226 | }, | ||
227 | 3 => { | ||
228 | 4 | ||
229 | } | ||
230 | }; | ||
231 | }"#, | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn test_pull_assignment_up_not_last_not_applicable() { | ||
237 | check_assist_not_applicable( | ||
238 | pull_assignment_up, | ||
239 | r#" | ||
240 | fn foo() { | ||
241 | let mut a = 1; | ||
242 | |||
243 | if true { | ||
244 | $0a = 2; | ||
245 | b = a; | ||
246 | } else { | ||
247 | a = 3; | ||
248 | } | ||
249 | }"#, | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | #[test] | ||
254 | fn test_pull_assignment_up_chained_if() { | ||
255 | mark::check!(test_pull_assignment_up_chained_if); | ||
256 | check_assist( | ||
257 | pull_assignment_up, | ||
258 | r#" | ||
259 | fn foo() { | ||
260 | let mut a = 1; | ||
261 | |||
262 | if true { | ||
263 | $0a = 2; | ||
264 | } else if false { | ||
265 | a = 3; | ||
266 | } else { | ||
267 | a = 4; | ||
268 | } | ||
269 | }"#, | ||
270 | r#" | ||
271 | fn foo() { | ||
272 | let mut a = 1; | ||
273 | |||
274 | a = if true { | ||
275 | 2 | ||
276 | } else if false { | ||
277 | 3 | ||
278 | } else { | ||
279 | 4 | ||
280 | }; | ||
281 | }"#, | ||
282 | ); | ||
283 | } | ||
284 | |||
285 | #[test] | ||
286 | fn test_pull_assignment_up_retains_stmts() { | ||
287 | check_assist( | ||
288 | pull_assignment_up, | ||
289 | r#" | ||
290 | fn foo() { | ||
291 | let mut a = 1; | ||
292 | |||
293 | if true { | ||
294 | let b = 2; | ||
295 | $0a = 2; | ||
296 | } else { | ||
297 | let b = 3; | ||
298 | a = 3; | ||
299 | } | ||
300 | }"#, | ||
301 | r#" | ||
302 | fn foo() { | ||
303 | let mut a = 1; | ||
304 | |||
305 | a = if true { | ||
306 | let b = 2; | ||
307 | 2 | ||
308 | } else { | ||
309 | let b = 3; | ||
310 | 3 | ||
311 | }; | ||
312 | }"#, | ||
313 | ) | ||
314 | } | ||
315 | |||
316 | #[test] | ||
317 | fn pull_assignment_up_let_stmt_not_applicable() { | ||
318 | check_assist_not_applicable( | ||
319 | pull_assignment_up, | ||
320 | r#" | ||
321 | fn foo() { | ||
322 | let mut a = 1; | ||
323 | |||
324 | let b = if true { | ||
325 | $0a = 2 | ||
326 | } else { | ||
327 | a = 3 | ||
328 | }; | ||
329 | }"#, | ||
330 | ) | ||
331 | } | ||
332 | |||
333 | #[test] | ||
334 | fn pull_assignment_up_if_missing_assigment_not_applicable() { | ||
335 | check_assist_not_applicable( | ||
336 | pull_assignment_up, | ||
337 | r#" | ||
338 | fn foo() { | ||
339 | let mut a = 1; | ||
340 | |||
341 | if true { | ||
342 | $0a = 2; | ||
343 | } else {} | ||
344 | }"#, | ||
345 | ) | ||
346 | } | ||
347 | |||
348 | #[test] | ||
349 | fn pull_assignment_up_match_missing_assigment_not_applicable() { | ||
350 | check_assist_not_applicable( | ||
351 | pull_assignment_up, | ||
352 | r#" | ||
353 | fn foo() { | ||
354 | let mut a = 1; | ||
355 | |||
356 | match 1 { | ||
357 | 1 => { | ||
358 | $0a = 2; | ||
359 | }, | ||
360 | 2 => { | ||
361 | a = 3; | ||
362 | }, | ||
363 | 3 => {}, | ||
364 | } | ||
365 | }"#, | ||
366 | ) | ||
367 | } | ||
368 | |||
369 | #[test] | ||
370 | fn test_pull_assignment_up_field_assignment() { | ||
371 | mark::check!(test_pull_assignment_up_field_assignment); | ||
372 | check_assist( | ||
373 | pull_assignment_up, | ||
374 | r#" | ||
375 | struct A(usize); | ||
376 | |||
377 | fn foo() { | ||
378 | let mut a = A(1); | ||
379 | |||
380 | if true { | ||
381 | $0a.0 = 2; | ||
382 | } else { | ||
383 | a.0 = 3; | ||
384 | } | ||
385 | }"#, | ||
386 | r#" | ||
387 | struct A(usize); | ||
388 | |||
389 | fn foo() { | ||
390 | let mut a = A(1); | ||
391 | |||
392 | a.0 = if true { | ||
393 | 2 | ||
394 | } else { | ||
395 | 3 | ||
396 | }; | ||
397 | }"#, | ||
398 | ) | ||
399 | } | ||
400 | } | ||
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs index 98cb09214..f7fbf37f4 100644 --- a/crates/assists/src/handlers/qualify_path.rs +++ b/crates/assists/src/handlers/qualify_path.rs | |||
@@ -22,7 +22,7 @@ use crate::{ | |||
22 | // | 22 | // |
23 | // ``` | 23 | // ``` |
24 | // fn main() { | 24 | // fn main() { |
25 | // let map = HashMap<|>::new(); | 25 | // let map = HashMap$0::new(); |
26 | // } | 26 | // } |
27 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | 27 | // # pub mod std { pub mod collections { pub struct HashMap { } } } |
28 | // ``` | 28 | // ``` |
@@ -221,7 +221,7 @@ mod tests { | |||
221 | 221 | ||
222 | use std::fmt; | 222 | use std::fmt; |
223 | 223 | ||
224 | <|>Formatter | 224 | $0Formatter |
225 | ", | 225 | ", |
226 | r" | 226 | r" |
227 | mod std { | 227 | mod std { |
@@ -242,7 +242,7 @@ mod tests { | |||
242 | check_assist( | 242 | check_assist( |
243 | qualify_path, | 243 | qualify_path, |
244 | r" | 244 | r" |
245 | <|>PubStruct | 245 | $0PubStruct |
246 | 246 | ||
247 | pub mod PubMod { | 247 | pub mod PubMod { |
248 | pub struct PubStruct; | 248 | pub struct PubStruct; |
@@ -266,7 +266,7 @@ mod tests { | |||
266 | macro_rules! foo { | 266 | macro_rules! foo { |
267 | ($i:ident) => { fn foo(a: $i) {} } | 267 | ($i:ident) => { fn foo(a: $i) {} } |
268 | } | 268 | } |
269 | foo!(Pub<|>Struct); | 269 | foo!(Pub$0Struct); |
270 | 270 | ||
271 | pub mod PubMod { | 271 | pub mod PubMod { |
272 | pub struct PubStruct; | 272 | pub struct PubStruct; |
@@ -290,7 +290,7 @@ mod tests { | |||
290 | check_assist( | 290 | check_assist( |
291 | qualify_path, | 291 | qualify_path, |
292 | r" | 292 | r" |
293 | PubSt<|>ruct | 293 | PubSt$0ruct |
294 | 294 | ||
295 | pub mod PubMod1 { | 295 | pub mod PubMod1 { |
296 | pub struct PubStruct; | 296 | pub struct PubStruct; |
@@ -325,7 +325,7 @@ mod tests { | |||
325 | r" | 325 | r" |
326 | use PubMod::PubStruct; | 326 | use PubMod::PubStruct; |
327 | 327 | ||
328 | PubStruct<|> | 328 | PubStruct$0 |
329 | 329 | ||
330 | pub mod PubMod { | 330 | pub mod PubMod { |
331 | pub struct PubStruct; | 331 | pub struct PubStruct; |
@@ -339,7 +339,7 @@ mod tests { | |||
339 | check_assist_not_applicable( | 339 | check_assist_not_applicable( |
340 | qualify_path, | 340 | qualify_path, |
341 | r" | 341 | r" |
342 | PrivateStruct<|> | 342 | PrivateStruct$0 |
343 | 343 | ||
344 | pub mod PubMod { | 344 | pub mod PubMod { |
345 | struct PrivateStruct; | 345 | struct PrivateStruct; |
@@ -353,7 +353,7 @@ mod tests { | |||
353 | check_assist_not_applicable( | 353 | check_assist_not_applicable( |
354 | qualify_path, | 354 | qualify_path, |
355 | " | 355 | " |
356 | PubStruct<|>", | 356 | PubStruct$0", |
357 | ); | 357 | ); |
358 | } | 358 | } |
359 | 359 | ||
@@ -362,7 +362,7 @@ mod tests { | |||
362 | check_assist_not_applicable( | 362 | check_assist_not_applicable( |
363 | qualify_path, | 363 | qualify_path, |
364 | r" | 364 | r" |
365 | use PubStruct<|>; | 365 | use PubStruct$0; |
366 | 366 | ||
367 | pub mod PubMod { | 367 | pub mod PubMod { |
368 | pub struct PubStruct; | 368 | pub struct PubStruct; |
@@ -375,7 +375,7 @@ mod tests { | |||
375 | check_assist( | 375 | check_assist( |
376 | qualify_path, | 376 | qualify_path, |
377 | r" | 377 | r" |
378 | test_function<|> | 378 | test_function$0 |
379 | 379 | ||
380 | pub mod PubMod { | 380 | pub mod PubMod { |
381 | pub fn test_function() {}; | 381 | pub fn test_function() {}; |
@@ -404,7 +404,7 @@ macro_rules! foo { | |||
404 | 404 | ||
405 | //- /main.rs crate:main deps:crate_with_macro | 405 | //- /main.rs crate:main deps:crate_with_macro |
406 | fn main() { | 406 | fn main() { |
407 | foo<|> | 407 | foo$0 |
408 | } | 408 | } |
409 | ", | 409 | ", |
410 | r" | 410 | r" |
@@ -421,7 +421,7 @@ fn main() { | |||
421 | qualify_path, | 421 | qualify_path, |
422 | r" | 422 | r" |
423 | struct AssistInfo { | 423 | struct AssistInfo { |
424 | group_label: Option<<|>GroupLabel>, | 424 | group_label: Option<$0GroupLabel>, |
425 | } | 425 | } |
426 | 426 | ||
427 | mod m { pub struct GroupLabel; } | 427 | mod m { pub struct GroupLabel; } |
@@ -445,7 +445,7 @@ fn main() { | |||
445 | 445 | ||
446 | use mod1::mod2; | 446 | use mod1::mod2; |
447 | fn main() { | 447 | fn main() { |
448 | mod2::mod3::TestStruct<|> | 448 | mod2::mod3::TestStruct$0 |
449 | } | 449 | } |
450 | ", | 450 | ", |
451 | ); | 451 | ); |
@@ -462,7 +462,7 @@ fn main() { | |||
462 | 462 | ||
463 | use test_mod::test_function; | 463 | use test_mod::test_function; |
464 | fn main() { | 464 | fn main() { |
465 | test_function<|> | 465 | test_function$0 |
466 | } | 466 | } |
467 | ", | 467 | ", |
468 | ); | 468 | ); |
@@ -481,7 +481,7 @@ fn main() { | |||
481 | } | 481 | } |
482 | 482 | ||
483 | fn main() { | 483 | fn main() { |
484 | TestStruct::test_function<|> | 484 | TestStruct::test_function$0 |
485 | } | 485 | } |
486 | ", | 486 | ", |
487 | r" | 487 | r" |
@@ -513,7 +513,7 @@ fn main() { | |||
513 | } | 513 | } |
514 | 514 | ||
515 | fn main() { | 515 | fn main() { |
516 | TestStruct::TEST_CONST<|> | 516 | TestStruct::TEST_CONST$0 |
517 | } | 517 | } |
518 | ", | 518 | ", |
519 | r" | 519 | r" |
@@ -547,7 +547,7 @@ fn main() { | |||
547 | } | 547 | } |
548 | 548 | ||
549 | fn main() { | 549 | fn main() { |
550 | test_mod::TestStruct::test_function<|> | 550 | test_mod::TestStruct::test_function$0 |
551 | } | 551 | } |
552 | ", | 552 | ", |
553 | r" | 553 | r" |
@@ -594,7 +594,7 @@ fn main() { | |||
594 | 594 | ||
595 | use test_mod::TestTrait2; | 595 | use test_mod::TestTrait2; |
596 | fn main() { | 596 | fn main() { |
597 | test_mod::TestEnum::test_function<|>; | 597 | test_mod::TestEnum::test_function$0; |
598 | } | 598 | } |
599 | ", | 599 | ", |
600 | ) | 600 | ) |
@@ -617,7 +617,7 @@ fn main() { | |||
617 | } | 617 | } |
618 | 618 | ||
619 | fn main() { | 619 | fn main() { |
620 | test_mod::TestStruct::TEST_CONST<|> | 620 | test_mod::TestStruct::TEST_CONST$0 |
621 | } | 621 | } |
622 | ", | 622 | ", |
623 | r" | 623 | r" |
@@ -664,7 +664,7 @@ fn main() { | |||
664 | 664 | ||
665 | use test_mod::TestTrait2; | 665 | use test_mod::TestTrait2; |
666 | fn main() { | 666 | fn main() { |
667 | test_mod::TestEnum::TEST_CONST<|>; | 667 | test_mod::TestEnum::TEST_CONST$0; |
668 | } | 668 | } |
669 | ", | 669 | ", |
670 | ) | 670 | ) |
@@ -688,7 +688,7 @@ fn main() { | |||
688 | 688 | ||
689 | fn main() { | 689 | fn main() { |
690 | let test_struct = test_mod::TestStruct {}; | 690 | let test_struct = test_mod::TestStruct {}; |
691 | test_struct.test_meth<|>od() | 691 | test_struct.test_meth$0od() |
692 | } | 692 | } |
693 | ", | 693 | ", |
694 | r" | 694 | r" |
@@ -727,7 +727,7 @@ fn main() { | |||
727 | 727 | ||
728 | fn main() { | 728 | fn main() { |
729 | let test_struct = test_mod::TestStruct {}; | 729 | let test_struct = test_mod::TestStruct {}; |
730 | test_struct.test_meth<|>od(42) | 730 | test_struct.test_meth$0od(42) |
731 | } | 731 | } |
732 | ", | 732 | ", |
733 | r" | 733 | r" |
@@ -766,7 +766,7 @@ fn main() { | |||
766 | 766 | ||
767 | fn main() { | 767 | fn main() { |
768 | let test_struct = test_mod::TestStruct {}; | 768 | let test_struct = test_mod::TestStruct {}; |
769 | test_struct.test_meth<|>od() | 769 | test_struct.test_meth$0od() |
770 | } | 770 | } |
771 | ", | 771 | ", |
772 | r" | 772 | r" |
@@ -796,7 +796,7 @@ fn main() { | |||
796 | //- /main.rs crate:main deps:dep | 796 | //- /main.rs crate:main deps:dep |
797 | fn main() { | 797 | fn main() { |
798 | let test_struct = dep::test_mod::TestStruct {}; | 798 | let test_struct = dep::test_mod::TestStruct {}; |
799 | test_struct.test_meth<|>od() | 799 | test_struct.test_meth$0od() |
800 | } | 800 | } |
801 | //- /dep.rs crate:dep | 801 | //- /dep.rs crate:dep |
802 | pub mod test_mod { | 802 | pub mod test_mod { |
@@ -825,7 +825,7 @@ fn main() { | |||
825 | r" | 825 | r" |
826 | //- /main.rs crate:main deps:dep | 826 | //- /main.rs crate:main deps:dep |
827 | fn main() { | 827 | fn main() { |
828 | dep::test_mod::TestStruct::test_func<|>tion | 828 | dep::test_mod::TestStruct::test_func$0tion |
829 | } | 829 | } |
830 | //- /dep.rs crate:dep | 830 | //- /dep.rs crate:dep |
831 | pub mod test_mod { | 831 | pub mod test_mod { |
@@ -853,7 +853,7 @@ fn main() { | |||
853 | r" | 853 | r" |
854 | //- /main.rs crate:main deps:dep | 854 | //- /main.rs crate:main deps:dep |
855 | fn main() { | 855 | fn main() { |
856 | dep::test_mod::TestStruct::CONST<|> | 856 | dep::test_mod::TestStruct::CONST$0 |
857 | } | 857 | } |
858 | //- /dep.rs crate:dep | 858 | //- /dep.rs crate:dep |
859 | pub mod test_mod { | 859 | pub mod test_mod { |
@@ -882,7 +882,7 @@ fn main() { | |||
882 | //- /main.rs crate:main deps:dep | 882 | //- /main.rs crate:main deps:dep |
883 | fn main() { | 883 | fn main() { |
884 | let test_struct = dep::test_mod::TestStruct {}; | 884 | let test_struct = dep::test_mod::TestStruct {}; |
885 | test_struct.test_func<|>tion() | 885 | test_struct.test_func$0tion() |
886 | } | 886 | } |
887 | //- /dep.rs crate:dep | 887 | //- /dep.rs crate:dep |
888 | pub mod test_mod { | 888 | pub mod test_mod { |
@@ -906,7 +906,7 @@ fn main() { | |||
906 | //- /main.rs crate:main deps:dep | 906 | //- /main.rs crate:main deps:dep |
907 | fn main() { | 907 | fn main() { |
908 | let test_struct = dep::test_mod::TestStruct {}; | 908 | let test_struct = dep::test_mod::TestStruct {}; |
909 | test_struct.test_meth<|>od() | 909 | test_struct.test_meth$0od() |
910 | } | 910 | } |
911 | //- /dep.rs crate:dep | 911 | //- /dep.rs crate:dep |
912 | pub mod test_mod { | 912 | pub mod test_mod { |
@@ -949,7 +949,7 @@ fn main() { | |||
949 | use test_mod::TestTrait2; | 949 | use test_mod::TestTrait2; |
950 | fn main() { | 950 | fn main() { |
951 | let one = test_mod::TestEnum::One; | 951 | let one = test_mod::TestEnum::One; |
952 | one.test<|>_method(); | 952 | one.test$0_method(); |
953 | } | 953 | } |
954 | ", | 954 | ", |
955 | ) | 955 | ) |
@@ -965,7 +965,7 @@ pub struct Struct; | |||
965 | 965 | ||
966 | //- /main.rs crate:main deps:dep | 966 | //- /main.rs crate:main deps:dep |
967 | fn main() { | 967 | fn main() { |
968 | Struct<|> | 968 | Struct$0 |
969 | } | 969 | } |
970 | ", | 970 | ", |
971 | r" | 971 | r" |
@@ -992,7 +992,7 @@ pub fn panic_fmt() {} | |||
992 | //- /main.rs crate:main deps:dep | 992 | //- /main.rs crate:main deps:dep |
993 | struct S; | 993 | struct S; |
994 | 994 | ||
995 | impl f<|>mt::Display for S {} | 995 | impl f$0mt::Display for S {} |
996 | ", | 996 | ", |
997 | r" | 997 | r" |
998 | struct S; | 998 | struct S; |
@@ -1019,7 +1019,7 @@ mac!(); | |||
1019 | 1019 | ||
1020 | //- /main.rs crate:main deps:dep | 1020 | //- /main.rs crate:main deps:dep |
1021 | fn main() { | 1021 | fn main() { |
1022 | Cheese<|>; | 1022 | Cheese$0; |
1023 | } | 1023 | } |
1024 | ", | 1024 | ", |
1025 | r" | 1025 | r" |
@@ -1042,7 +1042,7 @@ pub struct fmt; | |||
1042 | 1042 | ||
1043 | //- /main.rs crate:main deps:dep | 1043 | //- /main.rs crate:main deps:dep |
1044 | fn main() { | 1044 | fn main() { |
1045 | FMT<|>; | 1045 | FMT$0; |
1046 | } | 1046 | } |
1047 | ", | 1047 | ", |
1048 | r" | 1048 | r" |
@@ -1062,7 +1062,7 @@ fn main() { | |||
1062 | pub mod generic { pub struct Thing<'a, T>(&'a T); } | 1062 | pub mod generic { pub struct Thing<'a, T>(&'a T); } |
1063 | 1063 | ||
1064 | //- /main.rs crate:main deps:dep | 1064 | //- /main.rs crate:main deps:dep |
1065 | fn foo() -> Thin<|>g<'static, ()> {} | 1065 | fn foo() -> Thin$0g<'static, ()> {} |
1066 | 1066 | ||
1067 | fn main() {} | 1067 | fn main() {} |
1068 | ", | 1068 | ", |
@@ -1083,7 +1083,7 @@ fn main() {} | |||
1083 | pub mod generic { pub struct Thing<'a, T>(&'a T); } | 1083 | pub mod generic { pub struct Thing<'a, T>(&'a T); } |
1084 | 1084 | ||
1085 | //- /main.rs crate:main deps:dep | 1085 | //- /main.rs crate:main deps:dep |
1086 | fn foo() -> Thin<|>g::<'static, ()> {} | 1086 | fn foo() -> Thin$0g::<'static, ()> {} |
1087 | 1087 | ||
1088 | fn main() {} | 1088 | fn main() {} |
1089 | ", | 1089 | ", |
@@ -1108,7 +1108,7 @@ fn main() {} | |||
1108 | } | 1108 | } |
1109 | 1109 | ||
1110 | fn main() { | 1110 | fn main() { |
1111 | TestStruct::<()>::TEST_CONST<|> | 1111 | TestStruct::<()>::TEST_CONST$0 |
1112 | } | 1112 | } |
1113 | ", | 1113 | ", |
1114 | r" | 1114 | r" |
@@ -1142,7 +1142,7 @@ fn main() {} | |||
1142 | } | 1142 | } |
1143 | 1143 | ||
1144 | fn main() { | 1144 | fn main() { |
1145 | test_mod::TestStruct::<()>::TEST_CONST<|> | 1145 | test_mod::TestStruct::<()>::TEST_CONST$0 |
1146 | } | 1146 | } |
1147 | ", | 1147 | ", |
1148 | r" | 1148 | r" |
@@ -1180,7 +1180,7 @@ fn main() {} | |||
1180 | 1180 | ||
1181 | fn main() { | 1181 | fn main() { |
1182 | let test_struct = test_mod::TestStruct {}; | 1182 | let test_struct = test_mod::TestStruct {}; |
1183 | test_struct.test_meth<|>od::<()>() | 1183 | test_struct.test_meth$0od::<()>() |
1184 | } | 1184 | } |
1185 | ", | 1185 | ", |
1186 | r" | 1186 | r" |
diff --git a/crates/assists/src/handlers/raw_string.rs b/crates/assists/src/handlers/raw_string.rs index 4c759cc25..be963f162 100644 --- a/crates/assists/src/handlers/raw_string.rs +++ b/crates/assists/src/handlers/raw_string.rs | |||
@@ -11,7 +11,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
11 | // | 11 | // |
12 | // ``` | 12 | // ``` |
13 | // fn main() { | 13 | // fn main() { |
14 | // "Hello,<|> World!"; | 14 | // "Hello,$0 World!"; |
15 | // } | 15 | // } |
16 | // ``` | 16 | // ``` |
17 | // -> | 17 | // -> |
@@ -53,7 +53,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
53 | // | 53 | // |
54 | // ``` | 54 | // ``` |
55 | // fn main() { | 55 | // fn main() { |
56 | // r#"Hello,<|> "World!""#; | 56 | // r#"Hello,$0 "World!""#; |
57 | // } | 57 | // } |
58 | // ``` | 58 | // ``` |
59 | // -> | 59 | // -> |
@@ -95,7 +95,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
95 | // | 95 | // |
96 | // ``` | 96 | // ``` |
97 | // fn main() { | 97 | // fn main() { |
98 | // r#"Hello,<|> World!"#; | 98 | // r#"Hello,$0 World!"#; |
99 | // } | 99 | // } |
100 | // ``` | 100 | // ``` |
101 | // -> | 101 | // -> |
@@ -123,7 +123,7 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
123 | // | 123 | // |
124 | // ``` | 124 | // ``` |
125 | // fn main() { | 125 | // fn main() { |
126 | // r#"Hello,<|> World!"#; | 126 | // r#"Hello,$0 World!"#; |
127 | // } | 127 | // } |
128 | // ``` | 128 | // ``` |
129 | // -> | 129 | // -> |
@@ -194,7 +194,7 @@ mod tests { | |||
194 | make_raw_string, | 194 | make_raw_string, |
195 | r#" | 195 | r#" |
196 | fn f() { | 196 | fn f() { |
197 | let s = <|>"random\nstring"; | 197 | let s = $0"random\nstring"; |
198 | } | 198 | } |
199 | "#, | 199 | "#, |
200 | r#""random\nstring""#, | 200 | r#""random\nstring""#, |
@@ -207,7 +207,7 @@ mod tests { | |||
207 | make_raw_string, | 207 | make_raw_string, |
208 | r#" | 208 | r#" |
209 | fn f() { | 209 | fn f() { |
210 | let s = <|>"random\nstring"; | 210 | let s = $0"random\nstring"; |
211 | } | 211 | } |
212 | "#, | 212 | "#, |
213 | r##" | 213 | r##" |
@@ -225,7 +225,7 @@ string"#; | |||
225 | make_raw_string, | 225 | make_raw_string, |
226 | r#" | 226 | r#" |
227 | fn f() { | 227 | fn f() { |
228 | format!(<|>"x = {}", 92) | 228 | format!($0"x = {}", 92) |
229 | } | 229 | } |
230 | "#, | 230 | "#, |
231 | r##" | 231 | r##" |
@@ -242,7 +242,7 @@ string"#; | |||
242 | make_raw_string, | 242 | make_raw_string, |
243 | r###" | 243 | r###" |
244 | fn f() { | 244 | fn f() { |
245 | let s = <|>"#random##\nstring"; | 245 | let s = $0"#random##\nstring"; |
246 | } | 246 | } |
247 | "###, | 247 | "###, |
248 | r####" | 248 | r####" |
@@ -260,7 +260,7 @@ string"#; | |||
260 | make_raw_string, | 260 | make_raw_string, |
261 | r###" | 261 | r###" |
262 | fn f() { | 262 | fn f() { |
263 | let s = <|>"#random\"##\nstring"; | 263 | let s = $0"#random\"##\nstring"; |
264 | } | 264 | } |
265 | "###, | 265 | "###, |
266 | r####" | 266 | r####" |
@@ -278,7 +278,7 @@ string"###; | |||
278 | make_raw_string, | 278 | make_raw_string, |
279 | r#" | 279 | r#" |
280 | fn f() { | 280 | fn f() { |
281 | let s = <|>"random string"; | 281 | let s = $0"random string"; |
282 | } | 282 | } |
283 | "#, | 283 | "#, |
284 | r##" | 284 | r##" |
@@ -295,7 +295,7 @@ string"###; | |||
295 | make_raw_string, | 295 | make_raw_string, |
296 | r#" | 296 | r#" |
297 | fn f() { | 297 | fn f() { |
298 | let s = "foo<|> | 298 | let s = "foo$0 |
299 | } | 299 | } |
300 | "#, | 300 | "#, |
301 | ) | 301 | ) |
@@ -307,7 +307,7 @@ string"###; | |||
307 | make_usual_string, | 307 | make_usual_string, |
308 | r#" | 308 | r#" |
309 | fn main() { | 309 | fn main() { |
310 | let s = r#"bar<|> | 310 | let s = r#"bar$0 |
311 | } | 311 | } |
312 | "#, | 312 | "#, |
313 | ) | 313 | ) |
@@ -319,7 +319,7 @@ string"###; | |||
319 | add_hash, | 319 | add_hash, |
320 | r#" | 320 | r#" |
321 | fn f() { | 321 | fn f() { |
322 | let s = <|>r"random string"; | 322 | let s = $0r"random string"; |
323 | } | 323 | } |
324 | "#, | 324 | "#, |
325 | r#"r"random string""#, | 325 | r#"r"random string""#, |
@@ -332,7 +332,7 @@ string"###; | |||
332 | add_hash, | 332 | add_hash, |
333 | r#" | 333 | r#" |
334 | fn f() { | 334 | fn f() { |
335 | let s = <|>r"random string"; | 335 | let s = $0r"random string"; |
336 | } | 336 | } |
337 | "#, | 337 | "#, |
338 | r##" | 338 | r##" |
@@ -349,7 +349,7 @@ string"###; | |||
349 | add_hash, | 349 | add_hash, |
350 | r##" | 350 | r##" |
351 | fn f() { | 351 | fn f() { |
352 | let s = <|>r#"random"string"#; | 352 | let s = $0r#"random"string"#; |
353 | } | 353 | } |
354 | "##, | 354 | "##, |
355 | r###" | 355 | r###" |
@@ -366,7 +366,7 @@ string"###; | |||
366 | add_hash, | 366 | add_hash, |
367 | r#" | 367 | r#" |
368 | fn f() { | 368 | fn f() { |
369 | let s = <|>"random string"; | 369 | let s = $0"random string"; |
370 | } | 370 | } |
371 | "#, | 371 | "#, |
372 | ); | 372 | ); |
@@ -378,7 +378,7 @@ string"###; | |||
378 | remove_hash, | 378 | remove_hash, |
379 | r##" | 379 | r##" |
380 | fn f() { | 380 | fn f() { |
381 | let s = <|>r#"random string"#; | 381 | let s = $0r#"random string"#; |
382 | } | 382 | } |
383 | "##, | 383 | "##, |
384 | r##"r#"random string"#"##, | 384 | r##"r#"random string"#"##, |
@@ -389,7 +389,7 @@ string"###; | |||
389 | fn remove_hash_works() { | 389 | fn remove_hash_works() { |
390 | check_assist( | 390 | check_assist( |
391 | remove_hash, | 391 | remove_hash, |
392 | r##"fn f() { let s = <|>r#"random string"#; }"##, | 392 | r##"fn f() { let s = $0r#"random string"#; }"##, |
393 | r#"fn f() { let s = r"random string"; }"#, | 393 | r#"fn f() { let s = r"random string"; }"#, |
394 | ) | 394 | ) |
395 | } | 395 | } |
@@ -401,7 +401,7 @@ string"###; | |||
401 | remove_hash, | 401 | remove_hash, |
402 | r##" | 402 | r##" |
403 | fn f() { | 403 | fn f() { |
404 | let s = <|>r#"random"str"ing"#; | 404 | let s = $0r#"random"str"ing"#; |
405 | } | 405 | } |
406 | "##, | 406 | "##, |
407 | ) | 407 | ) |
@@ -413,7 +413,7 @@ string"###; | |||
413 | remove_hash, | 413 | remove_hash, |
414 | r###" | 414 | r###" |
415 | fn f() { | 415 | fn f() { |
416 | let s = <|>r##"random string"##; | 416 | let s = $0r##"random string"##; |
417 | } | 417 | } |
418 | "###, | 418 | "###, |
419 | r##" | 419 | r##" |
@@ -426,12 +426,12 @@ string"###; | |||
426 | 426 | ||
427 | #[test] | 427 | #[test] |
428 | fn remove_hash_doesnt_work() { | 428 | fn remove_hash_doesnt_work() { |
429 | check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>"random string"; }"#); | 429 | check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0"random string"; }"#); |
430 | } | 430 | } |
431 | 431 | ||
432 | #[test] | 432 | #[test] |
433 | fn remove_hash_no_hash_doesnt_work() { | 433 | fn remove_hash_no_hash_doesnt_work() { |
434 | check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>r"random string"; }"#); | 434 | check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0r"random string"; }"#); |
435 | } | 435 | } |
436 | 436 | ||
437 | #[test] | 437 | #[test] |
@@ -440,7 +440,7 @@ string"###; | |||
440 | make_usual_string, | 440 | make_usual_string, |
441 | r##" | 441 | r##" |
442 | fn f() { | 442 | fn f() { |
443 | let s = <|>r#"random string"#; | 443 | let s = $0r#"random string"#; |
444 | } | 444 | } |
445 | "##, | 445 | "##, |
446 | r##"r#"random string"#"##, | 446 | r##"r#"random string"#"##, |
@@ -453,7 +453,7 @@ string"###; | |||
453 | make_usual_string, | 453 | make_usual_string, |
454 | r##" | 454 | r##" |
455 | fn f() { | 455 | fn f() { |
456 | let s = <|>r#"random string"#; | 456 | let s = $0r#"random string"#; |
457 | } | 457 | } |
458 | "##, | 458 | "##, |
459 | r#" | 459 | r#" |
@@ -470,7 +470,7 @@ string"###; | |||
470 | make_usual_string, | 470 | make_usual_string, |
471 | r##" | 471 | r##" |
472 | fn f() { | 472 | fn f() { |
473 | let s = <|>r#"random"str"ing"#; | 473 | let s = $0r#"random"str"ing"#; |
474 | } | 474 | } |
475 | "##, | 475 | "##, |
476 | r#" | 476 | r#" |
@@ -487,7 +487,7 @@ string"###; | |||
487 | make_usual_string, | 487 | make_usual_string, |
488 | r###" | 488 | r###" |
489 | fn f() { | 489 | fn f() { |
490 | let s = <|>r##"random string"##; | 490 | let s = $0r##"random string"##; |
491 | } | 491 | } |
492 | "###, | 492 | "###, |
493 | r##" | 493 | r##" |
@@ -504,7 +504,7 @@ string"###; | |||
504 | make_usual_string, | 504 | make_usual_string, |
505 | r#" | 505 | r#" |
506 | fn f() { | 506 | fn f() { |
507 | let s = <|>"random string"; | 507 | let s = $0"random string"; |
508 | } | 508 | } |
509 | "#, | 509 | "#, |
510 | ); | 510 | ); |
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs index eae6367c1..6114091f2 100644 --- a/crates/assists/src/handlers/remove_dbg.rs +++ b/crates/assists/src/handlers/remove_dbg.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ |
2 | ast::{self, AstNode}, | 2 | ast::{self, AstNode}, |
3 | match_ast, SyntaxElement, SyntaxKind, TextRange, TextSize, T, | 3 | match_ast, SyntaxElement, TextRange, TextSize, T, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
@@ -11,7 +11,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
11 | // | 11 | // |
12 | // ``` | 12 | // ``` |
13 | // fn main() { | 13 | // fn main() { |
14 | // <|>dbg!(92); | 14 | // $0dbg!(92); |
15 | // } | 15 | // } |
16 | // ``` | 16 | // ``` |
17 | // -> | 17 | // -> |
@@ -136,14 +136,14 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) - | |||
136 | symbol_kind => { | 136 | symbol_kind => { |
137 | let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty(); | 137 | let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty(); |
138 | if symbol_not_in_bracket | 138 | if symbol_not_in_bracket |
139 | && symbol_kind != SyntaxKind::COLON // paths | 139 | && symbol_kind != T![:] // paths |
140 | && (symbol_kind != SyntaxKind::DOT // field/method access | 140 | && (symbol_kind != T![.] // field/method access |
141 | || macro_contents // range expressions consist of two SyntaxKind::Dot in macro invocations | 141 | || macro_contents // range expressions consist of two SyntaxKind::Dot in macro invocations |
142 | .peek() | 142 | .peek() |
143 | .map(|element| element.kind() == SyntaxKind::DOT) | 143 | .map(|element| element.kind() == T![.]) |
144 | .unwrap_or(false)) | 144 | .unwrap_or(false)) |
145 | && symbol_kind != SyntaxKind::QUESTION // try operator | 145 | && symbol_kind != T![?] // try operator |
146 | && (symbol_kind.is_punct() || symbol_kind == SyntaxKind::AS_KW) | 146 | && (symbol_kind.is_punct() || symbol_kind == T![as]) |
147 | { | 147 | { |
148 | return true; | 148 | return true; |
149 | } | 149 | } |
@@ -161,19 +161,19 @@ mod tests { | |||
161 | 161 | ||
162 | #[test] | 162 | #[test] |
163 | fn test_remove_dbg() { | 163 | fn test_remove_dbg() { |
164 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1"); | 164 | check_assist(remove_dbg, "$0dbg!(1 + 1)", "1 + 1"); |
165 | 165 | ||
166 | check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)"); | 166 | check_assist(remove_dbg, "dbg!$0((1 + 1))", "(1 + 1)"); |
167 | 167 | ||
168 | check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1"); | 168 | check_assist(remove_dbg, "dbg!(1 $0+ 1)", "1 + 1"); |
169 | 169 | ||
170 | check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1"); | 170 | check_assist(remove_dbg, "let _ = $0dbg!(1 + 1)", "let _ = 1 + 1"); |
171 | 171 | ||
172 | check_assist( | 172 | check_assist( |
173 | remove_dbg, | 173 | remove_dbg, |
174 | " | 174 | " |
175 | fn foo(n: usize) { | 175 | fn foo(n: usize) { |
176 | if let Some(_) = dbg!(n.<|>checked_sub(4)) { | 176 | if let Some(_) = dbg!(n.$0checked_sub(4)) { |
177 | // ... | 177 | // ... |
178 | } | 178 | } |
179 | } | 179 | } |
@@ -187,20 +187,20 @@ fn foo(n: usize) { | |||
187 | ", | 187 | ", |
188 | ); | 188 | ); |
189 | 189 | ||
190 | check_assist(remove_dbg, "<|>dbg!(Foo::foo_test()).bar()", "Foo::foo_test().bar()"); | 190 | check_assist(remove_dbg, "$0dbg!(Foo::foo_test()).bar()", "Foo::foo_test().bar()"); |
191 | } | 191 | } |
192 | 192 | ||
193 | #[test] | 193 | #[test] |
194 | fn test_remove_dbg_with_brackets_and_braces() { | 194 | fn test_remove_dbg_with_brackets_and_braces() { |
195 | check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1"); | 195 | check_assist(remove_dbg, "dbg![$01 + 1]", "1 + 1"); |
196 | check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1"); | 196 | check_assist(remove_dbg, "dbg!{$01 + 1}", "1 + 1"); |
197 | } | 197 | } |
198 | 198 | ||
199 | #[test] | 199 | #[test] |
200 | fn test_remove_dbg_not_applicable() { | 200 | fn test_remove_dbg_not_applicable() { |
201 | check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]"); | 201 | check_assist_not_applicable(remove_dbg, "$0vec![1, 2, 3]"); |
202 | check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)"); | 202 | check_assist_not_applicable(remove_dbg, "$0dbg(5, 6, 7)"); |
203 | check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7"); | 203 | check_assist_not_applicable(remove_dbg, "$0dbg!(5, 6, 7"); |
204 | } | 204 | } |
205 | 205 | ||
206 | #[test] | 206 | #[test] |
@@ -209,7 +209,7 @@ fn foo(n: usize) { | |||
209 | remove_dbg, | 209 | remove_dbg, |
210 | " | 210 | " |
211 | fn foo(n: usize) { | 211 | fn foo(n: usize) { |
212 | if let Some(_) = dbg!(n.<|>checked_sub(4)) { | 212 | if let Some(_) = dbg!(n.$0checked_sub(4)) { |
213 | // ... | 213 | // ... |
214 | } | 214 | } |
215 | } | 215 | } |
@@ -226,7 +226,7 @@ fn foo(n: usize) { | |||
226 | // the ast::MacroCall to include the semicolon at the end | 226 | // the ast::MacroCall to include the semicolon at the end |
227 | check_assist( | 227 | check_assist( |
228 | remove_dbg, | 228 | remove_dbg, |
229 | r#"let res = <|>dbg!(1 * 20); // needless comment"#, | 229 | r#"let res = $0dbg!(1 * 20); // needless comment"#, |
230 | r#"let res = 1 * 20; // needless comment"#, | 230 | r#"let res = 1 * 20; // needless comment"#, |
231 | ); | 231 | ); |
232 | } | 232 | } |
@@ -238,7 +238,7 @@ fn foo(n: usize) { | |||
238 | " | 238 | " |
239 | fn main() { | 239 | fn main() { |
240 | let mut a = 1; | 240 | let mut a = 1; |
241 | while dbg!<|>(a) < 10000 { | 241 | while dbg!$0(a) < 10000 { |
242 | a += 1; | 242 | a += 1; |
243 | } | 243 | } |
244 | } | 244 | } |
@@ -258,31 +258,31 @@ fn main() { | |||
258 | fn test_remove_dbg_keep_expression() { | 258 | fn test_remove_dbg_keep_expression() { |
259 | check_assist( | 259 | check_assist( |
260 | remove_dbg, | 260 | remove_dbg, |
261 | r#"let res = <|>dbg!(a + b).foo();"#, | 261 | r#"let res = $0dbg!(a + b).foo();"#, |
262 | r#"let res = (a + b).foo();"#, | 262 | r#"let res = (a + b).foo();"#, |
263 | ); | 263 | ); |
264 | 264 | ||
265 | check_assist(remove_dbg, r#"let res = <|>dbg!(2 + 2) * 5"#, r#"let res = (2 + 2) * 5"#); | 265 | check_assist(remove_dbg, r#"let res = $0dbg!(2 + 2) * 5"#, r#"let res = (2 + 2) * 5"#); |
266 | check_assist(remove_dbg, r#"let res = <|>dbg![2 + 2] * 5"#, r#"let res = (2 + 2) * 5"#); | 266 | check_assist(remove_dbg, r#"let res = $0dbg![2 + 2] * 5"#, r#"let res = (2 + 2) * 5"#); |
267 | } | 267 | } |
268 | 268 | ||
269 | #[test] | 269 | #[test] |
270 | fn test_remove_dbg_method_chaining() { | 270 | fn test_remove_dbg_method_chaining() { |
271 | check_assist( | 271 | check_assist( |
272 | remove_dbg, | 272 | remove_dbg, |
273 | r#"let res = <|>dbg!(foo().bar()).baz();"#, | 273 | r#"let res = $0dbg!(foo().bar()).baz();"#, |
274 | r#"let res = foo().bar().baz();"#, | 274 | r#"let res = foo().bar().baz();"#, |
275 | ); | 275 | ); |
276 | check_assist( | 276 | check_assist( |
277 | remove_dbg, | 277 | remove_dbg, |
278 | r#"let res = <|>dbg!(foo.bar()).baz();"#, | 278 | r#"let res = $0dbg!(foo.bar()).baz();"#, |
279 | r#"let res = foo.bar().baz();"#, | 279 | r#"let res = foo.bar().baz();"#, |
280 | ); | 280 | ); |
281 | } | 281 | } |
282 | 282 | ||
283 | #[test] | 283 | #[test] |
284 | fn test_remove_dbg_field_chaining() { | 284 | fn test_remove_dbg_field_chaining() { |
285 | check_assist(remove_dbg, r#"let res = <|>dbg!(foo.bar).baz;"#, r#"let res = foo.bar.baz;"#); | 285 | check_assist(remove_dbg, r#"let res = $0dbg!(foo.bar).baz;"#, r#"let res = foo.bar.baz;"#); |
286 | } | 286 | } |
287 | 287 | ||
288 | #[test] | 288 | #[test] |
@@ -295,7 +295,7 @@ fn square(x: u32) -> u32 { | |||
295 | } | 295 | } |
296 | 296 | ||
297 | fn main() { | 297 | fn main() { |
298 | let x = square(dbg<|>!(5 + 10)); | 298 | let x = square(dbg$0!(5 + 10)); |
299 | println!("{}", x); | 299 | println!("{}", x); |
300 | }"#, | 300 | }"#, |
301 | "dbg!(5 + 10)", | 301 | "dbg!(5 + 10)", |
@@ -309,7 +309,7 @@ fn square(x: u32) -> u32 { | |||
309 | } | 309 | } |
310 | 310 | ||
311 | fn main() { | 311 | fn main() { |
312 | let x = square(dbg<|>!(5 + 10)); | 312 | let x = square(dbg$0!(5 + 10)); |
313 | println!("{}", x); | 313 | println!("{}", x); |
314 | }"#, | 314 | }"#, |
315 | r#" | 315 | r#" |
@@ -328,7 +328,7 @@ fn main() { | |||
328 | fn test_remove_dbg_try_expr() { | 328 | fn test_remove_dbg_try_expr() { |
329 | check_assist( | 329 | check_assist( |
330 | remove_dbg, | 330 | remove_dbg, |
331 | r#"let res = <|>dbg!(result?).foo();"#, | 331 | r#"let res = $0dbg!(result?).foo();"#, |
332 | r#"let res = result?.foo();"#, | 332 | r#"let res = result?.foo();"#, |
333 | ); | 333 | ); |
334 | } | 334 | } |
@@ -337,7 +337,7 @@ fn main() { | |||
337 | fn test_remove_dbg_await_expr() { | 337 | fn test_remove_dbg_await_expr() { |
338 | check_assist( | 338 | check_assist( |
339 | remove_dbg, | 339 | remove_dbg, |
340 | r#"let res = <|>dbg!(fut.await).foo();"#, | 340 | r#"let res = $0dbg!(fut.await).foo();"#, |
341 | r#"let res = fut.await.foo();"#, | 341 | r#"let res = fut.await.foo();"#, |
342 | ); | 342 | ); |
343 | } | 343 | } |
@@ -346,7 +346,7 @@ fn main() { | |||
346 | fn test_remove_dbg_as_cast() { | 346 | fn test_remove_dbg_as_cast() { |
347 | check_assist( | 347 | check_assist( |
348 | remove_dbg, | 348 | remove_dbg, |
349 | r#"let res = <|>dbg!(3 as usize).foo();"#, | 349 | r#"let res = $0dbg!(3 as usize).foo();"#, |
350 | r#"let res = (3 as usize).foo();"#, | 350 | r#"let res = (3 as usize).foo();"#, |
351 | ); | 351 | ); |
352 | } | 352 | } |
@@ -355,12 +355,12 @@ fn main() { | |||
355 | fn test_remove_dbg_index_expr() { | 355 | fn test_remove_dbg_index_expr() { |
356 | check_assist( | 356 | check_assist( |
357 | remove_dbg, | 357 | remove_dbg, |
358 | r#"let res = <|>dbg!(array[3]).foo();"#, | 358 | r#"let res = $0dbg!(array[3]).foo();"#, |
359 | r#"let res = array[3].foo();"#, | 359 | r#"let res = array[3].foo();"#, |
360 | ); | 360 | ); |
361 | check_assist( | 361 | check_assist( |
362 | remove_dbg, | 362 | remove_dbg, |
363 | r#"let res = <|>dbg!(tuple.3).foo();"#, | 363 | r#"let res = $0dbg!(tuple.3).foo();"#, |
364 | r#"let res = tuple.3.foo();"#, | 364 | r#"let res = tuple.3.foo();"#, |
365 | ); | 365 | ); |
366 | } | 366 | } |
@@ -369,12 +369,12 @@ fn main() { | |||
369 | fn test_remove_dbg_range_expr() { | 369 | fn test_remove_dbg_range_expr() { |
370 | check_assist( | 370 | check_assist( |
371 | remove_dbg, | 371 | remove_dbg, |
372 | r#"let res = <|>dbg!(foo..bar).foo();"#, | 372 | r#"let res = $0dbg!(foo..bar).foo();"#, |
373 | r#"let res = (foo..bar).foo();"#, | 373 | r#"let res = (foo..bar).foo();"#, |
374 | ); | 374 | ); |
375 | check_assist( | 375 | check_assist( |
376 | remove_dbg, | 376 | remove_dbg, |
377 | r#"let res = <|>dbg!(foo..=bar).foo();"#, | 377 | r#"let res = $0dbg!(foo..=bar).foo();"#, |
378 | r#"let res = (foo..=bar).foo();"#, | 378 | r#"let res = (foo..=bar).foo();"#, |
379 | ); | 379 | ); |
380 | } | 380 | } |
@@ -384,7 +384,7 @@ fn main() { | |||
384 | check_assist( | 384 | check_assist( |
385 | remove_dbg, | 385 | remove_dbg, |
386 | r#"fn foo() { | 386 | r#"fn foo() { |
387 | if <|>dbg!(x || y) {} | 387 | if $0dbg!(x || y) {} |
388 | }"#, | 388 | }"#, |
389 | r#"fn foo() { | 389 | r#"fn foo() { |
390 | if x || y {} | 390 | if x || y {} |
@@ -393,7 +393,7 @@ fn main() { | |||
393 | check_assist( | 393 | check_assist( |
394 | remove_dbg, | 394 | remove_dbg, |
395 | r#"fn foo() { | 395 | r#"fn foo() { |
396 | while let foo = <|>dbg!(&x) {} | 396 | while let foo = $0dbg!(&x) {} |
397 | }"#, | 397 | }"#, |
398 | r#"fn foo() { | 398 | r#"fn foo() { |
399 | while let foo = &x {} | 399 | while let foo = &x {} |
@@ -402,7 +402,7 @@ fn main() { | |||
402 | check_assist( | 402 | check_assist( |
403 | remove_dbg, | 403 | remove_dbg, |
404 | r#"fn foo() { | 404 | r#"fn foo() { |
405 | if let foo = <|>dbg!(&x) {} | 405 | if let foo = $0dbg!(&x) {} |
406 | }"#, | 406 | }"#, |
407 | r#"fn foo() { | 407 | r#"fn foo() { |
408 | if let foo = &x {} | 408 | if let foo = &x {} |
@@ -411,7 +411,7 @@ fn main() { | |||
411 | check_assist( | 411 | check_assist( |
412 | remove_dbg, | 412 | remove_dbg, |
413 | r#"fn foo() { | 413 | r#"fn foo() { |
414 | match <|>dbg!(&x) {} | 414 | match $0dbg!(&x) {} |
415 | }"#, | 415 | }"#, |
416 | r#"fn foo() { | 416 | r#"fn foo() { |
417 | match &x {} | 417 | match &x {} |
diff --git a/crates/assists/src/handlers/remove_mut.rs b/crates/assists/src/handlers/remove_mut.rs index 575b271f7..30d36dacd 100644 --- a/crates/assists/src/handlers/remove_mut.rs +++ b/crates/assists/src/handlers/remove_mut.rs | |||
@@ -8,7 +8,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
8 | // | 8 | // |
9 | // ``` | 9 | // ``` |
10 | // impl Walrus { | 10 | // impl Walrus { |
11 | // fn feed(&mut<|> self, amount: u32) {} | 11 | // fn feed(&mut$0 self, amount: u32) {} |
12 | // } | 12 | // } |
13 | // ``` | 13 | // ``` |
14 | // -> | 14 | // -> |
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs index f72dd49ed..c961680e2 100644 --- a/crates/assists/src/handlers/remove_unused_param.rs +++ b/crates/assists/src/handlers/remove_unused_param.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use ide_db::{defs::Definition, search::Reference}; | 1 | use ide_db::{base_db::FileId, defs::Definition, search::FileReference}; |
2 | use syntax::{ | 2 | use syntax::{ |
3 | algo::find_node_at_range, | 3 | algo::find_node_at_range, |
4 | ast::{self, ArgListOwner}, | 4 | ast::{self, ArgListOwner}, |
5 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, | 5 | AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T, |
6 | }; | 6 | }; |
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | use SyntaxKind::WHITESPACE; | 8 | use SyntaxKind::WHITESPACE; |
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | // Removes unused function parameter. | 16 | // Removes unused function parameter. |
17 | // | 17 | // |
18 | // ``` | 18 | // ``` |
19 | // fn frobnicate(x: i32<|>) {} | 19 | // fn frobnicate(x: i32$0) {} |
20 | // | 20 | // |
21 | // fn main() { | 21 | // fn main() { |
22 | // frobnicate(92); | 22 | // frobnicate(92); |
@@ -58,32 +58,41 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
58 | param.syntax().text_range(), | 58 | param.syntax().text_range(), |
59 | |builder| { | 59 | |builder| { |
60 | builder.delete(range_to_remove(param.syntax())); | 60 | builder.delete(range_to_remove(param.syntax())); |
61 | for usage in fn_def.usages(&ctx.sema).all() { | 61 | for (file_id, references) in fn_def.usages(&ctx.sema).all() { |
62 | process_usage(ctx, builder, usage, param_position); | 62 | process_usages(ctx, builder, file_id, references, param_position); |
63 | } | 63 | } |
64 | }, | 64 | }, |
65 | ) | 65 | ) |
66 | } | 66 | } |
67 | 67 | ||
68 | fn process_usage( | 68 | fn process_usages( |
69 | ctx: &AssistContext, | 69 | ctx: &AssistContext, |
70 | builder: &mut AssistBuilder, | 70 | builder: &mut AssistBuilder, |
71 | usage: Reference, | 71 | file_id: FileId, |
72 | references: Vec<FileReference>, | ||
72 | arg_to_remove: usize, | 73 | arg_to_remove: usize, |
73 | ) -> Option<()> { | 74 | ) { |
74 | let source_file = ctx.sema.parse(usage.file_range.file_id); | 75 | let source_file = ctx.sema.parse(file_id); |
75 | let call_expr: ast::CallExpr = | 76 | builder.edit_file(file_id); |
76 | find_node_at_range(source_file.syntax(), usage.file_range.range)?; | 77 | for usage in references { |
78 | if let Some(text_range) = process_usage(&source_file, usage, arg_to_remove) { | ||
79 | builder.delete(text_range); | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | fn process_usage( | ||
85 | source_file: &SourceFile, | ||
86 | FileReference { range, .. }: FileReference, | ||
87 | arg_to_remove: usize, | ||
88 | ) -> Option<TextRange> { | ||
89 | let call_expr: ast::CallExpr = find_node_at_range(source_file.syntax(), range)?; | ||
77 | let call_expr_range = call_expr.expr()?.syntax().text_range(); | 90 | let call_expr_range = call_expr.expr()?.syntax().text_range(); |
78 | if !call_expr_range.contains_range(usage.file_range.range) { | 91 | if !call_expr_range.contains_range(range) { |
79 | return None; | 92 | return None; |
80 | } | 93 | } |
81 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; | 94 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; |
82 | 95 | Some(range_to_remove(arg.syntax())) | |
83 | builder.edit_file(usage.file_range.file_id); | ||
84 | builder.delete(range_to_remove(arg.syntax())); | ||
85 | |||
86 | Some(()) | ||
87 | } | 96 | } |
88 | 97 | ||
89 | fn range_to_remove(node: &SyntaxNode) -> TextRange { | 98 | fn range_to_remove(node: &SyntaxNode) -> TextRange { |
@@ -123,7 +132,7 @@ mod tests { | |||
123 | remove_unused_param, | 132 | remove_unused_param, |
124 | r#" | 133 | r#" |
125 | fn a() { foo(9, 2) } | 134 | fn a() { foo(9, 2) } |
126 | fn foo(x: i32, <|>y: i32) { x; } | 135 | fn foo(x: i32, $0y: i32) { x; } |
127 | fn b() { foo(9, 2,) } | 136 | fn b() { foo(9, 2,) } |
128 | "#, | 137 | "#, |
129 | r#" | 138 | r#" |
@@ -139,7 +148,7 @@ fn b() { foo(9, ) } | |||
139 | check_assist( | 148 | check_assist( |
140 | remove_unused_param, | 149 | remove_unused_param, |
141 | r#" | 150 | r#" |
142 | fn foo(<|>x: i32, y: i32) { y; } | 151 | fn foo($0x: i32, y: i32) { y; } |
143 | fn a() { foo(1, 2) } | 152 | fn a() { foo(1, 2) } |
144 | fn b() { foo(1, 2,) } | 153 | fn b() { foo(1, 2,) } |
145 | "#, | 154 | "#, |
@@ -156,7 +165,7 @@ fn b() { foo(2,) } | |||
156 | check_assist( | 165 | check_assist( |
157 | remove_unused_param, | 166 | remove_unused_param, |
158 | r#" | 167 | r#" |
159 | fn foo(<|>x: i32) { 0; } | 168 | fn foo($0x: i32) { 0; } |
160 | fn a() { foo(1) } | 169 | fn a() { foo(1) } |
161 | fn b() { foo(1, ) } | 170 | fn b() { foo(1, ) } |
162 | "#, | 171 | "#, |
@@ -173,7 +182,7 @@ fn b() { foo( ) } | |||
173 | check_assist( | 182 | check_assist( |
174 | remove_unused_param, | 183 | remove_unused_param, |
175 | r#" | 184 | r#" |
176 | fn foo(x: i32, <|>y: i32, z: i32) { x; } | 185 | fn foo(x: i32, $0y: i32, z: i32) { x; } |
177 | fn a() { foo(1, 2, 3) } | 186 | fn a() { foo(1, 2, 3) } |
178 | fn b() { foo(1, 2, 3,) } | 187 | fn b() { foo(1, 2, 3,) } |
179 | "#, | 188 | "#, |
@@ -190,7 +199,7 @@ fn b() { foo(1, 3,) } | |||
190 | check_assist( | 199 | check_assist( |
191 | remove_unused_param, | 200 | remove_unused_param, |
192 | r#" | 201 | r#" |
193 | mod bar { pub fn foo(x: i32, <|>y: i32) { x; } } | 202 | mod bar { pub fn foo(x: i32, $0y: i32) { x; } } |
194 | fn b() { bar::foo(9, 2) } | 203 | fn b() { bar::foo(9, 2) } |
195 | "#, | 204 | "#, |
196 | r#" | 205 | r#" |
@@ -205,7 +214,7 @@ fn b() { bar::foo(9) } | |||
205 | check_assist( | 214 | check_assist( |
206 | remove_unused_param, | 215 | remove_unused_param, |
207 | r#" | 216 | r#" |
208 | pub fn foo<T>(x: T, <|>y: i32) { x; } | 217 | pub fn foo<T>(x: T, $0y: i32) { x; } |
209 | fn b() { foo::<i32>(9, 2) } | 218 | fn b() { foo::<i32>(9, 2) } |
210 | "#, | 219 | "#, |
211 | r#" | 220 | r#" |
@@ -220,7 +229,7 @@ fn b() { foo::<i32>(9) } | |||
220 | check_assist( | 229 | check_assist( |
221 | remove_unused_param, | 230 | remove_unused_param, |
222 | r#" | 231 | r#" |
223 | pub fn foo<T>(x: i32, <|>y: T) { x; } | 232 | pub fn foo<T>(x: i32, $0y: T) { x; } |
224 | fn b() { foo::<i32>(9, 2) } | 233 | fn b() { foo::<i32>(9, 2) } |
225 | fn b2() { foo(9, 2) } | 234 | fn b2() { foo(9, 2) } |
226 | "#, | 235 | "#, |
@@ -238,7 +247,7 @@ fn b2() { foo(9) } | |||
238 | check_assist_not_applicable( | 247 | check_assist_not_applicable( |
239 | remove_unused_param, | 248 | remove_unused_param, |
240 | r#" | 249 | r#" |
241 | fn foo(x: i32, <|>y: i32) { y; } | 250 | fn foo(x: i32, $0y: i32) { y; } |
242 | fn main() { foo(9, 2) } | 251 | fn main() { foo(9, 2) } |
243 | "#, | 252 | "#, |
244 | ); | 253 | ); |
@@ -250,7 +259,7 @@ fn main() { foo(9, 2) } | |||
250 | remove_unused_param, | 259 | remove_unused_param, |
251 | r#" | 260 | r#" |
252 | //- /main.rs | 261 | //- /main.rs |
253 | fn foo(x: i32, <|>y: i32) { x; } | 262 | fn foo(x: i32, $0y: i32) { x; } |
254 | 263 | ||
255 | mod foo; | 264 | mod foo; |
256 | 265 | ||
diff --git a/crates/assists/src/handlers/reorder_fields.rs b/crates/assists/src/handlers/reorder_fields.rs index fe5574242..fba7d6ddb 100644 --- a/crates/assists/src/handlers/reorder_fields.rs +++ b/crates/assists/src/handlers/reorder_fields.rs | |||
@@ -15,7 +15,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
15 | // | 15 | // |
16 | // ``` | 16 | // ``` |
17 | // struct Foo {foo: i32, bar: i32}; | 17 | // struct Foo {foo: i32, bar: i32}; |
18 | // const test: Foo = <|>Foo {bar: 0, foo: 1} | 18 | // const test: Foo = $0Foo {bar: 0, foo: 1} |
19 | // ``` | 19 | // ``` |
20 | // -> | 20 | // -> |
21 | // ``` | 21 | // ``` |
@@ -126,7 +126,7 @@ struct Foo { | |||
126 | bar: i32, | 126 | bar: i32, |
127 | } | 127 | } |
128 | 128 | ||
129 | const test: Foo = <|>Foo { foo: 0, bar: 0 }; | 129 | const test: Foo = $0Foo { foo: 0, bar: 0 }; |
130 | "#, | 130 | "#, |
131 | ) | 131 | ) |
132 | } | 132 | } |
@@ -137,7 +137,7 @@ const test: Foo = <|>Foo { foo: 0, bar: 0 }; | |||
137 | reorder_fields, | 137 | reorder_fields, |
138 | r#" | 138 | r#" |
139 | struct Foo {}; | 139 | struct Foo {}; |
140 | const test: Foo = <|>Foo {} | 140 | const test: Foo = $0Foo {} |
141 | "#, | 141 | "#, |
142 | ) | 142 | ) |
143 | } | 143 | } |
@@ -148,7 +148,7 @@ const test: Foo = <|>Foo {} | |||
148 | reorder_fields, | 148 | reorder_fields, |
149 | r#" | 149 | r#" |
150 | struct Foo {foo: i32, bar: i32}; | 150 | struct Foo {foo: i32, bar: i32}; |
151 | const test: Foo = <|>Foo {bar: 0, foo: 1} | 151 | const test: Foo = $0Foo {bar: 0, foo: 1} |
152 | "#, | 152 | "#, |
153 | r#" | 153 | r#" |
154 | struct Foo {foo: i32, bar: i32}; | 154 | struct Foo {foo: i32, bar: i32}; |
@@ -166,7 +166,7 @@ struct Foo { foo: i64, bar: i64, baz: i64 } | |||
166 | 166 | ||
167 | fn f(f: Foo) -> { | 167 | fn f(f: Foo) -> { |
168 | match f { | 168 | match f { |
169 | <|>Foo { baz: 0, ref mut bar, .. } => (), | 169 | $0Foo { baz: 0, ref mut bar, .. } => (), |
170 | _ => () | 170 | _ => () |
171 | } | 171 | } |
172 | } | 172 | } |
@@ -197,7 +197,7 @@ struct Foo { | |||
197 | impl Foo { | 197 | impl Foo { |
198 | fn new() -> Foo { | 198 | fn new() -> Foo { |
199 | let foo = String::new(); | 199 | let foo = String::new(); |
200 | <|>Foo { | 200 | $0Foo { |
201 | bar: foo.clone(), | 201 | bar: foo.clone(), |
202 | extra: "Extra field", | 202 | extra: "Extra field", |
203 | foo, | 203 | foo, |
diff --git a/crates/assists/src/handlers/reorder_impl.rs b/crates/assists/src/handlers/reorder_impl.rs new file mode 100644 index 000000000..309f291c8 --- /dev/null +++ b/crates/assists/src/handlers/reorder_impl.rs | |||
@@ -0,0 +1,201 @@ | |||
1 | use itertools::Itertools; | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use hir::{PathResolution, Semantics}; | ||
5 | use ide_db::RootDatabase; | ||
6 | use syntax::{ | ||
7 | algo, | ||
8 | ast::{self, NameOwner}, | ||
9 | AstNode, | ||
10 | }; | ||
11 | use test_utils::mark; | ||
12 | |||
13 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
14 | |||
15 | // Assist: reorder_impl | ||
16 | // | ||
17 | // Reorder the methods of an `impl Trait`. The methods will be ordered | ||
18 | // in the same order as in the trait definition. | ||
19 | // | ||
20 | // ``` | ||
21 | // trait Foo { | ||
22 | // fn a() {} | ||
23 | // fn b() {} | ||
24 | // fn c() {} | ||
25 | // } | ||
26 | // | ||
27 | // struct Bar; | ||
28 | // $0impl Foo for Bar { | ||
29 | // fn b() {} | ||
30 | // fn c() {} | ||
31 | // fn a() {} | ||
32 | // } | ||
33 | // ``` | ||
34 | // -> | ||
35 | // ``` | ||
36 | // trait Foo { | ||
37 | // fn a() {} | ||
38 | // fn b() {} | ||
39 | // fn c() {} | ||
40 | // } | ||
41 | // | ||
42 | // struct Bar; | ||
43 | // impl Foo for Bar { | ||
44 | // fn a() {} | ||
45 | // fn b() {} | ||
46 | // fn c() {} | ||
47 | // } | ||
48 | // ``` | ||
49 | // | ||
50 | pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
51 | let impl_ast = ctx.find_node_at_offset::<ast::Impl>()?; | ||
52 | let items = impl_ast.assoc_item_list()?; | ||
53 | let methods = get_methods(&items); | ||
54 | |||
55 | let path = impl_ast | ||
56 | .trait_() | ||
57 | .and_then(|t| match t { | ||
58 | ast::Type::PathType(path) => Some(path), | ||
59 | _ => None, | ||
60 | })? | ||
61 | .path()?; | ||
62 | |||
63 | let ranks = compute_method_ranks(&path, ctx)?; | ||
64 | let sorted: Vec<_> = methods | ||
65 | .iter() | ||
66 | .cloned() | ||
67 | .sorted_by_key(|f| { | ||
68 | f.name().and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value()) | ||
69 | }) | ||
70 | .collect(); | ||
71 | |||
72 | // Don't edit already sorted methods: | ||
73 | if methods == sorted { | ||
74 | mark::hit!(not_applicable_if_sorted); | ||
75 | return None; | ||
76 | } | ||
77 | |||
78 | let target = items.syntax().text_range(); | ||
79 | acc.add(AssistId("reorder_impl", AssistKind::RefactorRewrite), "Sort methods", target, |edit| { | ||
80 | let mut rewriter = algo::SyntaxRewriter::default(); | ||
81 | for (old, new) in methods.iter().zip(&sorted) { | ||
82 | rewriter.replace(old.syntax(), new.syntax()); | ||
83 | } | ||
84 | edit.rewrite(rewriter); | ||
85 | }) | ||
86 | } | ||
87 | |||
88 | fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { | ||
89 | let td = trait_definition(path, &ctx.sema)?; | ||
90 | |||
91 | Some( | ||
92 | td.items(ctx.db()) | ||
93 | .iter() | ||
94 | .flat_map(|i| match i { | ||
95 | hir::AssocItem::Function(f) => Some(f), | ||
96 | _ => None, | ||
97 | }) | ||
98 | .enumerate() | ||
99 | .map(|(idx, func)| ((func.name(ctx.db()).to_string(), idx))) | ||
100 | .collect(), | ||
101 | ) | ||
102 | } | ||
103 | |||
104 | fn trait_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<hir::Trait> { | ||
105 | match sema.resolve_path(path)? { | ||
106 | PathResolution::Def(hir::ModuleDef::Trait(trait_)) => Some(trait_), | ||
107 | _ => None, | ||
108 | } | ||
109 | } | ||
110 | |||
111 | fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> { | ||
112 | items | ||
113 | .assoc_items() | ||
114 | .flat_map(|i| match i { | ||
115 | ast::AssocItem::Fn(f) => Some(f), | ||
116 | _ => None, | ||
117 | }) | ||
118 | .filter(|f| f.name().is_some()) | ||
119 | .collect() | ||
120 | } | ||
121 | |||
122 | #[cfg(test)] | ||
123 | mod tests { | ||
124 | use test_utils::mark; | ||
125 | |||
126 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
127 | |||
128 | use super::*; | ||
129 | |||
130 | #[test] | ||
131 | fn not_applicable_if_sorted() { | ||
132 | mark::check!(not_applicable_if_sorted); | ||
133 | check_assist_not_applicable( | ||
134 | reorder_impl, | ||
135 | r#" | ||
136 | trait Bar { | ||
137 | fn a() {} | ||
138 | fn z() {} | ||
139 | fn b() {} | ||
140 | } | ||
141 | struct Foo; | ||
142 | $0impl Bar for Foo { | ||
143 | fn a() {} | ||
144 | fn z() {} | ||
145 | fn b() {} | ||
146 | } | ||
147 | "#, | ||
148 | ) | ||
149 | } | ||
150 | |||
151 | #[test] | ||
152 | fn not_applicable_if_empty() { | ||
153 | check_assist_not_applicable( | ||
154 | reorder_impl, | ||
155 | r#" | ||
156 | trait Bar {}; | ||
157 | struct Foo; | ||
158 | $0impl Bar for Foo {} | ||
159 | "#, | ||
160 | ) | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn reorder_impl_trait_methods() { | ||
165 | check_assist( | ||
166 | reorder_impl, | ||
167 | r#" | ||
168 | trait Bar { | ||
169 | fn a() {} | ||
170 | fn c() {} | ||
171 | fn b() {} | ||
172 | fn d() {} | ||
173 | } | ||
174 | |||
175 | struct Foo; | ||
176 | $0impl Bar for Foo { | ||
177 | fn d() {} | ||
178 | fn b() {} | ||
179 | fn c() {} | ||
180 | fn a() {} | ||
181 | } | ||
182 | "#, | ||
183 | r#" | ||
184 | trait Bar { | ||
185 | fn a() {} | ||
186 | fn c() {} | ||
187 | fn b() {} | ||
188 | fn d() {} | ||
189 | } | ||
190 | |||
191 | struct Foo; | ||
192 | impl Bar for Foo { | ||
193 | fn a() {} | ||
194 | fn c() {} | ||
195 | fn b() {} | ||
196 | fn d() {} | ||
197 | } | ||
198 | "#, | ||
199 | ) | ||
200 | } | ||
201 | } | ||
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 cb7a5c104..bd4c1c806 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -22,7 +22,7 @@ use crate::{ | |||
22 | // | 22 | // |
23 | // ``` | 23 | // ``` |
24 | // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; } | 24 | // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; } |
25 | // #[derive(Deb<|>ug, Display)] | 25 | // #[derive(Deb$0ug, Display)] |
26 | // struct S; | 26 | // struct S; |
27 | // ``` | 27 | // ``` |
28 | // -> | 28 | // -> |
@@ -219,7 +219,7 @@ mod fmt { | |||
219 | } | 219 | } |
220 | } | 220 | } |
221 | 221 | ||
222 | #[derive(Debu<|>g)] | 222 | #[derive(Debu$0g)] |
223 | struct Foo { | 223 | struct Foo { |
224 | bar: String, | 224 | bar: String, |
225 | } | 225 | } |
@@ -261,7 +261,7 @@ mod foo { | |||
261 | } | 261 | } |
262 | } | 262 | } |
263 | 263 | ||
264 | #[derive(<|>Bar)] | 264 | #[derive($0Bar)] |
265 | struct Foo { | 265 | struct Foo { |
266 | bar: String, | 266 | bar: String, |
267 | } | 267 | } |
@@ -300,7 +300,7 @@ impl foo::Bar for Foo { | |||
300 | check_assist( | 300 | check_assist( |
301 | replace_derive_with_manual_impl, | 301 | replace_derive_with_manual_impl, |
302 | " | 302 | " |
303 | #[derive(Debu<|>g)] | 303 | #[derive(Debu$0g)] |
304 | struct Foo { | 304 | struct Foo { |
305 | bar: String, | 305 | bar: String, |
306 | } | 306 | } |
@@ -322,7 +322,7 @@ impl Debug for Foo { | |||
322 | check_assist( | 322 | check_assist( |
323 | replace_derive_with_manual_impl, | 323 | replace_derive_with_manual_impl, |
324 | " | 324 | " |
325 | #[derive(Debug<|>)] | 325 | #[derive(Debug$0)] |
326 | pub struct Foo { | 326 | pub struct Foo { |
327 | bar: String, | 327 | bar: String, |
328 | } | 328 | } |
@@ -344,7 +344,7 @@ impl Debug for Foo { | |||
344 | check_assist( | 344 | check_assist( |
345 | replace_derive_with_manual_impl, | 345 | replace_derive_with_manual_impl, |
346 | " | 346 | " |
347 | #[derive(Display, Debug<|>, Serialize)] | 347 | #[derive(Display, Debug$0, Serialize)] |
348 | struct Foo {} | 348 | struct Foo {} |
349 | ", | 349 | ", |
350 | " | 350 | " |
@@ -363,7 +363,7 @@ impl Debug for Foo { | |||
363 | check_assist_not_applicable( | 363 | check_assist_not_applicable( |
364 | replace_derive_with_manual_impl, | 364 | replace_derive_with_manual_impl, |
365 | " | 365 | " |
366 | #[derive(<|>)] | 366 | #[derive($0)] |
367 | struct Foo {} | 367 | struct Foo {} |
368 | ", | 368 | ", |
369 | ) | 369 | ) |
@@ -374,7 +374,7 @@ struct Foo {} | |||
374 | check_assist_not_applicable( | 374 | check_assist_not_applicable( |
375 | replace_derive_with_manual_impl, | 375 | replace_derive_with_manual_impl, |
376 | " | 376 | " |
377 | #[derive<|>(Debug)] | 377 | #[derive$0(Debug)] |
378 | struct Foo {} | 378 | struct Foo {} |
379 | ", | 379 | ", |
380 | ); | 380 | ); |
@@ -382,7 +382,7 @@ struct Foo {} | |||
382 | check_assist_not_applicable( | 382 | check_assist_not_applicable( |
383 | replace_derive_with_manual_impl, | 383 | replace_derive_with_manual_impl, |
384 | " | 384 | " |
385 | #[derive(Debug)<|>] | 385 | #[derive(Debug)$0] |
386 | struct Foo {} | 386 | struct Foo {} |
387 | ", | 387 | ", |
388 | ) | 388 | ) |
@@ -393,7 +393,7 @@ struct Foo {} | |||
393 | check_assist_not_applicable( | 393 | check_assist_not_applicable( |
394 | replace_derive_with_manual_impl, | 394 | replace_derive_with_manual_impl, |
395 | " | 395 | " |
396 | #[allow(non_camel_<|>case_types)] | 396 | #[allow(non_camel_$0case_types)] |
397 | struct Foo {} | 397 | struct Foo {} |
398 | ", | 398 | ", |
399 | ) | 399 | ) |
diff --git a/crates/assists/src/handlers/replace_if_let_with_match.rs b/crates/assists/src/handlers/replace_if_let_with_match.rs index 4a355c66f..aee3397ab 100644 --- a/crates/assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -20,7 +20,7 @@ use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, As | |||
20 | // enum Action { Move { distance: u32 }, Stop } | 20 | // enum Action { Move { distance: u32 }, Stop } |
21 | // | 21 | // |
22 | // fn handle(action: Action) { | 22 | // fn handle(action: Action) { |
23 | // <|>if let Action::Move { distance } = action { | 23 | // $0if let Action::Move { distance } = action { |
24 | // foo(distance) | 24 | // foo(distance) |
25 | // } else { | 25 | // } else { |
26 | // bar() | 26 | // bar() |
@@ -89,7 +89,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
89 | // enum Action { Move { distance: u32 }, Stop } | 89 | // enum Action { Move { distance: u32 }, Stop } |
90 | // | 90 | // |
91 | // fn handle(action: Action) { | 91 | // fn handle(action: Action) { |
92 | // <|>match action { | 92 | // $0match action { |
93 | // Action::Move { distance } => foo(distance), | 93 | // Action::Move { distance } => foo(distance), |
94 | // _ => bar(), | 94 | // _ => bar(), |
95 | // } | 95 | // } |
@@ -138,7 +138,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext) | |||
138 | }; | 138 | }; |
139 | let else_expr = match else_expr { | 139 | let else_expr = match else_expr { |
140 | ast::Expr::BlockExpr(block) | 140 | ast::Expr::BlockExpr(block) |
141 | if block.statements().count() == 0 && block.expr().is_none() => | 141 | if block.statements().count() == 0 && block.tail_expr().is_none() => |
142 | { | 142 | { |
143 | None | 143 | None |
144 | } | 144 | } |
@@ -179,7 +179,7 @@ mod tests { | |||
179 | r#" | 179 | r#" |
180 | impl VariantData { | 180 | impl VariantData { |
181 | pub fn is_struct(&self) -> bool { | 181 | pub fn is_struct(&self) -> bool { |
182 | if <|>let VariantData::Struct(..) = *self { | 182 | if $0let VariantData::Struct(..) = *self { |
183 | true | 183 | true |
184 | } else { | 184 | } else { |
185 | false | 185 | false |
@@ -204,7 +204,7 @@ impl VariantData { | |||
204 | replace_if_let_with_match, | 204 | replace_if_let_with_match, |
205 | r#" | 205 | r#" |
206 | fn foo() { | 206 | fn foo() { |
207 | if <|>let VariantData::Struct(..) = a { | 207 | if $0let VariantData::Struct(..) = a { |
208 | bar( | 208 | bar( |
209 | 123 | 209 | 123 |
210 | ) | 210 | ) |
@@ -233,7 +233,7 @@ fn foo() { | |||
233 | r#" | 233 | r#" |
234 | impl VariantData { | 234 | impl VariantData { |
235 | pub fn is_struct(&self) -> bool { | 235 | pub fn is_struct(&self) -> bool { |
236 | if <|>let VariantData::Struct(..) = *self { | 236 | if $0let VariantData::Struct(..) = *self { |
237 | true | 237 | true |
238 | } else { | 238 | } else { |
239 | false | 239 | false |
@@ -257,7 +257,7 @@ enum Option<T> { Some(T), None } | |||
257 | use Option::*; | 257 | use Option::*; |
258 | 258 | ||
259 | fn foo(x: Option<i32>) { | 259 | fn foo(x: Option<i32>) { |
260 | <|>if let Some(x) = x { | 260 | $0if let Some(x) = x { |
261 | println!("{}", x) | 261 | println!("{}", x) |
262 | } else { | 262 | } else { |
263 | println!("none") | 263 | println!("none") |
@@ -287,7 +287,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
287 | use Result::*; | 287 | use Result::*; |
288 | 288 | ||
289 | fn foo(x: Result<i32, ()>) { | 289 | fn foo(x: Result<i32, ()>) { |
290 | <|>if let Ok(x) = x { | 290 | $0if let Ok(x) = x { |
291 | println!("{}", x) | 291 | println!("{}", x) |
292 | } else { | 292 | } else { |
293 | println!("none") | 293 | println!("none") |
@@ -315,7 +315,7 @@ fn foo(x: Result<i32, ()>) { | |||
315 | r#" | 315 | r#" |
316 | fn main() { | 316 | fn main() { |
317 | if true { | 317 | if true { |
318 | <|>if let Ok(rel_path) = path.strip_prefix(root_path) { | 318 | $0if let Ok(rel_path) = path.strip_prefix(root_path) { |
319 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | 319 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; |
320 | Some((*id, rel_path)) | 320 | Some((*id, rel_path)) |
321 | } else { | 321 | } else { |
@@ -347,7 +347,7 @@ fn main() { | |||
347 | r#" | 347 | r#" |
348 | impl VariantData { | 348 | impl VariantData { |
349 | pub fn is_struct(&self) -> bool { | 349 | pub fn is_struct(&self) -> bool { |
350 | <|>match *self { | 350 | $0match *self { |
351 | VariantData::Struct(..) => true, | 351 | VariantData::Struct(..) => true, |
352 | _ => false, | 352 | _ => false, |
353 | } | 353 | } |
@@ -372,7 +372,7 @@ impl VariantData { | |||
372 | replace_match_with_if_let, | 372 | replace_match_with_if_let, |
373 | r#" | 373 | r#" |
374 | fn foo() { | 374 | fn foo() { |
375 | <|>match a { | 375 | $0match a { |
376 | VariantData::Struct(..) => { | 376 | VariantData::Struct(..) => { |
377 | bar( | 377 | bar( |
378 | 123 | 378 | 123 |
@@ -401,7 +401,7 @@ fn foo() { | |||
401 | r#" | 401 | r#" |
402 | impl VariantData { | 402 | impl VariantData { |
403 | pub fn is_struct(&self) -> bool { | 403 | pub fn is_struct(&self) -> bool { |
404 | <|>match *self { | 404 | $0match *self { |
405 | VariantData::Struct(..) => true, | 405 | VariantData::Struct(..) => true, |
406 | _ => false, | 406 | _ => false, |
407 | } | 407 | } |
@@ -423,7 +423,7 @@ enum Option<T> { Some(T), None } | |||
423 | use Option::*; | 423 | use Option::*; |
424 | 424 | ||
425 | fn foo(x: Option<i32>) { | 425 | fn foo(x: Option<i32>) { |
426 | <|>match x { | 426 | $0match x { |
427 | Some(x) => println!("{}", x), | 427 | Some(x) => println!("{}", x), |
428 | None => println!("none"), | 428 | None => println!("none"), |
429 | } | 429 | } |
@@ -453,7 +453,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
453 | use Result::*; | 453 | use Result::*; |
454 | 454 | ||
455 | fn foo(x: Result<i32, ()>) { | 455 | fn foo(x: Result<i32, ()>) { |
456 | <|>match x { | 456 | $0match x { |
457 | Ok(x) => println!("{}", x), | 457 | Ok(x) => println!("{}", x), |
458 | Err(_) => println!("none"), | 458 | Err(_) => println!("none"), |
459 | } | 459 | } |
@@ -481,7 +481,7 @@ fn foo(x: Result<i32, ()>) { | |||
481 | r#" | 481 | r#" |
482 | fn main() { | 482 | fn main() { |
483 | if true { | 483 | if true { |
484 | <|>match path.strip_prefix(root_path) { | 484 | $0match path.strip_prefix(root_path) { |
485 | Ok(rel_path) => { | 485 | Ok(rel_path) => { |
486 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | 486 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; |
487 | Some((*id, rel_path)) | 487 | Some((*id, rel_path)) |
@@ -512,7 +512,7 @@ fn main() { | |||
512 | replace_match_with_if_let, | 512 | replace_match_with_if_let, |
513 | r#" | 513 | r#" |
514 | fn main() { | 514 | fn main() { |
515 | <|>match path.strip_prefix(root_path) { | 515 | $0match path.strip_prefix(root_path) { |
516 | Ok(rel_path) => println!("{}", rel_path), | 516 | Ok(rel_path) => println!("{}", rel_path), |
517 | _ => (), | 517 | _ => (), |
518 | } | 518 | } |
diff --git a/crates/assists/src/handlers/replace_impl_trait_with_generic.rs b/crates/assists/src/handlers/replace_impl_trait_with_generic.rs index 6738bc134..ff25b61ea 100644 --- a/crates/assists/src/handlers/replace_impl_trait_with_generic.rs +++ b/crates/assists/src/handlers/replace_impl_trait_with_generic.rs | |||
@@ -7,7 +7,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
7 | // Replaces `impl Trait` function argument with the named generic. | 7 | // Replaces `impl Trait` function argument with the named generic. |
8 | // | 8 | // |
9 | // ``` | 9 | // ``` |
10 | // fn foo(bar: <|>impl Bar) {} | 10 | // fn foo(bar: $0impl Bar) {} |
11 | // ``` | 11 | // ``` |
12 | // -> | 12 | // -> |
13 | // ``` | 13 | // ``` |
@@ -56,7 +56,7 @@ mod tests { | |||
56 | check_assist( | 56 | check_assist( |
57 | replace_impl_trait_with_generic, | 57 | replace_impl_trait_with_generic, |
58 | r#" | 58 | r#" |
59 | fn foo<G>(bar: <|>impl Bar) {} | 59 | fn foo<G>(bar: $0impl Bar) {} |
60 | "#, | 60 | "#, |
61 | r#" | 61 | r#" |
62 | fn foo<G, B: Bar>(bar: B) {} | 62 | fn foo<G, B: Bar>(bar: B) {} |
@@ -69,7 +69,7 @@ mod tests { | |||
69 | check_assist( | 69 | check_assist( |
70 | replace_impl_trait_with_generic, | 70 | replace_impl_trait_with_generic, |
71 | r#" | 71 | r#" |
72 | fn foo(bar: <|>impl Bar) {} | 72 | fn foo(bar: $0impl Bar) {} |
73 | "#, | 73 | "#, |
74 | r#" | 74 | r#" |
75 | fn foo<B: Bar>(bar: B) {} | 75 | fn foo<B: Bar>(bar: B) {} |
@@ -82,7 +82,7 @@ mod tests { | |||
82 | check_assist( | 82 | check_assist( |
83 | replace_impl_trait_with_generic, | 83 | replace_impl_trait_with_generic, |
84 | r#" | 84 | r#" |
85 | fn foo<G>(foo: impl Foo, bar: <|>impl Bar) {} | 85 | fn foo<G>(foo: impl Foo, bar: $0impl Bar) {} |
86 | "#, | 86 | "#, |
87 | r#" | 87 | r#" |
88 | fn foo<G, B: Bar>(foo: impl Foo, bar: B) {} | 88 | fn foo<G, B: Bar>(foo: impl Foo, bar: B) {} |
@@ -95,7 +95,7 @@ mod tests { | |||
95 | check_assist( | 95 | check_assist( |
96 | replace_impl_trait_with_generic, | 96 | replace_impl_trait_with_generic, |
97 | r#" | 97 | r#" |
98 | fn foo<>(bar: <|>impl Bar) {} | 98 | fn foo<>(bar: $0impl Bar) {} |
99 | "#, | 99 | "#, |
100 | r#" | 100 | r#" |
101 | fn foo<B: Bar>(bar: B) {} | 101 | fn foo<B: Bar>(bar: B) {} |
@@ -109,7 +109,7 @@ mod tests { | |||
109 | replace_impl_trait_with_generic, | 109 | replace_impl_trait_with_generic, |
110 | r#" | 110 | r#" |
111 | fn foo< | 111 | fn foo< |
112 | >(bar: <|>impl Bar) {} | 112 | >(bar: $0impl Bar) {} |
113 | "#, | 113 | "#, |
114 | r#" | 114 | r#" |
115 | fn foo<B: Bar | 115 | fn foo<B: Bar |
@@ -124,7 +124,7 @@ mod tests { | |||
124 | check_assist( | 124 | check_assist( |
125 | replace_impl_trait_with_generic, | 125 | replace_impl_trait_with_generic, |
126 | r#" | 126 | r#" |
127 | fn foo<B>(bar: <|>impl Bar) {} | 127 | fn foo<B>(bar: $0impl Bar) {} |
128 | "#, | 128 | "#, |
129 | r#" | 129 | r#" |
130 | fn foo<B, C: Bar>(bar: C) {} | 130 | fn foo<B, C: Bar>(bar: C) {} |
@@ -141,7 +141,7 @@ mod tests { | |||
141 | G: Foo, | 141 | G: Foo, |
142 | F, | 142 | F, |
143 | H, | 143 | H, |
144 | >(bar: <|>impl Bar) {} | 144 | >(bar: $0impl Bar) {} |
145 | "#, | 145 | "#, |
146 | r#" | 146 | r#" |
147 | fn foo< | 147 | fn foo< |
@@ -158,7 +158,7 @@ mod tests { | |||
158 | check_assist( | 158 | check_assist( |
159 | replace_impl_trait_with_generic, | 159 | replace_impl_trait_with_generic, |
160 | r#" | 160 | r#" |
161 | fn foo(bar: <|>impl Foo + Bar) {} | 161 | fn foo(bar: $0impl Foo + Bar) {} |
162 | "#, | 162 | "#, |
163 | r#" | 163 | r#" |
164 | fn foo<F: Foo + Bar>(bar: F) {} | 164 | fn foo<F: Foo + Bar>(bar: F) {} |
diff --git a/crates/assists/src/handlers/replace_let_with_if_let.rs b/crates/assists/src/handlers/replace_let_with_if_let.rs index 5970e283c..5a27ada6b 100644 --- a/crates/assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -20,7 +20,7 @@ use ide_db::ty_filter::TryEnum; | |||
20 | // # enum Option<T> { Some(T), None } | 20 | // # enum Option<T> { Some(T), None } |
21 | // | 21 | // |
22 | // fn main(action: Action) { | 22 | // fn main(action: Action) { |
23 | // <|>let x = compute(); | 23 | // $0let x = compute(); |
24 | // } | 24 | // } |
25 | // | 25 | // |
26 | // fn compute() -> Option<i32> { None } | 26 | // fn compute() -> Option<i32> { None } |
@@ -85,7 +85,7 @@ mod tests { | |||
85 | enum E<T> { X(T), Y(T) } | 85 | enum E<T> { X(T), Y(T) } |
86 | 86 | ||
87 | fn main() { | 87 | fn main() { |
88 | <|>let x = E::X(92); | 88 | $0let x = E::X(92); |
89 | } | 89 | } |
90 | ", | 90 | ", |
91 | r" | 91 | r" |
diff --git a/crates/assists/src/handlers/replace_qualified_name_with_use.rs b/crates/assists/src/handlers/replace_qualified_name_with_use.rs index 8193e45a8..f3bc6cf39 100644 --- a/crates/assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -9,7 +9,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
9 | // Adds a use statement for a given fully-qualified name. | 9 | // Adds a use statement for a given fully-qualified name. |
10 | // | 10 | // |
11 | // ``` | 11 | // ``` |
12 | // fn process(map: std::collections::<|>HashMap<String, String>) {} | 12 | // fn process(map: std::collections::$0HashMap<String, String>) {} |
13 | // ``` | 13 | // ``` |
14 | // -> | 14 | // -> |
15 | // ``` | 15 | // ``` |
@@ -127,7 +127,7 @@ mod tests { | |||
127 | r"use std::fs; | 127 | r"use std::fs; |
128 | 128 | ||
129 | fn main() { | 129 | fn main() { |
130 | std::f<|>s::Path | 130 | std::f$0s::Path |
131 | }", | 131 | }", |
132 | r"use std::fs; | 132 | r"use std::fs; |
133 | 133 | ||
@@ -142,7 +142,7 @@ fn main() { | |||
142 | check_assist( | 142 | check_assist( |
143 | replace_qualified_name_with_use, | 143 | replace_qualified_name_with_use, |
144 | r" | 144 | r" |
145 | std::fmt::Debug<|> | 145 | std::fmt::Debug$0 |
146 | ", | 146 | ", |
147 | r" | 147 | r" |
148 | use std::fmt::Debug; | 148 | use std::fmt::Debug; |
@@ -156,7 +156,7 @@ Debug | |||
156 | check_assist( | 156 | check_assist( |
157 | replace_qualified_name_with_use, | 157 | replace_qualified_name_with_use, |
158 | r" | 158 | r" |
159 | std::fmt::Debug<|> | 159 | std::fmt::Debug$0 |
160 | 160 | ||
161 | fn main() { | 161 | fn main() { |
162 | } | 162 | } |
@@ -180,7 +180,7 @@ fn main() { | |||
180 | fn main() { | 180 | fn main() { |
181 | } | 181 | } |
182 | 182 | ||
183 | std::fmt::Debug<|> | 183 | std::fmt::Debug$0 |
184 | ", | 184 | ", |
185 | r" | 185 | r" |
186 | use std::fmt::Debug; | 186 | use std::fmt::Debug; |
@@ -198,7 +198,7 @@ Debug | |||
198 | check_assist( | 198 | check_assist( |
199 | replace_qualified_name_with_use, | 199 | replace_qualified_name_with_use, |
200 | r" | 200 | r" |
201 | std::fmt<|>::Debug | 201 | std::fmt$0::Debug |
202 | ", | 202 | ", |
203 | r" | 203 | r" |
204 | use std::fmt; | 204 | use std::fmt; |
@@ -215,7 +215,7 @@ fmt::Debug | |||
215 | r" | 215 | r" |
216 | use stdx; | 216 | use stdx; |
217 | 217 | ||
218 | impl std::fmt::Debug<|> for Foo { | 218 | impl std::fmt::Debug$0 for Foo { |
219 | } | 219 | } |
220 | ", | 220 | ", |
221 | r" | 221 | r" |
@@ -234,7 +234,7 @@ impl Debug for Foo { | |||
234 | check_assist( | 234 | check_assist( |
235 | replace_qualified_name_with_use, | 235 | replace_qualified_name_with_use, |
236 | r" | 236 | r" |
237 | impl std::fmt::Debug<|> for Foo { | 237 | impl std::fmt::Debug$0 for Foo { |
238 | } | 238 | } |
239 | ", | 239 | ", |
240 | r" | 240 | r" |
@@ -251,7 +251,7 @@ impl Debug for Foo { | |||
251 | check_assist( | 251 | check_assist( |
252 | replace_qualified_name_with_use, | 252 | replace_qualified_name_with_use, |
253 | r" | 253 | r" |
254 | impl std::fmt::Debug<|> for Foo { | 254 | impl std::fmt::Debug$0 for Foo { |
255 | } | 255 | } |
256 | ", | 256 | ", |
257 | r" | 257 | r" |
@@ -270,7 +270,7 @@ impl Debug for Foo { | |||
270 | r" | 270 | r" |
271 | use std::fmt; | 271 | use std::fmt; |
272 | 272 | ||
273 | impl std::io<|> for Foo { | 273 | impl std::io$0 for Foo { |
274 | } | 274 | } |
275 | ", | 275 | ", |
276 | r" | 276 | r" |
@@ -289,7 +289,7 @@ impl io for Foo { | |||
289 | r" | 289 | r" |
290 | use std::fmt; | 290 | use std::fmt; |
291 | 291 | ||
292 | impl std::fmt::Debug<|> for Foo { | 292 | impl std::fmt::Debug$0 for Foo { |
293 | } | 293 | } |
294 | ", | 294 | ", |
295 | r" | 295 | r" |
@@ -308,7 +308,7 @@ impl Debug for Foo { | |||
308 | r" | 308 | r" |
309 | use std::fmt::Debug; | 309 | use std::fmt::Debug; |
310 | 310 | ||
311 | impl std::fmt<|> for Foo { | 311 | impl std::fmt$0 for Foo { |
312 | } | 312 | } |
313 | ", | 313 | ", |
314 | r" | 314 | r" |
@@ -327,7 +327,7 @@ impl fmt for Foo { | |||
327 | r" | 327 | r" |
328 | use std::fmt::{Debug, nested::{Display}}; | 328 | use std::fmt::{Debug, nested::{Display}}; |
329 | 329 | ||
330 | impl std::fmt::nested<|> for Foo { | 330 | impl std::fmt::nested$0 for Foo { |
331 | } | 331 | } |
332 | ", | 332 | ", |
333 | r" | 333 | r" |
@@ -346,7 +346,7 @@ impl nested for Foo { | |||
346 | r" | 346 | r" |
347 | use std::fmt::{Debug, nested::{self, Display}}; | 347 | use std::fmt::{Debug, nested::{self, Display}}; |
348 | 348 | ||
349 | impl std::fmt::nested<|> for Foo { | 349 | impl std::fmt::nested$0 for Foo { |
350 | } | 350 | } |
351 | ", | 351 | ", |
352 | r" | 352 | r" |
@@ -365,7 +365,7 @@ impl nested for Foo { | |||
365 | r" | 365 | r" |
366 | use std::fmt::{Debug, nested::{Display}}; | 366 | use std::fmt::{Debug, nested::{Display}}; |
367 | 367 | ||
368 | impl std::fmt::nested::Debug<|> for Foo { | 368 | impl std::fmt::nested::Debug$0 for Foo { |
369 | } | 369 | } |
370 | ", | 370 | ", |
371 | r" | 371 | r" |
@@ -384,7 +384,7 @@ impl Debug for Foo { | |||
384 | r" | 384 | r" |
385 | use std::fmt::Debug; | 385 | use std::fmt::Debug; |
386 | 386 | ||
387 | impl std::fmt::nested::Display<|> for Foo { | 387 | impl std::fmt::nested::Display$0 for Foo { |
388 | } | 388 | } |
389 | ", | 389 | ", |
390 | r" | 390 | r" |
@@ -403,7 +403,7 @@ impl Display for Foo { | |||
403 | r" | 403 | r" |
404 | use std::fmt::nested::Debug; | 404 | use std::fmt::nested::Debug; |
405 | 405 | ||
406 | impl std::fmt::Display<|> for Foo { | 406 | impl std::fmt::Display$0 for Foo { |
407 | } | 407 | } |
408 | ", | 408 | ", |
409 | r" | 409 | r" |
@@ -425,7 +425,7 @@ use crate::{ | |||
425 | AssocItem, | 425 | AssocItem, |
426 | }; | 426 | }; |
427 | 427 | ||
428 | fn foo() { crate::ty::lower<|>::trait_env() } | 428 | fn foo() { crate::ty::lower$0::trait_env() } |
429 | ", | 429 | ", |
430 | r" | 430 | r" |
431 | use crate::{AssocItem, ty::{Substs, Ty, lower}}; | 431 | use crate::{AssocItem, ty::{Substs, Ty, lower}}; |
@@ -442,7 +442,7 @@ fn foo() { lower::trait_env() } | |||
442 | r" | 442 | r" |
443 | use std::fmt as foo; | 443 | use std::fmt as foo; |
444 | 444 | ||
445 | impl foo::Debug<|> for Foo { | 445 | impl foo::Debug$0 for Foo { |
446 | } | 446 | } |
447 | ", | 447 | ", |
448 | r" | 448 | r" |
@@ -462,7 +462,7 @@ impl Debug for Foo { | |||
462 | check_assist_not_applicable( | 462 | check_assist_not_applicable( |
463 | replace_qualified_name_with_use, | 463 | replace_qualified_name_with_use, |
464 | r" | 464 | r" |
465 | impl foo<|> for Foo { | 465 | impl foo$0 for Foo { |
466 | } | 466 | } |
467 | ", | 467 | ", |
468 | ); | 468 | ); |
@@ -473,7 +473,7 @@ impl foo<|> for Foo { | |||
473 | check_assist_not_applicable( | 473 | check_assist_not_applicable( |
474 | replace_qualified_name_with_use, | 474 | replace_qualified_name_with_use, |
475 | r" | 475 | r" |
476 | use std::fmt<|>; | 476 | use std::fmt$0; |
477 | ", | 477 | ", |
478 | ); | 478 | ); |
479 | } | 479 | } |
@@ -485,7 +485,7 @@ use std::fmt<|>; | |||
485 | r" | 485 | r" |
486 | mod foo { | 486 | mod foo { |
487 | mod bar { | 487 | mod bar { |
488 | std::fmt::Debug<|> | 488 | std::fmt::Debug$0 |
489 | } | 489 | } |
490 | } | 490 | } |
491 | ", | 491 | ", |
@@ -509,7 +509,7 @@ mod foo { | |||
509 | #![allow(dead_code)] | 509 | #![allow(dead_code)] |
510 | 510 | ||
511 | fn main() { | 511 | fn main() { |
512 | std::fmt::Debug<|> | 512 | std::fmt::Debug$0 |
513 | } | 513 | } |
514 | ", | 514 | ", |
515 | r" | 515 | r" |
@@ -530,7 +530,7 @@ fn main() { | |||
530 | replace_qualified_name_with_use, | 530 | replace_qualified_name_with_use, |
531 | r" | 531 | r" |
532 | fn main() { | 532 | fn main() { |
533 | std::fmt::Debug<|>; | 533 | std::fmt::Debug$0; |
534 | let x: std::fmt::Debug = std::fmt::Debug; | 534 | let x: std::fmt::Debug = std::fmt::Debug; |
535 | } | 535 | } |
536 | ", | 536 | ", |
@@ -552,7 +552,7 @@ fn main() { | |||
552 | r" | 552 | r" |
553 | mod m { | 553 | mod m { |
554 | fn f() { | 554 | fn f() { |
555 | std::fmt::Debug<|>; | 555 | std::fmt::Debug$0; |
556 | let x: std::fmt::Debug = std::fmt::Debug; | 556 | let x: std::fmt::Debug = std::fmt::Debug; |
557 | } | 557 | } |
558 | fn g() { | 558 | fn g() { |
@@ -590,7 +590,7 @@ fn f() { | |||
590 | replace_qualified_name_with_use, | 590 | replace_qualified_name_with_use, |
591 | r" | 591 | r" |
592 | fn main() { | 592 | fn main() { |
593 | std::fmt::Debug<|>; | 593 | std::fmt::Debug$0; |
594 | } | 594 | } |
595 | 595 | ||
596 | mod sub { | 596 | mod sub { |
@@ -623,7 +623,7 @@ mod sub { | |||
623 | use std::fmt::Display; | 623 | use std::fmt::Display; |
624 | 624 | ||
625 | fn main() { | 625 | fn main() { |
626 | std::fmt<|>; | 626 | std::fmt$0; |
627 | } | 627 | } |
628 | ", | 628 | ", |
629 | r" | 629 | r" |
@@ -643,7 +643,7 @@ fn main() { | |||
643 | r" | 643 | r" |
644 | pub use std::fmt; | 644 | pub use std::fmt; |
645 | 645 | ||
646 | impl std::io<|> for Foo { | 646 | impl std::io$0 for Foo { |
647 | } | 647 | } |
648 | ", | 648 | ", |
649 | r" | 649 | r" |
@@ -663,7 +663,7 @@ impl io for Foo { | |||
663 | r" | 663 | r" |
664 | pub(crate) use std::fmt; | 664 | pub(crate) use std::fmt; |
665 | 665 | ||
666 | impl std::io<|> for Foo { | 666 | impl std::io$0 for Foo { |
667 | } | 667 | } |
668 | ", | 668 | ", |
669 | r" | 669 | r" |
diff --git a/crates/assists/src/handlers/replace_string_with_char.rs b/crates/assists/src/handlers/replace_string_with_char.rs index b4b898846..317318c24 100644 --- a/crates/assists/src/handlers/replace_string_with_char.rs +++ b/crates/assists/src/handlers/replace_string_with_char.rs | |||
@@ -8,7 +8,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
8 | // | 8 | // |
9 | // ``` | 9 | // ``` |
10 | // fn main() { | 10 | // fn main() { |
11 | // find("{<|>"); | 11 | // find("{$0"); |
12 | // } | 12 | // } |
13 | // ``` | 13 | // ``` |
14 | // -> | 14 | // -> |
@@ -48,7 +48,7 @@ mod tests { | |||
48 | replace_string_with_char, | 48 | replace_string_with_char, |
49 | r#" | 49 | r#" |
50 | fn f() { | 50 | fn f() { |
51 | let s = "<|>c"; | 51 | let s = "$0c"; |
52 | } | 52 | } |
53 | "#, | 53 | "#, |
54 | r#""c""#, | 54 | r#""c""#, |
@@ -61,7 +61,7 @@ mod tests { | |||
61 | replace_string_with_char, | 61 | replace_string_with_char, |
62 | r#" | 62 | r#" |
63 | fn f() { | 63 | fn f() { |
64 | let s = "<|>c"; | 64 | let s = "$0c"; |
65 | } | 65 | } |
66 | "#, | 66 | "#, |
67 | r##" | 67 | r##" |
@@ -78,7 +78,7 @@ mod tests { | |||
78 | replace_string_with_char, | 78 | replace_string_with_char, |
79 | r#" | 79 | r#" |
80 | fn f() { | 80 | fn f() { |
81 | let s = "<|>😀"; | 81 | let s = "$0😀"; |
82 | } | 82 | } |
83 | "#, | 83 | "#, |
84 | r##" | 84 | r##" |
@@ -95,7 +95,7 @@ mod tests { | |||
95 | replace_string_with_char, | 95 | replace_string_with_char, |
96 | r#" | 96 | r#" |
97 | fn f() { | 97 | fn f() { |
98 | let s = "<|>test"; | 98 | let s = "$0test"; |
99 | } | 99 | } |
100 | "#, | 100 | "#, |
101 | ) | 101 | ) |
@@ -107,7 +107,7 @@ mod tests { | |||
107 | replace_string_with_char, | 107 | replace_string_with_char, |
108 | r#" | 108 | r#" |
109 | fn f() { | 109 | fn f() { |
110 | format!(<|>"x", 92) | 110 | format!($0"x", 92) |
111 | } | 111 | } |
112 | "#, | 112 | "#, |
113 | r##" | 113 | r##" |
@@ -124,7 +124,7 @@ mod tests { | |||
124 | replace_string_with_char, | 124 | replace_string_with_char, |
125 | r#" | 125 | r#" |
126 | fn f() { | 126 | fn f() { |
127 | find(<|>"x"); | 127 | find($0"x"); |
128 | } | 128 | } |
129 | "#, | 129 | "#, |
130 | r##" | 130 | r##" |
diff --git a/crates/assists/src/handlers/replace_unwrap_with_match.rs b/crates/assists/src/handlers/replace_unwrap_with_match.rs index f547066f0..a986a6ae8 100644 --- a/crates/assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -23,7 +23,7 @@ use ide_db::ty_filter::TryEnum; | |||
23 | // enum Result<T, E> { Ok(T), Err(E) } | 23 | // enum Result<T, E> { Ok(T), Err(E) } |
24 | // fn main() { | 24 | // fn main() { |
25 | // let x: Result<i32, i32> = Result::Ok(92); | 25 | // let x: Result<i32, i32> = Result::Ok(92); |
26 | // let y = x.<|>unwrap(); | 26 | // let y = x.$0unwrap(); |
27 | // } | 27 | // } |
28 | // ``` | 28 | // ``` |
29 | // -> | 29 | // -> |
@@ -101,7 +101,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
101 | fn i<T>(a: T) -> T { a } | 101 | fn i<T>(a: T) -> T { a } |
102 | fn main() { | 102 | fn main() { |
103 | let x: Result<i32, i32> = Result::Ok(92); | 103 | let x: Result<i32, i32> = Result::Ok(92); |
104 | let y = i(x).<|>unwrap(); | 104 | let y = i(x).$0unwrap(); |
105 | } | 105 | } |
106 | ", | 106 | ", |
107 | r" | 107 | r" |
@@ -127,7 +127,7 @@ enum Option<T> { Some(T), None } | |||
127 | fn i<T>(a: T) -> T { a } | 127 | fn i<T>(a: T) -> T { a } |
128 | fn main() { | 128 | fn main() { |
129 | let x = Option::Some(92); | 129 | let x = Option::Some(92); |
130 | let y = i(x).<|>unwrap(); | 130 | let y = i(x).$0unwrap(); |
131 | } | 131 | } |
132 | ", | 132 | ", |
133 | r" | 133 | r" |
@@ -153,7 +153,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
153 | fn i<T>(a: T) -> T { a } | 153 | fn i<T>(a: T) -> T { a } |
154 | fn main() { | 154 | fn main() { |
155 | let x: Result<i32, i32> = Result::Ok(92); | 155 | let x: Result<i32, i32> = Result::Ok(92); |
156 | let y = i(x).<|>unwrap().count_zeroes(); | 156 | let y = i(x).$0unwrap().count_zeroes(); |
157 | } | 157 | } |
158 | ", | 158 | ", |
159 | r" | 159 | r" |
@@ -179,7 +179,7 @@ enum Option<T> { Some(T), None } | |||
179 | fn i<T>(a: T) -> T { a } | 179 | fn i<T>(a: T) -> T { a } |
180 | fn main() { | 180 | fn main() { |
181 | let x = Option::Some(92); | 181 | let x = Option::Some(92); |
182 | let y = i(x).<|>unwrap(); | 182 | let y = i(x).$0unwrap(); |
183 | } | 183 | } |
184 | ", | 184 | ", |
185 | r"i(x).unwrap()", | 185 | r"i(x).unwrap()", |
diff --git a/crates/assists/src/handlers/split_import.rs b/crates/assists/src/handlers/split_import.rs index ef1f6b8a1..9319a4267 100644 --- a/crates/assists/src/handlers/split_import.rs +++ b/crates/assists/src/handlers/split_import.rs | |||
@@ -9,7 +9,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
9 | // Wraps the tail of import into braces. | 9 | // Wraps the tail of import into braces. |
10 | // | 10 | // |
11 | // ``` | 11 | // ``` |
12 | // use std::<|>collections::HashMap; | 12 | // use std::$0collections::HashMap; |
13 | // ``` | 13 | // ``` |
14 | // -> | 14 | // -> |
15 | // ``` | 15 | // ``` |
@@ -43,7 +43,7 @@ mod tests { | |||
43 | fn test_split_import() { | 43 | fn test_split_import() { |
44 | check_assist( | 44 | check_assist( |
45 | split_import, | 45 | split_import, |
46 | "use crate::<|>db::RootDatabase;", | 46 | "use crate::$0db::RootDatabase;", |
47 | "use crate::{db::RootDatabase};", | 47 | "use crate::{db::RootDatabase};", |
48 | ) | 48 | ) |
49 | } | 49 | } |
@@ -52,19 +52,19 @@ mod tests { | |||
52 | fn split_import_works_with_trees() { | 52 | fn split_import_works_with_trees() { |
53 | check_assist( | 53 | check_assist( |
54 | split_import, | 54 | split_import, |
55 | "use crate:<|>:db::{RootDatabase, FileSymbol}", | 55 | "use crate:$0:db::{RootDatabase, FileSymbol}", |
56 | "use crate::{db::{RootDatabase, FileSymbol}}", | 56 | "use crate::{db::{RootDatabase, FileSymbol}}", |
57 | ) | 57 | ) |
58 | } | 58 | } |
59 | 59 | ||
60 | #[test] | 60 | #[test] |
61 | fn split_import_target() { | 61 | fn split_import_target() { |
62 | check_assist_target(split_import, "use crate::<|>db::{RootDatabase, FileSymbol}", "::"); | 62 | check_assist_target(split_import, "use crate::$0db::{RootDatabase, FileSymbol}", "::"); |
63 | } | 63 | } |
64 | 64 | ||
65 | #[test] | 65 | #[test] |
66 | fn issue4044() { | 66 | fn issue4044() { |
67 | check_assist_not_applicable(split_import, "use crate::<|>:::self;") | 67 | check_assist_not_applicable(split_import, "use crate::$0:::self;") |
68 | } | 68 | } |
69 | 69 | ||
70 | #[test] | 70 | #[test] |
@@ -72,7 +72,7 @@ mod tests { | |||
72 | check_assist_not_applicable( | 72 | check_assist_not_applicable( |
73 | split_import, | 73 | split_import, |
74 | r" | 74 | r" |
75 | use std::<|> | 75 | use std::$0 |
76 | fn main() {}", | 76 | fn main() {}", |
77 | ); | 77 | ); |
78 | } | 78 | } |
diff --git a/crates/assists/src/handlers/toggle_ignore.rs b/crates/assists/src/handlers/toggle_ignore.rs index 14b420421..33e12a7d0 100644 --- a/crates/assists/src/handlers/toggle_ignore.rs +++ b/crates/assists/src/handlers/toggle_ignore.rs | |||
@@ -10,7 +10,7 @@ use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, | |||
10 | // Adds `#[ignore]` attribute to the test. | 10 | // Adds `#[ignore]` attribute to the test. |
11 | // | 11 | // |
12 | // ``` | 12 | // ``` |
13 | // <|>#[test] | 13 | // $0#[test] |
14 | // fn arithmetics { | 14 | // fn arithmetics { |
15 | // assert_eq!(2 + 2, 5); | 15 | // assert_eq!(2 + 2, 5); |
16 | // } | 16 | // } |
@@ -69,7 +69,7 @@ mod tests { | |||
69 | check_assist( | 69 | check_assist( |
70 | toggle_ignore, | 70 | toggle_ignore, |
71 | r#" | 71 | r#" |
72 | #[test<|>] | 72 | #[test$0] |
73 | fn test() {} | 73 | fn test() {} |
74 | "#, | 74 | "#, |
75 | r#" | 75 | r#" |
@@ -85,7 +85,7 @@ mod tests { | |||
85 | check_assist( | 85 | check_assist( |
86 | toggle_ignore, | 86 | toggle_ignore, |
87 | r#" | 87 | r#" |
88 | #[test<|>] | 88 | #[test$0] |
89 | #[ignore] | 89 | #[ignore] |
90 | fn test() {} | 90 | fn test() {} |
91 | "#, | 91 | "#, |
diff --git a/crates/assists/src/handlers/unwrap_block.rs b/crates/assists/src/handlers/unwrap_block.rs index 676db7137..ed6f6177d 100644 --- a/crates/assists/src/handlers/unwrap_block.rs +++ b/crates/assists/src/handlers/unwrap_block.rs | |||
@@ -14,7 +14,7 @@ use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, As | |||
14 | // | 14 | // |
15 | // ``` | 15 | // ``` |
16 | // fn foo() { | 16 | // fn foo() { |
17 | // if true {<|> | 17 | // if true {$0 |
18 | // println!("foo"); | 18 | // println!("foo"); |
19 | // } | 19 | // } |
20 | // } | 20 | // } |
@@ -124,7 +124,7 @@ mod tests { | |||
124 | unwrap_block, | 124 | unwrap_block, |
125 | r#" | 125 | r#" |
126 | fn main() { | 126 | fn main() { |
127 | <|>{ | 127 | $0{ |
128 | 92 | 128 | 92 |
129 | } | 129 | } |
130 | } | 130 | } |
@@ -143,7 +143,7 @@ fn main() { | |||
143 | unwrap_block, | 143 | unwrap_block, |
144 | r#" | 144 | r#" |
145 | fn main() { | 145 | fn main() { |
146 | <|>{ | 146 | $0{ |
147 | 92; | 147 | 92; |
148 | } | 148 | } |
149 | () | 149 | () |
@@ -161,7 +161,7 @@ fn main() { | |||
161 | unwrap_block, | 161 | unwrap_block, |
162 | r#" | 162 | r#" |
163 | fn main() { | 163 | fn main() { |
164 | <|>{ | 164 | $0{ |
165 | 92 | 165 | 92 |
166 | } | 166 | } |
167 | () | 167 | () |
@@ -183,7 +183,7 @@ fn main() { | |||
183 | r#" | 183 | r#" |
184 | fn main() { | 184 | fn main() { |
185 | bar(); | 185 | bar(); |
186 | if true {<|> | 186 | if true {$0 |
187 | foo(); | 187 | foo(); |
188 | 188 | ||
189 | //comment | 189 | //comment |
@@ -217,7 +217,7 @@ fn main() { | |||
217 | 217 | ||
218 | //comment | 218 | //comment |
219 | bar(); | 219 | bar(); |
220 | } else {<|> | 220 | } else {$0 |
221 | println!("bar"); | 221 | println!("bar"); |
222 | } | 222 | } |
223 | } | 223 | } |
@@ -249,7 +249,7 @@ fn main() { | |||
249 | 249 | ||
250 | //comment | 250 | //comment |
251 | //bar(); | 251 | //bar(); |
252 | } else if false {<|> | 252 | } else if false {$0 |
253 | println!("bar"); | 253 | println!("bar"); |
254 | } else { | 254 | } else { |
255 | println!("foo"); | 255 | println!("foo"); |
@@ -285,7 +285,7 @@ fn main() { | |||
285 | //bar(); | 285 | //bar(); |
286 | } else if false { | 286 | } else if false { |
287 | println!("bar"); | 287 | println!("bar"); |
288 | } else if true {<|> | 288 | } else if true {$0 |
289 | println!("foo"); | 289 | println!("foo"); |
290 | } | 290 | } |
291 | } | 291 | } |
@@ -323,7 +323,7 @@ fn main() { | |||
323 | println!("bar"); | 323 | println!("bar"); |
324 | } else if true { | 324 | } else if true { |
325 | println!("foo"); | 325 | println!("foo"); |
326 | } else {<|> | 326 | } else {$0 |
327 | println!("else"); | 327 | println!("else"); |
328 | } | 328 | } |
329 | } | 329 | } |
@@ -361,7 +361,7 @@ fn main() { | |||
361 | //bar(); | 361 | //bar(); |
362 | } else if false { | 362 | } else if false { |
363 | println!("bar"); | 363 | println!("bar"); |
364 | } else if true {<|> | 364 | } else if true {$0 |
365 | println!("foo"); | 365 | println!("foo"); |
366 | } else { | 366 | } else { |
367 | println!("else"); | 367 | println!("else"); |
@@ -391,7 +391,7 @@ fn main() { | |||
391 | unwrap_block, | 391 | unwrap_block, |
392 | r#" | 392 | r#" |
393 | fn main() { | 393 | fn main() { |
394 | bar();<|> | 394 | bar();$0 |
395 | if true { | 395 | if true { |
396 | foo(); | 396 | foo(); |
397 | 397 | ||
@@ -411,7 +411,7 @@ fn main() { | |||
411 | unwrap_block, | 411 | unwrap_block, |
412 | r#" | 412 | r#" |
413 | fn main() { | 413 | fn main() { |
414 | for i in 0..5 {<|> | 414 | for i in 0..5 {$0 |
415 | if true { | 415 | if true { |
416 | foo(); | 416 | foo(); |
417 | 417 | ||
@@ -445,7 +445,7 @@ fn main() { | |||
445 | r#" | 445 | r#" |
446 | fn main() { | 446 | fn main() { |
447 | for i in 0..5 { | 447 | for i in 0..5 { |
448 | if true {<|> | 448 | if true {$0 |
449 | foo(); | 449 | foo(); |
450 | 450 | ||
451 | //comment | 451 | //comment |
@@ -475,7 +475,7 @@ fn main() { | |||
475 | unwrap_block, | 475 | unwrap_block, |
476 | r#" | 476 | r#" |
477 | fn main() { | 477 | fn main() { |
478 | loop {<|> | 478 | loop {$0 |
479 | if true { | 479 | if true { |
480 | foo(); | 480 | foo(); |
481 | 481 | ||
@@ -508,7 +508,7 @@ fn main() { | |||
508 | unwrap_block, | 508 | unwrap_block, |
509 | r#" | 509 | r#" |
510 | fn main() { | 510 | fn main() { |
511 | while true {<|> | 511 | while true {$0 |
512 | if true { | 512 | if true { |
513 | foo(); | 513 | foo(); |
514 | 514 | ||
@@ -542,7 +542,7 @@ fn main() { | |||
542 | r#" | 542 | r#" |
543 | fn main() { | 543 | fn main() { |
544 | match rel_path { | 544 | match rel_path { |
545 | Ok(rel_path) => {<|> | 545 | Ok(rel_path) => {$0 |
546 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | 546 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; |
547 | Some((*id, rel_path)) | 547 | Some((*id, rel_path)) |
548 | } | 548 | } |
@@ -567,7 +567,7 @@ fn main() { | |||
567 | fn main() { | 567 | fn main() { |
568 | while true { | 568 | while true { |
569 | if true { | 569 | if true { |
570 | foo();<|> | 570 | foo();$0 |
571 | 571 | ||
572 | //comment | 572 | //comment |
573 | bar(); | 573 | bar(); |
diff --git a/crates/assists/src/handlers/wrap_return_type_in_result.rs b/crates/assists/src/handlers/wrap_return_type_in_result.rs index 59e5debb1..fec16fc49 100644 --- a/crates/assists/src/handlers/wrap_return_type_in_result.rs +++ b/crates/assists/src/handlers/wrap_return_type_in_result.rs | |||
@@ -13,7 +13,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
13 | // Wrap the function's return type into Result. | 13 | // Wrap the function's return type into Result. |
14 | // | 14 | // |
15 | // ``` | 15 | // ``` |
16 | // fn foo() -> i32<|> { 42i32 } | 16 | // fn foo() -> i32$0 { 42i32 } |
17 | // ``` | 17 | // ``` |
18 | // -> | 18 | // -> |
19 | // ``` | 19 | // ``` |
@@ -98,7 +98,7 @@ impl TailReturnCollector { | |||
98 | } | 98 | } |
99 | 99 | ||
100 | // Browse tail expressions for each block | 100 | // Browse tail expressions for each block |
101 | if let Some(expr) = block_expr.expr() { | 101 | if let Some(expr) = block_expr.tail_expr() { |
102 | if let Some(last_exprs) = get_tail_expr_from_block(&expr) { | 102 | if let Some(last_exprs) = get_tail_expr_from_block(&expr) { |
103 | for last_expr in last_exprs { | 103 | for last_expr in last_exprs { |
104 | let last_expr = match last_expr { | 104 | let last_expr = match last_expr { |
@@ -170,7 +170,7 @@ impl TailReturnCollector { | |||
170 | } | 170 | } |
171 | 171 | ||
172 | fn collect_tail_exprs(&mut self, block: &BlockExpr) { | 172 | fn collect_tail_exprs(&mut self, block: &BlockExpr) { |
173 | if let Some(expr) = block.expr() { | 173 | if let Some(expr) = block.tail_expr() { |
174 | self.handle_exprs(&expr, true); | 174 | self.handle_exprs(&expr, true); |
175 | self.fetch_tail_exprs(&expr); | 175 | self.fetch_tail_exprs(&expr); |
176 | } | 176 | } |
@@ -206,7 +206,7 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> { | |||
206 | Expr::IfExpr(if_expr) => { | 206 | Expr::IfExpr(if_expr) => { |
207 | let mut nodes = vec![]; | 207 | let mut nodes = vec![]; |
208 | for block in if_expr.blocks() { | 208 | for block in if_expr.blocks() { |
209 | if let Some(block_expr) = block.expr() { | 209 | if let Some(block_expr) = block.tail_expr() { |
210 | if let Some(tail_exprs) = get_tail_expr_from_block(&block_expr) { | 210 | if let Some(tail_exprs) = get_tail_expr_from_block(&block_expr) { |
211 | nodes.extend(tail_exprs); | 211 | nodes.extend(tail_exprs); |
212 | } | 212 | } |
@@ -228,7 +228,7 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> { | |||
228 | while_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)]) | 228 | while_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)]) |
229 | } | 229 | } |
230 | Expr::BlockExpr(block_expr) => { | 230 | Expr::BlockExpr(block_expr) => { |
231 | block_expr.expr().map(|lc| vec![NodeType::Node(lc.syntax().clone())]) | 231 | block_expr.tail_expr().map(|lc| vec![NodeType::Node(lc.syntax().clone())]) |
232 | } | 232 | } |
233 | Expr::MatchExpr(match_expr) => { | 233 | Expr::MatchExpr(match_expr) => { |
234 | let arm_list = match_expr.match_arm_list()?; | 234 | let arm_list = match_expr.match_arm_list()?; |
@@ -282,7 +282,7 @@ mod tests { | |||
282 | check_assist( | 282 | check_assist( |
283 | wrap_return_type_in_result, | 283 | wrap_return_type_in_result, |
284 | r#" | 284 | r#" |
285 | fn foo() -> i3<|>2 { | 285 | fn foo() -> i3$02 { |
286 | let test = "test"; | 286 | let test = "test"; |
287 | return 42i32; | 287 | return 42i32; |
288 | } | 288 | } |
@@ -302,7 +302,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
302 | wrap_return_type_in_result, | 302 | wrap_return_type_in_result, |
303 | r#" | 303 | r#" |
304 | fn foo() { | 304 | fn foo() { |
305 | || -> i32<|> { | 305 | || -> i32$0 { |
306 | let test = "test"; | 306 | let test = "test"; |
307 | return 42i32; | 307 | return 42i32; |
308 | }; | 308 | }; |
@@ -325,7 +325,7 @@ fn foo() { | |||
325 | wrap_return_type_in_result, | 325 | wrap_return_type_in_result, |
326 | r#" | 326 | r#" |
327 | fn foo() -> i32 { | 327 | fn foo() -> i32 { |
328 | let test = "test";<|> | 328 | let test = "test";$0 |
329 | return 42i32; | 329 | return 42i32; |
330 | } | 330 | } |
331 | "#, | 331 | "#, |
@@ -339,7 +339,7 @@ fn foo() -> i32 { | |||
339 | r#" | 339 | r#" |
340 | fn foo() { | 340 | fn foo() { |
341 | || -> i32 { | 341 | || -> i32 { |
342 | let test = "test";<|> | 342 | let test = "test";$0 |
343 | return 42i32; | 343 | return 42i32; |
344 | }; | 344 | }; |
345 | } | 345 | } |
@@ -349,7 +349,7 @@ fn foo() { | |||
349 | 349 | ||
350 | #[test] | 350 | #[test] |
351 | fn wrap_return_type_in_result_closure_non_block() { | 351 | fn wrap_return_type_in_result_closure_non_block() { |
352 | check_assist_not_applicable(wrap_return_type_in_result, r#"fn foo() { || -> i<|>32 3; }"#); | 352 | check_assist_not_applicable(wrap_return_type_in_result, r#"fn foo() { || -> i$032 3; }"#); |
353 | } | 353 | } |
354 | 354 | ||
355 | #[test] | 355 | #[test] |
@@ -357,7 +357,7 @@ fn foo() { | |||
357 | check_assist_not_applicable( | 357 | check_assist_not_applicable( |
358 | wrap_return_type_in_result, | 358 | wrap_return_type_in_result, |
359 | r#" | 359 | r#" |
360 | fn foo() -> std::result::Result<i32<|>, String> { | 360 | fn foo() -> std::result::Result<i32$0, String> { |
361 | let test = "test"; | 361 | let test = "test"; |
362 | return 42i32; | 362 | return 42i32; |
363 | } | 363 | } |
@@ -371,7 +371,7 @@ fn foo() -> std::result::Result<i32<|>, String> { | |||
371 | check_assist_not_applicable( | 371 | check_assist_not_applicable( |
372 | wrap_return_type_in_result, | 372 | wrap_return_type_in_result, |
373 | r#" | 373 | r#" |
374 | fn foo() -> Result<i32<|>, String> { | 374 | fn foo() -> Result<i32$0, String> { |
375 | let test = "test"; | 375 | let test = "test"; |
376 | return 42i32; | 376 | return 42i32; |
377 | } | 377 | } |
@@ -385,7 +385,7 @@ fn foo() -> Result<i32<|>, String> { | |||
385 | wrap_return_type_in_result, | 385 | wrap_return_type_in_result, |
386 | r#" | 386 | r#" |
387 | fn foo() { | 387 | fn foo() { |
388 | || -> Result<i32<|>, String> { | 388 | || -> Result<i32$0, String> { |
389 | let test = "test"; | 389 | let test = "test"; |
390 | return 42i32; | 390 | return 42i32; |
391 | }; | 391 | }; |
@@ -399,7 +399,7 @@ fn foo() { | |||
399 | check_assist( | 399 | check_assist( |
400 | wrap_return_type_in_result, | 400 | wrap_return_type_in_result, |
401 | r#" | 401 | r#" |
402 | fn foo() -> <|>i32 { | 402 | fn foo() -> $0i32 { |
403 | let test = "test"; | 403 | let test = "test"; |
404 | return 42i32; | 404 | return 42i32; |
405 | } | 405 | } |
@@ -418,7 +418,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
418 | check_assist( | 418 | check_assist( |
419 | wrap_return_type_in_result, | 419 | wrap_return_type_in_result, |
420 | r#" | 420 | r#" |
421 | fn foo() -><|> i32 { | 421 | fn foo() ->$0 i32 { |
422 | let test = "test"; | 422 | let test = "test"; |
423 | 42i32 | 423 | 42i32 |
424 | } | 424 | } |
@@ -438,7 +438,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
438 | wrap_return_type_in_result, | 438 | wrap_return_type_in_result, |
439 | r#" | 439 | r#" |
440 | fn foo() { | 440 | fn foo() { |
441 | || -><|> i32 { | 441 | || ->$0 i32 { |
442 | let test = "test"; | 442 | let test = "test"; |
443 | 42i32 | 443 | 42i32 |
444 | }; | 444 | }; |
@@ -459,7 +459,7 @@ fn foo() { | |||
459 | fn wrap_return_type_in_result_simple_with_tail_only() { | 459 | fn wrap_return_type_in_result_simple_with_tail_only() { |
460 | check_assist( | 460 | check_assist( |
461 | wrap_return_type_in_result, | 461 | wrap_return_type_in_result, |
462 | r#"fn foo() -> i32<|> { 42i32 }"#, | 462 | r#"fn foo() -> i32$0 { 42i32 }"#, |
463 | r#"fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }"#, | 463 | r#"fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }"#, |
464 | ); | 464 | ); |
465 | } | 465 | } |
@@ -469,7 +469,7 @@ fn foo() { | |||
469 | check_assist( | 469 | check_assist( |
470 | wrap_return_type_in_result, | 470 | wrap_return_type_in_result, |
471 | r#" | 471 | r#" |
472 | fn foo() -> i32<|> { | 472 | fn foo() -> i32$0 { |
473 | if true { | 473 | if true { |
474 | 42i32 | 474 | 42i32 |
475 | } else { | 475 | } else { |
@@ -495,7 +495,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
495 | wrap_return_type_in_result, | 495 | wrap_return_type_in_result, |
496 | r#" | 496 | r#" |
497 | fn foo() { | 497 | fn foo() { |
498 | || -> i32<|> { | 498 | || -> i32$0 { |
499 | if true { | 499 | if true { |
500 | 42i32 | 500 | 42i32 |
501 | } else { | 501 | } else { |
@@ -523,7 +523,7 @@ fn foo() { | |||
523 | check_assist( | 523 | check_assist( |
524 | wrap_return_type_in_result, | 524 | wrap_return_type_in_result, |
525 | r#" | 525 | r#" |
526 | fn foo() -> i32<|> { | 526 | fn foo() -> i32$0 { |
527 | if true { | 527 | if true { |
528 | if false { | 528 | if false { |
529 | 1 | 529 | 1 |
@@ -556,7 +556,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
556 | check_assist( | 556 | check_assist( |
557 | wrap_return_type_in_result, | 557 | wrap_return_type_in_result, |
558 | r#" | 558 | r#" |
559 | async fn foo() -> i<|>32 { | 559 | async fn foo() -> i$032 { |
560 | if true { | 560 | if true { |
561 | if false { | 561 | if false { |
562 | 1.await | 562 | 1.await |
@@ -588,7 +588,7 @@ async fn foo() -> Result<i32, ${0:_}> { | |||
588 | fn wrap_return_type_in_result_simple_with_array() { | 588 | fn wrap_return_type_in_result_simple_with_array() { |
589 | check_assist( | 589 | check_assist( |
590 | wrap_return_type_in_result, | 590 | wrap_return_type_in_result, |
591 | r#"fn foo() -> [i32;<|> 3] { [1, 2, 3] }"#, | 591 | r#"fn foo() -> [i32;$0 3] { [1, 2, 3] }"#, |
592 | r#"fn foo() -> Result<[i32; 3], ${0:_}> { Ok([1, 2, 3]) }"#, | 592 | r#"fn foo() -> Result<[i32; 3], ${0:_}> { Ok([1, 2, 3]) }"#, |
593 | ); | 593 | ); |
594 | } | 594 | } |
@@ -598,7 +598,7 @@ async fn foo() -> Result<i32, ${0:_}> { | |||
598 | check_assist( | 598 | check_assist( |
599 | wrap_return_type_in_result, | 599 | wrap_return_type_in_result, |
600 | r#" | 600 | r#" |
601 | fn foo() -<|>> i32 { | 601 | fn foo() -$0> i32 { |
602 | if true { | 602 | if true { |
603 | if false { | 603 | if false { |
604 | 1 as i32 | 604 | 1 as i32 |
@@ -631,7 +631,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
631 | check_assist( | 631 | check_assist( |
632 | wrap_return_type_in_result, | 632 | wrap_return_type_in_result, |
633 | r#" | 633 | r#" |
634 | fn foo() -> i32<|> { | 634 | fn foo() -> i32$0 { |
635 | let my_var = 5; | 635 | let my_var = 5; |
636 | match my_var { | 636 | match my_var { |
637 | 5 => 42i32, | 637 | 5 => 42i32, |
@@ -656,7 +656,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
656 | check_assist( | 656 | check_assist( |
657 | wrap_return_type_in_result, | 657 | wrap_return_type_in_result, |
658 | r#" | 658 | r#" |
659 | fn foo() -> i32<|> { | 659 | fn foo() -> i32$0 { |
660 | let my_var = 5; | 660 | let my_var = 5; |
661 | loop { | 661 | loop { |
662 | println!("test"); | 662 | println!("test"); |
@@ -683,7 +683,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
683 | check_assist( | 683 | check_assist( |
684 | wrap_return_type_in_result, | 684 | wrap_return_type_in_result, |
685 | r#" | 685 | r#" |
686 | fn foo() -> i32<|> { | 686 | fn foo() -> i32$0 { |
687 | let my_var = let x = loop { | 687 | let my_var = let x = loop { |
688 | break 1; | 688 | break 1; |
689 | }; | 689 | }; |
@@ -706,7 +706,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
706 | check_assist( | 706 | check_assist( |
707 | wrap_return_type_in_result, | 707 | wrap_return_type_in_result, |
708 | r#" | 708 | r#" |
709 | fn foo() -> i32<|> { | 709 | fn foo() -> i32$0 { |
710 | let my_var = 5; | 710 | let my_var = 5; |
711 | let res = match my_var { | 711 | let res = match my_var { |
712 | 5 => 42i32, | 712 | 5 => 42i32, |
@@ -730,7 +730,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
730 | check_assist( | 730 | check_assist( |
731 | wrap_return_type_in_result, | 731 | wrap_return_type_in_result, |
732 | r#" | 732 | r#" |
733 | fn foo() -> i32<|> { | 733 | fn foo() -> i32$0 { |
734 | let my_var = 5; | 734 | let my_var = 5; |
735 | let res = if my_var == 5 { | 735 | let res = if my_var == 5 { |
736 | 42i32 | 736 | 42i32 |
@@ -759,7 +759,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
759 | check_assist( | 759 | check_assist( |
760 | wrap_return_type_in_result, | 760 | wrap_return_type_in_result, |
761 | r#" | 761 | r#" |
762 | fn foo() -> i32<|> { | 762 | fn foo() -> i32$0 { |
763 | let my_var = 5; | 763 | let my_var = 5; |
764 | match my_var { | 764 | match my_var { |
765 | 5 => { | 765 | 5 => { |
@@ -808,7 +808,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
808 | check_assist( | 808 | check_assist( |
809 | wrap_return_type_in_result, | 809 | wrap_return_type_in_result, |
810 | r#" | 810 | r#" |
811 | fn foo() -> i<|>32 { | 811 | fn foo() -> i$032 { |
812 | let test = "test"; | 812 | let test = "test"; |
813 | if test == "test" { | 813 | if test == "test" { |
814 | return 24i32; | 814 | return 24i32; |
@@ -833,7 +833,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
833 | check_assist( | 833 | check_assist( |
834 | wrap_return_type_in_result, | 834 | wrap_return_type_in_result, |
835 | r#" | 835 | r#" |
836 | fn foo(the_field: u32) -><|> u32 { | 836 | fn foo(the_field: u32) ->$0 u32 { |
837 | let true_closure = || { return true; }; | 837 | let true_closure = || { return true; }; |
838 | if the_field < 5 { | 838 | if the_field < 5 { |
839 | let mut i = 0; | 839 | let mut i = 0; |
@@ -865,7 +865,7 @@ fn foo(the_field: u32) -> Result<u32, ${0:_}> { | |||
865 | check_assist( | 865 | check_assist( |
866 | wrap_return_type_in_result, | 866 | wrap_return_type_in_result, |
867 | r#" | 867 | r#" |
868 | fn foo(the_field: u32) -> u32<|> { | 868 | fn foo(the_field: u32) -> u32$0 { |
869 | let true_closure = || { | 869 | let true_closure = || { |
870 | return true; | 870 | return true; |
871 | }; | 871 | }; |
@@ -912,7 +912,7 @@ fn foo(the_field: u32) -> Result<u32, ${0:_}> { | |||
912 | check_assist( | 912 | check_assist( |
913 | wrap_return_type_in_result, | 913 | wrap_return_type_in_result, |
914 | r#" | 914 | r#" |
915 | fn foo() -> i32<|> { | 915 | fn foo() -> i32$0 { |
916 | let test = "test"; | 916 | let test = "test"; |
917 | if test == "test" { | 917 | if test == "test" { |
918 | return 24i32; | 918 | return 24i32; |
@@ -946,7 +946,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
946 | check_assist( | 946 | check_assist( |
947 | wrap_return_type_in_result, | 947 | wrap_return_type_in_result, |
948 | r#" | 948 | r#" |
949 | fn foo() -> i32<|> { | 949 | fn foo() -> i32$0 { |
950 | let test = "test"; | 950 | let test = "test"; |
951 | if test == "test" { | 951 | if test == "test" { |
952 | return 24i32; | 952 | return 24i32; |
@@ -984,7 +984,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
984 | check_assist( | 984 | check_assist( |
985 | wrap_return_type_in_result, | 985 | wrap_return_type_in_result, |
986 | r#" | 986 | r#" |
987 | fn foo() -> i3<|>2 { | 987 | fn foo() -> i3$02 { |
988 | let test = "test"; | 988 | let test = "test"; |
989 | let other = 5; | 989 | let other = 5; |
990 | if test == "test" { | 990 | if test == "test" { |
@@ -1030,7 +1030,7 @@ fn foo() -> Result<i32, ${0:_}> { | |||
1030 | check_assist( | 1030 | check_assist( |
1031 | wrap_return_type_in_result, | 1031 | wrap_return_type_in_result, |
1032 | r#" | 1032 | r#" |
1033 | fn foo(the_field: u32) -> u32<|> { | 1033 | fn foo(the_field: u32) -> u32$0 { |
1034 | if the_field < 5 { | 1034 | if the_field < 5 { |
1035 | let mut i = 0; | 1035 | let mut i = 0; |
1036 | loop { | 1036 | loop { |
@@ -1070,7 +1070,7 @@ fn foo(the_field: u32) -> Result<u32, ${0:_}> { | |||
1070 | check_assist( | 1070 | check_assist( |
1071 | wrap_return_type_in_result, | 1071 | wrap_return_type_in_result, |
1072 | r#" | 1072 | r#" |
1073 | fn foo(the_field: u32) -> u3<|>2 { | 1073 | fn foo(the_field: u32) -> u3$02 { |
1074 | if the_field < 5 { | 1074 | if the_field < 5 { |
1075 | let mut i = 0; | 1075 | let mut i = 0; |
1076 | match i { | 1076 | match i { |
@@ -1098,7 +1098,7 @@ fn foo(the_field: u32) -> Result<u32, ${0:_}> { | |||
1098 | check_assist( | 1098 | check_assist( |
1099 | wrap_return_type_in_result, | 1099 | wrap_return_type_in_result, |
1100 | r#" | 1100 | r#" |
1101 | fn foo(the_field: u32) -> u32<|> { | 1101 | fn foo(the_field: u32) -> u32$0 { |
1102 | if the_field < 5 { | 1102 | if the_field < 5 { |
1103 | let mut i = 0; | 1103 | let mut i = 0; |
1104 | if i == 5 { | 1104 | if i == 5 { |
@@ -1128,7 +1128,7 @@ fn foo(the_field: u32) -> Result<u32, ${0:_}> { | |||
1128 | check_assist( | 1128 | check_assist( |
1129 | wrap_return_type_in_result, | 1129 | wrap_return_type_in_result, |
1130 | r#" | 1130 | r#" |
1131 | fn foo(the_field: u32) -> <|>u32 { | 1131 | fn foo(the_field: u32) -> $0u32 { |
1132 | if the_field < 5 { | 1132 | if the_field < 5 { |
1133 | let mut i = 0; | 1133 | let mut i = 0; |
1134 | if i == 5 { | 1134 | if i == 5 { |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index fdec886e9..1080294ab 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -24,7 +24,7 @@ use syntax::TextRange; | |||
24 | 24 | ||
25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
26 | 26 | ||
27 | pub use assist_config::AssistConfig; | 27 | pub use assist_config::{AssistConfig, InsertUseConfig}; |
28 | 28 | ||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
30 | pub enum AssistKind { | 30 | pub enum AssistKind { |
@@ -116,7 +116,6 @@ mod handlers { | |||
116 | mod convert_integer_literal; | 116 | mod convert_integer_literal; |
117 | mod early_return; | 117 | mod early_return; |
118 | mod expand_glob_import; | 118 | mod expand_glob_import; |
119 | mod extract_module_to_file; | ||
120 | mod extract_struct_from_enum_variant; | 119 | mod extract_struct_from_enum_variant; |
121 | mod extract_variable; | 120 | mod extract_variable; |
122 | mod fill_match_arms; | 121 | mod fill_match_arms; |
@@ -124,13 +123,14 @@ mod handlers { | |||
124 | mod flip_binexpr; | 123 | mod flip_binexpr; |
125 | mod flip_comma; | 124 | mod flip_comma; |
126 | mod flip_trait_bound; | 125 | mod flip_trait_bound; |
127 | mod generate_derive; | ||
128 | mod generate_default_from_enum_variant; | 126 | mod generate_default_from_enum_variant; |
127 | mod generate_derive; | ||
129 | mod generate_from_impl_for_enum; | 128 | mod generate_from_impl_for_enum; |
130 | mod generate_function; | 129 | mod generate_function; |
131 | mod generate_impl; | 130 | mod generate_impl; |
132 | mod generate_new; | 131 | mod generate_new; |
133 | mod infer_function_return_type; | 132 | mod infer_function_return_type; |
133 | mod inline_function; | ||
134 | mod inline_local_variable; | 134 | mod inline_local_variable; |
135 | mod introduce_named_lifetime; | 135 | mod introduce_named_lifetime; |
136 | mod invert_if; | 136 | mod invert_if; |
@@ -138,12 +138,15 @@ mod handlers { | |||
138 | mod merge_match_arms; | 138 | mod merge_match_arms; |
139 | mod move_bounds; | 139 | mod move_bounds; |
140 | mod move_guard; | 140 | mod move_guard; |
141 | mod move_module_to_file; | ||
142 | mod pull_assignment_up; | ||
141 | mod qualify_path; | 143 | mod qualify_path; |
142 | mod raw_string; | 144 | mod raw_string; |
143 | mod remove_dbg; | 145 | mod remove_dbg; |
144 | mod remove_mut; | 146 | mod remove_mut; |
145 | mod remove_unused_param; | 147 | mod remove_unused_param; |
146 | mod reorder_fields; | 148 | mod reorder_fields; |
149 | mod reorder_impl; | ||
147 | mod replace_derive_with_manual_impl; | 150 | mod replace_derive_with_manual_impl; |
148 | mod replace_if_let_with_match; | 151 | mod replace_if_let_with_match; |
149 | mod replace_impl_trait_with_generic; | 152 | mod replace_impl_trait_with_generic; |
@@ -167,7 +170,7 @@ mod handlers { | |||
167 | convert_integer_literal::convert_integer_literal, | 170 | convert_integer_literal::convert_integer_literal, |
168 | early_return::convert_to_guarded_return, | 171 | early_return::convert_to_guarded_return, |
169 | expand_glob_import::expand_glob_import, | 172 | expand_glob_import::expand_glob_import, |
170 | extract_module_to_file::extract_module_to_file, | 173 | move_module_to_file::move_module_to_file, |
171 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 174 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
172 | extract_variable::extract_variable, | 175 | extract_variable::extract_variable, |
173 | fill_match_arms::fill_match_arms, | 176 | fill_match_arms::fill_match_arms, |
@@ -175,13 +178,14 @@ mod handlers { | |||
175 | flip_binexpr::flip_binexpr, | 178 | flip_binexpr::flip_binexpr, |
176 | flip_comma::flip_comma, | 179 | flip_comma::flip_comma, |
177 | flip_trait_bound::flip_trait_bound, | 180 | flip_trait_bound::flip_trait_bound, |
178 | generate_derive::generate_derive, | ||
179 | generate_default_from_enum_variant::generate_default_from_enum_variant, | 181 | generate_default_from_enum_variant::generate_default_from_enum_variant, |
182 | generate_derive::generate_derive, | ||
180 | generate_from_impl_for_enum::generate_from_impl_for_enum, | 183 | generate_from_impl_for_enum::generate_from_impl_for_enum, |
181 | generate_function::generate_function, | 184 | generate_function::generate_function, |
182 | generate_impl::generate_impl, | 185 | generate_impl::generate_impl, |
183 | generate_new::generate_new, | 186 | generate_new::generate_new, |
184 | infer_function_return_type::infer_function_return_type, | 187 | infer_function_return_type::infer_function_return_type, |
188 | inline_function::inline_function, | ||
185 | inline_local_variable::inline_local_variable, | 189 | inline_local_variable::inline_local_variable, |
186 | introduce_named_lifetime::introduce_named_lifetime, | 190 | introduce_named_lifetime::introduce_named_lifetime, |
187 | invert_if::invert_if, | 191 | invert_if::invert_if, |
@@ -190,6 +194,7 @@ mod handlers { | |||
190 | move_bounds::move_bounds_to_where_clause, | 194 | move_bounds::move_bounds_to_where_clause, |
191 | move_guard::move_arm_cond_to_match_guard, | 195 | move_guard::move_arm_cond_to_match_guard, |
192 | move_guard::move_guard_to_arm_body, | 196 | move_guard::move_guard_to_arm_body, |
197 | pull_assignment_up::pull_assignment_up, | ||
193 | qualify_path::qualify_path, | 198 | qualify_path::qualify_path, |
194 | raw_string::add_hash, | 199 | raw_string::add_hash, |
195 | raw_string::make_usual_string, | 200 | raw_string::make_usual_string, |
@@ -198,6 +203,7 @@ mod handlers { | |||
198 | remove_mut::remove_mut, | 203 | remove_mut::remove_mut, |
199 | remove_unused_param::remove_unused_param, | 204 | remove_unused_param::remove_unused_param, |
200 | reorder_fields::reorder_fields, | 205 | reorder_fields::reorder_fields, |
206 | reorder_impl::reorder_impl, | ||
201 | replace_derive_with_manual_impl::replace_derive_with_manual_impl, | 207 | replace_derive_with_manual_impl::replace_derive_with_manual_impl, |
202 | replace_if_let_with_match::replace_if_let_with_match, | 208 | replace_if_let_with_match::replace_if_let_with_match, |
203 | replace_if_let_with_match::replace_match_with_if_let, | 209 | replace_if_let_with_match::replace_match_with_if_let, |
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs index 21e448fb8..fef29a0b8 100644 --- a/crates/assists/src/tests.rs +++ b/crates/assists/src/tests.rs | |||
@@ -1,15 +1,29 @@ | |||
1 | mod generated; | 1 | mod generated; |
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | 4 | use ide_db::{ |
5 | use ide_db::source_change::FileSystemEdit; | 5 | base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, |
6 | use ide_db::RootDatabase; | 6 | helpers::{insert_use::MergeBehavior, SnippetCap}, |
7 | source_change::FileSystemEdit, | ||
8 | RootDatabase, | ||
9 | }; | ||
7 | use syntax::TextRange; | 10 | use syntax::TextRange; |
8 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 11 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
9 | 12 | ||
10 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists}; | 13 | use crate::{ |
14 | handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists, InsertUseConfig, | ||
15 | }; | ||
11 | use stdx::{format_to, trim_indent}; | 16 | use stdx::{format_to, trim_indent}; |
12 | 17 | ||
18 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | ||
19 | snippet_cap: SnippetCap::new(true), | ||
20 | allowed: None, | ||
21 | insert_use: InsertUseConfig { | ||
22 | merge: Some(MergeBehavior::Full), | ||
23 | prefix_kind: hir::PrefixKind::Plain, | ||
24 | }, | ||
25 | }; | ||
26 | |||
13 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | 27 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { |
14 | RootDatabase::with_single_file(text) | 28 | RootDatabase::with_single_file(text) |
15 | } | 29 | } |
@@ -48,14 +62,14 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
48 | let before = db.file_text(file_id).to_string(); | 62 | let before = db.file_text(file_id).to_string(); |
49 | let frange = FileRange { file_id, range: selection.into() }; | 63 | let frange = FileRange { file_id, range: selection.into() }; |
50 | 64 | ||
51 | let assist = Assist::get(&db, &AssistConfig::default(), true, frange) | 65 | let assist = Assist::get(&db, &TEST_CONFIG, true, frange) |
52 | .into_iter() | 66 | .into_iter() |
53 | .find(|assist| assist.id.0 == assist_id) | 67 | .find(|assist| assist.id.0 == assist_id) |
54 | .unwrap_or_else(|| { | 68 | .unwrap_or_else(|| { |
55 | panic!( | 69 | panic!( |
56 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", | 70 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", |
57 | assist_id, | 71 | assist_id, |
58 | Assist::get(&db, &AssistConfig::default(), false, frange) | 72 | Assist::get(&db, &TEST_CONFIG, false, frange) |
59 | .into_iter() | 73 | .into_iter() |
60 | .map(|assist| assist.id.0) | 74 | .map(|assist| assist.id.0) |
61 | .collect::<Vec<_>>() | 75 | .collect::<Vec<_>>() |
@@ -89,7 +103,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
89 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; | 103 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; |
90 | 104 | ||
91 | let sema = Semantics::new(&db); | 105 | let sema = Semantics::new(&db); |
92 | let config = AssistConfig::default(); | 106 | let config = TEST_CONFIG; |
93 | let ctx = AssistContext::new(sema, &config, frange); | 107 | let ctx = AssistContext::new(sema, &config, frange); |
94 | let mut acc = Assists::new(&ctx, true); | 108 | let mut acc = Assists::new(&ctx, true); |
95 | handler(&mut acc, &ctx); | 109 | handler(&mut acc, &ctx); |
@@ -152,11 +166,11 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
152 | 166 | ||
153 | #[test] | 167 | #[test] |
154 | fn assist_order_field_struct() { | 168 | fn assist_order_field_struct() { |
155 | let before = "struct Foo { <|>bar: u32 }"; | 169 | let before = "struct Foo { $0bar: u32 }"; |
156 | let (before_cursor_pos, before) = extract_offset(before); | 170 | let (before_cursor_pos, before) = extract_offset(before); |
157 | let (db, file_id) = with_single_file(&before); | 171 | let (db, file_id) = with_single_file(&before); |
158 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; | 172 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; |
159 | let assists = Assist::get(&db, &AssistConfig::default(), false, frange); | 173 | let assists = Assist::get(&db, &TEST_CONFIG, false, frange); |
160 | let mut assists = assists.iter(); | 174 | let mut assists = assists.iter(); |
161 | 175 | ||
162 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); | 176 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); |
@@ -167,7 +181,7 @@ fn assist_order_field_struct() { | |||
167 | fn assist_order_if_expr() { | 181 | fn assist_order_if_expr() { |
168 | let before = " | 182 | let before = " |
169 | pub fn test_some_range(a: int) -> bool { | 183 | pub fn test_some_range(a: int) -> bool { |
170 | if let 2..6 = <|>5<|> { | 184 | if let 2..6 = $05$0 { |
171 | true | 185 | true |
172 | } else { | 186 | } else { |
173 | false | 187 | false |
@@ -176,7 +190,7 @@ fn assist_order_if_expr() { | |||
176 | let (range, before) = extract_range(before); | 190 | let (range, before) = extract_range(before); |
177 | let (db, file_id) = with_single_file(&before); | 191 | let (db, file_id) = with_single_file(&before); |
178 | let frange = FileRange { file_id, range }; | 192 | let frange = FileRange { file_id, range }; |
179 | let assists = Assist::get(&db, &AssistConfig::default(), false, frange); | 193 | let assists = Assist::get(&db, &TEST_CONFIG, false, frange); |
180 | let mut assists = assists.iter(); | 194 | let mut assists = assists.iter(); |
181 | 195 | ||
182 | assert_eq!(assists.next().expect("expected assist").label, "Extract into variable"); | 196 | assert_eq!(assists.next().expect("expected assist").label, "Extract into variable"); |
@@ -187,7 +201,7 @@ fn assist_order_if_expr() { | |||
187 | fn assist_filter_works() { | 201 | fn assist_filter_works() { |
188 | let before = " | 202 | let before = " |
189 | pub fn test_some_range(a: int) -> bool { | 203 | pub fn test_some_range(a: int) -> bool { |
190 | if let 2..6 = <|>5<|> { | 204 | if let 2..6 = $05$0 { |
191 | true | 205 | true |
192 | } else { | 206 | } else { |
193 | false | 207 | false |
@@ -198,7 +212,7 @@ fn assist_filter_works() { | |||
198 | let frange = FileRange { file_id, range }; | 212 | let frange = FileRange { file_id, range }; |
199 | 213 | ||
200 | { | 214 | { |
201 | let mut cfg = AssistConfig::default(); | 215 | let mut cfg = TEST_CONFIG; |
202 | cfg.allowed = Some(vec![AssistKind::Refactor]); | 216 | cfg.allowed = Some(vec![AssistKind::Refactor]); |
203 | 217 | ||
204 | let assists = Assist::get(&db, &cfg, false, frange); | 218 | let assists = Assist::get(&db, &cfg, false, frange); |
@@ -209,7 +223,7 @@ fn assist_filter_works() { | |||
209 | } | 223 | } |
210 | 224 | ||
211 | { | 225 | { |
212 | let mut cfg = AssistConfig::default(); | 226 | let mut cfg = TEST_CONFIG; |
213 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); | 227 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); |
214 | let assists = Assist::get(&db, &cfg, false, frange); | 228 | let assists = Assist::get(&db, &cfg, false, frange); |
215 | assert_eq!(assists.len(), 1); | 229 | assert_eq!(assists.len(), 1); |
@@ -219,7 +233,7 @@ fn assist_filter_works() { | |||
219 | } | 233 | } |
220 | 234 | ||
221 | { | 235 | { |
222 | let mut cfg = AssistConfig::default(); | 236 | let mut cfg = TEST_CONFIG; |
223 | cfg.allowed = Some(vec![AssistKind::QuickFix]); | 237 | cfg.allowed = Some(vec![AssistKind::QuickFix]); |
224 | let assists = Assist::get(&db, &cfg, false, frange); | 238 | let assists = Assist::get(&db, &cfg, false, frange); |
225 | assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out"); | 239 | assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out"); |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index d3dfe24e7..217f577eb 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -8,7 +8,7 @@ fn doctest_add_explicit_type() { | |||
8 | "add_explicit_type", | 8 | "add_explicit_type", |
9 | r#####" | 9 | r#####" |
10 | fn main() { | 10 | fn main() { |
11 | let x<|> = 92; | 11 | let x$0 = 92; |
12 | } | 12 | } |
13 | "#####, | 13 | "#####, |
14 | r#####" | 14 | r#####" |
@@ -25,7 +25,7 @@ fn doctest_add_hash() { | |||
25 | "add_hash", | 25 | "add_hash", |
26 | r#####" | 26 | r#####" |
27 | fn main() { | 27 | fn main() { |
28 | r#"Hello,<|> World!"#; | 28 | r#"Hello,$0 World!"#; |
29 | } | 29 | } |
30 | "#####, | 30 | "#####, |
31 | r#####" | 31 | r#####" |
@@ -49,7 +49,7 @@ trait Trait { | |||
49 | 49 | ||
50 | impl Trait for () { | 50 | impl Trait for () { |
51 | type X = (); | 51 | type X = (); |
52 | fn foo(&self) {}<|> | 52 | fn foo(&self) {}$0 |
53 | 53 | ||
54 | } | 54 | } |
55 | "#####, | 55 | "#####, |
@@ -81,7 +81,7 @@ trait Trait<T> { | |||
81 | fn bar(&self) {} | 81 | fn bar(&self) {} |
82 | } | 82 | } |
83 | 83 | ||
84 | impl Trait<u32> for () {<|> | 84 | impl Trait<u32> for () {$0 |
85 | 85 | ||
86 | } | 86 | } |
87 | "#####, | 87 | "#####, |
@@ -110,7 +110,7 @@ fn doctest_add_turbo_fish() { | |||
110 | r#####" | 110 | r#####" |
111 | fn make<T>() -> T { todo!() } | 111 | fn make<T>() -> T { todo!() } |
112 | fn main() { | 112 | fn main() { |
113 | let x = make<|>(); | 113 | let x = make$0(); |
114 | } | 114 | } |
115 | "#####, | 115 | "#####, |
116 | r#####" | 116 | r#####" |
@@ -128,7 +128,7 @@ fn doctest_apply_demorgan() { | |||
128 | "apply_demorgan", | 128 | "apply_demorgan", |
129 | r#####" | 129 | r#####" |
130 | fn main() { | 130 | fn main() { |
131 | if x != 4 ||<|> !y {} | 131 | if x != 4 ||$0 !y {} |
132 | } | 132 | } |
133 | "#####, | 133 | "#####, |
134 | r#####" | 134 | r#####" |
@@ -145,7 +145,7 @@ fn doctest_auto_import() { | |||
145 | "auto_import", | 145 | "auto_import", |
146 | r#####" | 146 | r#####" |
147 | fn main() { | 147 | fn main() { |
148 | let map = HashMap<|>::new(); | 148 | let map = HashMap$0::new(); |
149 | } | 149 | } |
150 | pub mod std { pub mod collections { pub struct HashMap { } } } | 150 | pub mod std { pub mod collections { pub struct HashMap { } } } |
151 | "#####, | 151 | "#####, |
@@ -165,7 +165,7 @@ fn doctest_change_visibility() { | |||
165 | check_doc_test( | 165 | check_doc_test( |
166 | "change_visibility", | 166 | "change_visibility", |
167 | r#####" | 167 | r#####" |
168 | <|>fn frobnicate() {} | 168 | $0fn frobnicate() {} |
169 | "#####, | 169 | "#####, |
170 | r#####" | 170 | r#####" |
171 | pub(crate) fn frobnicate() {} | 171 | pub(crate) fn frobnicate() {} |
@@ -178,7 +178,7 @@ fn doctest_convert_integer_literal() { | |||
178 | check_doc_test( | 178 | check_doc_test( |
179 | "convert_integer_literal", | 179 | "convert_integer_literal", |
180 | r#####" | 180 | r#####" |
181 | const _: i32 = 10<|>; | 181 | const _: i32 = 10$0; |
182 | "#####, | 182 | "#####, |
183 | r#####" | 183 | r#####" |
184 | const _: i32 = 0b1010; | 184 | const _: i32 = 0b1010; |
@@ -192,7 +192,7 @@ fn doctest_convert_to_guarded_return() { | |||
192 | "convert_to_guarded_return", | 192 | "convert_to_guarded_return", |
193 | r#####" | 193 | r#####" |
194 | fn main() { | 194 | fn main() { |
195 | <|>if cond { | 195 | $0if cond { |
196 | foo(); | 196 | foo(); |
197 | bar(); | 197 | bar(); |
198 | } | 198 | } |
@@ -220,7 +220,7 @@ mod foo { | |||
220 | pub struct Baz; | 220 | pub struct Baz; |
221 | } | 221 | } |
222 | 222 | ||
223 | use foo::*<|>; | 223 | use foo::*$0; |
224 | 224 | ||
225 | fn qux(bar: Bar, baz: Baz) {} | 225 | fn qux(bar: Bar, baz: Baz) {} |
226 | "#####, | 226 | "#####, |
@@ -238,26 +238,11 @@ fn qux(bar: Bar, baz: Baz) {} | |||
238 | } | 238 | } |
239 | 239 | ||
240 | #[test] | 240 | #[test] |
241 | fn doctest_extract_module_to_file() { | ||
242 | check_doc_test( | ||
243 | "extract_module_to_file", | ||
244 | r#####" | ||
245 | mod foo {<|> | ||
246 | fn t() {} | ||
247 | } | ||
248 | "#####, | ||
249 | r#####" | ||
250 | mod foo; | ||
251 | "#####, | ||
252 | ) | ||
253 | } | ||
254 | |||
255 | #[test] | ||
256 | fn doctest_extract_struct_from_enum_variant() { | 241 | fn doctest_extract_struct_from_enum_variant() { |
257 | check_doc_test( | 242 | check_doc_test( |
258 | "extract_struct_from_enum_variant", | 243 | "extract_struct_from_enum_variant", |
259 | r#####" | 244 | r#####" |
260 | enum A { <|>One(u32, u32) } | 245 | enum A { $0One(u32, u32) } |
261 | "#####, | 246 | "#####, |
262 | r#####" | 247 | r#####" |
263 | struct One(pub u32, pub u32); | 248 | struct One(pub u32, pub u32); |
@@ -273,7 +258,7 @@ fn doctest_extract_variable() { | |||
273 | "extract_variable", | 258 | "extract_variable", |
274 | r#####" | 259 | r#####" |
275 | fn main() { | 260 | fn main() { |
276 | <|>(1 + 2)<|> * 4; | 261 | $0(1 + 2)$0 * 4; |
277 | } | 262 | } |
278 | "#####, | 263 | "#####, |
279 | r#####" | 264 | r#####" |
@@ -294,7 +279,7 @@ enum Action { Move { distance: u32 }, Stop } | |||
294 | 279 | ||
295 | fn handle(action: Action) { | 280 | fn handle(action: Action) { |
296 | match action { | 281 | match action { |
297 | <|> | 282 | $0 |
298 | } | 283 | } |
299 | } | 284 | } |
300 | "#####, | 285 | "#####, |
@@ -320,7 +305,7 @@ mod m { | |||
320 | fn frobnicate() {} | 305 | fn frobnicate() {} |
321 | } | 306 | } |
322 | fn main() { | 307 | fn main() { |
323 | m::frobnicate<|>() {} | 308 | m::frobnicate$0() {} |
324 | } | 309 | } |
325 | "#####, | 310 | "#####, |
326 | r#####" | 311 | r#####" |
@@ -340,7 +325,7 @@ fn doctest_flip_binexpr() { | |||
340 | "flip_binexpr", | 325 | "flip_binexpr", |
341 | r#####" | 326 | r#####" |
342 | fn main() { | 327 | fn main() { |
343 | let _ = 90 +<|> 2; | 328 | let _ = 90 +$0 2; |
344 | } | 329 | } |
345 | "#####, | 330 | "#####, |
346 | r#####" | 331 | r#####" |
@@ -357,7 +342,7 @@ fn doctest_flip_comma() { | |||
357 | "flip_comma", | 342 | "flip_comma", |
358 | r#####" | 343 | r#####" |
359 | fn main() { | 344 | fn main() { |
360 | ((1, 2),<|> (3, 4)); | 345 | ((1, 2),$0 (3, 4)); |
361 | } | 346 | } |
362 | "#####, | 347 | "#####, |
363 | r#####" | 348 | r#####" |
@@ -373,7 +358,7 @@ fn doctest_flip_trait_bound() { | |||
373 | check_doc_test( | 358 | check_doc_test( |
374 | "flip_trait_bound", | 359 | "flip_trait_bound", |
375 | r#####" | 360 | r#####" |
376 | fn foo<T: Clone +<|> Copy>() { } | 361 | fn foo<T: Clone +$0 Copy>() { } |
377 | "#####, | 362 | "#####, |
378 | r#####" | 363 | r#####" |
379 | fn foo<T: Copy + Clone>() { } | 364 | fn foo<T: Copy + Clone>() { } |
@@ -388,7 +373,7 @@ fn doctest_generate_default_from_enum_variant() { | |||
388 | r#####" | 373 | r#####" |
389 | enum Version { | 374 | enum Version { |
390 | Undefined, | 375 | Undefined, |
391 | Minor<|>, | 376 | Minor$0, |
392 | Major, | 377 | Major, |
393 | } | 378 | } |
394 | "#####, | 379 | "#####, |
@@ -415,7 +400,7 @@ fn doctest_generate_derive() { | |||
415 | r#####" | 400 | r#####" |
416 | struct Point { | 401 | struct Point { |
417 | x: u32, | 402 | x: u32, |
418 | y: u32,<|> | 403 | y: u32,$0 |
419 | } | 404 | } |
420 | "#####, | 405 | "#####, |
421 | r#####" | 406 | r#####" |
@@ -433,7 +418,7 @@ fn doctest_generate_from_impl_for_enum() { | |||
433 | check_doc_test( | 418 | check_doc_test( |
434 | "generate_from_impl_for_enum", | 419 | "generate_from_impl_for_enum", |
435 | r#####" | 420 | r#####" |
436 | enum A { <|>One(u32) } | 421 | enum A { $0One(u32) } |
437 | "#####, | 422 | "#####, |
438 | r#####" | 423 | r#####" |
439 | enum A { One(u32) } | 424 | enum A { One(u32) } |
@@ -455,7 +440,7 @@ fn doctest_generate_function() { | |||
455 | struct Baz; | 440 | struct Baz; |
456 | fn baz() -> Baz { Baz } | 441 | fn baz() -> Baz { Baz } |
457 | fn foo() { | 442 | fn foo() { |
458 | bar<|>("", baz()); | 443 | bar$0("", baz()); |
459 | } | 444 | } |
460 | 445 | ||
461 | "#####, | 446 | "#####, |
@@ -480,7 +465,7 @@ fn doctest_generate_impl() { | |||
480 | "generate_impl", | 465 | "generate_impl", |
481 | r#####" | 466 | r#####" |
482 | struct Ctx<T: Clone> { | 467 | struct Ctx<T: Clone> { |
483 | data: T,<|> | 468 | data: T,$0 |
484 | } | 469 | } |
485 | "#####, | 470 | "#####, |
486 | r#####" | 471 | r#####" |
@@ -501,7 +486,7 @@ fn doctest_generate_new() { | |||
501 | "generate_new", | 486 | "generate_new", |
502 | r#####" | 487 | r#####" |
503 | struct Ctx<T: Clone> { | 488 | struct Ctx<T: Clone> { |
504 | data: T,<|> | 489 | data: T,$0 |
505 | } | 490 | } |
506 | "#####, | 491 | "#####, |
507 | r#####" | 492 | r#####" |
@@ -522,7 +507,7 @@ fn doctest_infer_function_return_type() { | |||
522 | check_doc_test( | 507 | check_doc_test( |
523 | "infer_function_return_type", | 508 | "infer_function_return_type", |
524 | r#####" | 509 | r#####" |
525 | fn foo() { 4<|>2i32 } | 510 | fn foo() { 4$02i32 } |
526 | "#####, | 511 | "#####, |
527 | r#####" | 512 | r#####" |
528 | fn foo() -> i32 { 42i32 } | 513 | fn foo() -> i32 { 42i32 } |
@@ -531,12 +516,35 @@ fn foo() -> i32 { 42i32 } | |||
531 | } | 516 | } |
532 | 517 | ||
533 | #[test] | 518 | #[test] |
519 | fn doctest_inline_function() { | ||
520 | check_doc_test( | ||
521 | "inline_function", | ||
522 | r#####" | ||
523 | fn add(a: u32, b: u32) -> u32 { a + b } | ||
524 | fn main() { | ||
525 | let x = add$0(1, 2); | ||
526 | } | ||
527 | "#####, | ||
528 | r#####" | ||
529 | fn add(a: u32, b: u32) -> u32 { a + b } | ||
530 | fn main() { | ||
531 | let x = { | ||
532 | let a = 1; | ||
533 | let b = 2; | ||
534 | a + b | ||
535 | }; | ||
536 | } | ||
537 | "#####, | ||
538 | ) | ||
539 | } | ||
540 | |||
541 | #[test] | ||
534 | fn doctest_inline_local_variable() { | 542 | fn doctest_inline_local_variable() { |
535 | check_doc_test( | 543 | check_doc_test( |
536 | "inline_local_variable", | 544 | "inline_local_variable", |
537 | r#####" | 545 | r#####" |
538 | fn main() { | 546 | fn main() { |
539 | let x<|> = 1 + 2; | 547 | let x$0 = 1 + 2; |
540 | x * 4; | 548 | x * 4; |
541 | } | 549 | } |
542 | "#####, | 550 | "#####, |
@@ -553,7 +561,7 @@ fn doctest_introduce_named_lifetime() { | |||
553 | check_doc_test( | 561 | check_doc_test( |
554 | "introduce_named_lifetime", | 562 | "introduce_named_lifetime", |
555 | r#####" | 563 | r#####" |
556 | impl Cursor<'_<|>> { | 564 | impl Cursor<'_$0> { |
557 | fn node(self) -> &SyntaxNode { | 565 | fn node(self) -> &SyntaxNode { |
558 | match self { | 566 | match self { |
559 | Cursor::Replace(node) | Cursor::Before(node) => node, | 567 | Cursor::Replace(node) | Cursor::Before(node) => node, |
@@ -579,7 +587,7 @@ fn doctest_invert_if() { | |||
579 | "invert_if", | 587 | "invert_if", |
580 | r#####" | 588 | r#####" |
581 | fn main() { | 589 | fn main() { |
582 | if<|> !y { A } else { B } | 590 | if$0 !y { A } else { B } |
583 | } | 591 | } |
584 | "#####, | 592 | "#####, |
585 | r#####" | 593 | r#####" |
@@ -596,7 +604,7 @@ fn doctest_make_raw_string() { | |||
596 | "make_raw_string", | 604 | "make_raw_string", |
597 | r#####" | 605 | r#####" |
598 | fn main() { | 606 | fn main() { |
599 | "Hello,<|> World!"; | 607 | "Hello,$0 World!"; |
600 | } | 608 | } |
601 | "#####, | 609 | "#####, |
602 | r#####" | 610 | r#####" |
@@ -613,7 +621,7 @@ fn doctest_make_usual_string() { | |||
613 | "make_usual_string", | 621 | "make_usual_string", |
614 | r#####" | 622 | r#####" |
615 | fn main() { | 623 | fn main() { |
616 | r#"Hello,<|> "World!""#; | 624 | r#"Hello,$0 "World!""#; |
617 | } | 625 | } |
618 | "#####, | 626 | "#####, |
619 | r#####" | 627 | r#####" |
@@ -629,7 +637,7 @@ fn doctest_merge_imports() { | |||
629 | check_doc_test( | 637 | check_doc_test( |
630 | "merge_imports", | 638 | "merge_imports", |
631 | r#####" | 639 | r#####" |
632 | use std::<|>fmt::Formatter; | 640 | use std::$0fmt::Formatter; |
633 | use std::io; | 641 | use std::io; |
634 | "#####, | 642 | "#####, |
635 | r#####" | 643 | r#####" |
@@ -647,7 +655,7 @@ enum Action { Move { distance: u32 }, Stop } | |||
647 | 655 | ||
648 | fn handle(action: Action) { | 656 | fn handle(action: Action) { |
649 | match action { | 657 | match action { |
650 | <|>Action::Move(..) => foo(), | 658 | $0Action::Move(..) => foo(), |
651 | Action::Stop => foo(), | 659 | Action::Stop => foo(), |
652 | } | 660 | } |
653 | } | 661 | } |
@@ -673,7 +681,7 @@ enum Action { Move { distance: u32 }, Stop } | |||
673 | 681 | ||
674 | fn handle(action: Action) { | 682 | fn handle(action: Action) { |
675 | match action { | 683 | match action { |
676 | Action::Move { distance } => <|>if distance > 10 { foo() }, | 684 | Action::Move { distance } => $0if distance > 10 { foo() }, |
677 | _ => (), | 685 | _ => (), |
678 | } | 686 | } |
679 | } | 687 | } |
@@ -696,7 +704,7 @@ fn doctest_move_bounds_to_where_clause() { | |||
696 | check_doc_test( | 704 | check_doc_test( |
697 | "move_bounds_to_where_clause", | 705 | "move_bounds_to_where_clause", |
698 | r#####" | 706 | r#####" |
699 | fn apply<T, U, <|>F: FnOnce(T) -> U>(f: F, x: T) -> U { | 707 | fn apply<T, U, $0F: FnOnce(T) -> U>(f: F, x: T) -> U { |
700 | f(x) | 708 | f(x) |
701 | } | 709 | } |
702 | "#####, | 710 | "#####, |
@@ -717,7 +725,7 @@ enum Action { Move { distance: u32 }, Stop } | |||
717 | 725 | ||
718 | fn handle(action: Action) { | 726 | fn handle(action: Action) { |
719 | match action { | 727 | match action { |
720 | Action::Move { distance } <|>if distance > 10 => foo(), | 728 | Action::Move { distance } $0if distance > 10 => foo(), |
721 | _ => (), | 729 | _ => (), |
722 | } | 730 | } |
723 | } | 731 | } |
@@ -738,12 +746,56 @@ fn handle(action: Action) { | |||
738 | } | 746 | } |
739 | 747 | ||
740 | #[test] | 748 | #[test] |
749 | fn doctest_move_module_to_file() { | ||
750 | check_doc_test( | ||
751 | "move_module_to_file", | ||
752 | r#####" | ||
753 | mod $0foo { | ||
754 | fn t() {} | ||
755 | } | ||
756 | "#####, | ||
757 | r#####" | ||
758 | mod foo; | ||
759 | "#####, | ||
760 | ) | ||
761 | } | ||
762 | |||
763 | #[test] | ||
764 | fn doctest_pull_assignment_up() { | ||
765 | check_doc_test( | ||
766 | "pull_assignment_up", | ||
767 | r#####" | ||
768 | fn main() { | ||
769 | let mut foo = 6; | ||
770 | |||
771 | if true { | ||
772 | $0foo = 5; | ||
773 | } else { | ||
774 | foo = 4; | ||
775 | } | ||
776 | } | ||
777 | "#####, | ||
778 | r#####" | ||
779 | fn main() { | ||
780 | let mut foo = 6; | ||
781 | |||
782 | foo = if true { | ||
783 | 5 | ||
784 | } else { | ||
785 | 4 | ||
786 | }; | ||
787 | } | ||
788 | "#####, | ||
789 | ) | ||
790 | } | ||
791 | |||
792 | #[test] | ||
741 | fn doctest_qualify_path() { | 793 | fn doctest_qualify_path() { |
742 | check_doc_test( | 794 | check_doc_test( |
743 | "qualify_path", | 795 | "qualify_path", |
744 | r#####" | 796 | r#####" |
745 | fn main() { | 797 | fn main() { |
746 | let map = HashMap<|>::new(); | 798 | let map = HashMap$0::new(); |
747 | } | 799 | } |
748 | pub mod std { pub mod collections { pub struct HashMap { } } } | 800 | pub mod std { pub mod collections { pub struct HashMap { } } } |
749 | "#####, | 801 | "#####, |
@@ -762,7 +814,7 @@ fn doctest_remove_dbg() { | |||
762 | "remove_dbg", | 814 | "remove_dbg", |
763 | r#####" | 815 | r#####" |
764 | fn main() { | 816 | fn main() { |
765 | <|>dbg!(92); | 817 | $0dbg!(92); |
766 | } | 818 | } |
767 | "#####, | 819 | "#####, |
768 | r#####" | 820 | r#####" |
@@ -779,7 +831,7 @@ fn doctest_remove_hash() { | |||
779 | "remove_hash", | 831 | "remove_hash", |
780 | r#####" | 832 | r#####" |
781 | fn main() { | 833 | fn main() { |
782 | r#"Hello,<|> World!"#; | 834 | r#"Hello,$0 World!"#; |
783 | } | 835 | } |
784 | "#####, | 836 | "#####, |
785 | r#####" | 837 | r#####" |
@@ -796,7 +848,7 @@ fn doctest_remove_mut() { | |||
796 | "remove_mut", | 848 | "remove_mut", |
797 | r#####" | 849 | r#####" |
798 | impl Walrus { | 850 | impl Walrus { |
799 | fn feed(&mut<|> self, amount: u32) {} | 851 | fn feed(&mut$0 self, amount: u32) {} |
800 | } | 852 | } |
801 | "#####, | 853 | "#####, |
802 | r#####" | 854 | r#####" |
@@ -812,7 +864,7 @@ fn doctest_remove_unused_param() { | |||
812 | check_doc_test( | 864 | check_doc_test( |
813 | "remove_unused_param", | 865 | "remove_unused_param", |
814 | r#####" | 866 | r#####" |
815 | fn frobnicate(x: i32<|>) {} | 867 | fn frobnicate(x: i32$0) {} |
816 | 868 | ||
817 | fn main() { | 869 | fn main() { |
818 | frobnicate(92); | 870 | frobnicate(92); |
@@ -834,7 +886,7 @@ fn doctest_reorder_fields() { | |||
834 | "reorder_fields", | 886 | "reorder_fields", |
835 | r#####" | 887 | r#####" |
836 | struct Foo {foo: i32, bar: i32}; | 888 | struct Foo {foo: i32, bar: i32}; |
837 | const test: Foo = <|>Foo {bar: 0, foo: 1} | 889 | const test: Foo = $0Foo {bar: 0, foo: 1} |
838 | "#####, | 890 | "#####, |
839 | r#####" | 891 | r#####" |
840 | struct Foo {foo: i32, bar: i32}; | 892 | struct Foo {foo: i32, bar: i32}; |
@@ -844,12 +896,47 @@ const test: Foo = Foo {foo: 1, bar: 0} | |||
844 | } | 896 | } |
845 | 897 | ||
846 | #[test] | 898 | #[test] |
899 | fn doctest_reorder_impl() { | ||
900 | check_doc_test( | ||
901 | "reorder_impl", | ||
902 | r#####" | ||
903 | trait Foo { | ||
904 | fn a() {} | ||
905 | fn b() {} | ||
906 | fn c() {} | ||
907 | } | ||
908 | |||
909 | struct Bar; | ||
910 | $0impl Foo for Bar { | ||
911 | fn b() {} | ||
912 | fn c() {} | ||
913 | fn a() {} | ||
914 | } | ||
915 | "#####, | ||
916 | r#####" | ||
917 | trait Foo { | ||
918 | fn a() {} | ||
919 | fn b() {} | ||
920 | fn c() {} | ||
921 | } | ||
922 | |||
923 | struct Bar; | ||
924 | impl Foo for Bar { | ||
925 | fn a() {} | ||
926 | fn b() {} | ||
927 | fn c() {} | ||
928 | } | ||
929 | "#####, | ||
930 | ) | ||
931 | } | ||
932 | |||
933 | #[test] | ||
847 | fn doctest_replace_derive_with_manual_impl() { | 934 | fn doctest_replace_derive_with_manual_impl() { |
848 | check_doc_test( | 935 | check_doc_test( |
849 | "replace_derive_with_manual_impl", | 936 | "replace_derive_with_manual_impl", |
850 | r#####" | 937 | r#####" |
851 | trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; } | 938 | trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; } |
852 | #[derive(Deb<|>ug, Display)] | 939 | #[derive(Deb$0ug, Display)] |
853 | struct S; | 940 | struct S; |
854 | "#####, | 941 | "#####, |
855 | r#####" | 942 | r#####" |
@@ -874,7 +961,7 @@ fn doctest_replace_if_let_with_match() { | |||
874 | enum Action { Move { distance: u32 }, Stop } | 961 | enum Action { Move { distance: u32 }, Stop } |
875 | 962 | ||
876 | fn handle(action: Action) { | 963 | fn handle(action: Action) { |
877 | <|>if let Action::Move { distance } = action { | 964 | $0if let Action::Move { distance } = action { |
878 | foo(distance) | 965 | foo(distance) |
879 | } else { | 966 | } else { |
880 | bar() | 967 | bar() |
@@ -899,7 +986,7 @@ fn doctest_replace_impl_trait_with_generic() { | |||
899 | check_doc_test( | 986 | check_doc_test( |
900 | "replace_impl_trait_with_generic", | 987 | "replace_impl_trait_with_generic", |
901 | r#####" | 988 | r#####" |
902 | fn foo(bar: <|>impl Bar) {} | 989 | fn foo(bar: $0impl Bar) {} |
903 | "#####, | 990 | "#####, |
904 | r#####" | 991 | r#####" |
905 | fn foo<B: Bar>(bar: B) {} | 992 | fn foo<B: Bar>(bar: B) {} |
@@ -915,7 +1002,7 @@ fn doctest_replace_let_with_if_let() { | |||
915 | enum Option<T> { Some(T), None } | 1002 | enum Option<T> { Some(T), None } |
916 | 1003 | ||
917 | fn main(action: Action) { | 1004 | fn main(action: Action) { |
918 | <|>let x = compute(); | 1005 | $0let x = compute(); |
919 | } | 1006 | } |
920 | 1007 | ||
921 | fn compute() -> Option<i32> { None } | 1008 | fn compute() -> Option<i32> { None } |
@@ -941,7 +1028,7 @@ fn doctest_replace_match_with_if_let() { | |||
941 | enum Action { Move { distance: u32 }, Stop } | 1028 | enum Action { Move { distance: u32 }, Stop } |
942 | 1029 | ||
943 | fn handle(action: Action) { | 1030 | fn handle(action: Action) { |
944 | <|>match action { | 1031 | $0match action { |
945 | Action::Move { distance } => foo(distance), | 1032 | Action::Move { distance } => foo(distance), |
946 | _ => bar(), | 1033 | _ => bar(), |
947 | } | 1034 | } |
@@ -966,7 +1053,7 @@ fn doctest_replace_qualified_name_with_use() { | |||
966 | check_doc_test( | 1053 | check_doc_test( |
967 | "replace_qualified_name_with_use", | 1054 | "replace_qualified_name_with_use", |
968 | r#####" | 1055 | r#####" |
969 | fn process(map: std::collections::<|>HashMap<String, String>) {} | 1056 | fn process(map: std::collections::$0HashMap<String, String>) {} |
970 | "#####, | 1057 | "#####, |
971 | r#####" | 1058 | r#####" |
972 | use std::collections::HashMap; | 1059 | use std::collections::HashMap; |
@@ -982,7 +1069,7 @@ fn doctest_replace_string_with_char() { | |||
982 | "replace_string_with_char", | 1069 | "replace_string_with_char", |
983 | r#####" | 1070 | r#####" |
984 | fn main() { | 1071 | fn main() { |
985 | find("{<|>"); | 1072 | find("{$0"); |
986 | } | 1073 | } |
987 | "#####, | 1074 | "#####, |
988 | r#####" | 1075 | r#####" |
@@ -1001,7 +1088,7 @@ fn doctest_replace_unwrap_with_match() { | |||
1001 | enum Result<T, E> { Ok(T), Err(E) } | 1088 | enum Result<T, E> { Ok(T), Err(E) } |
1002 | fn main() { | 1089 | fn main() { |
1003 | let x: Result<i32, i32> = Result::Ok(92); | 1090 | let x: Result<i32, i32> = Result::Ok(92); |
1004 | let y = x.<|>unwrap(); | 1091 | let y = x.$0unwrap(); |
1005 | } | 1092 | } |
1006 | "#####, | 1093 | "#####, |
1007 | r#####" | 1094 | r#####" |
@@ -1022,7 +1109,7 @@ fn doctest_split_import() { | |||
1022 | check_doc_test( | 1109 | check_doc_test( |
1023 | "split_import", | 1110 | "split_import", |
1024 | r#####" | 1111 | r#####" |
1025 | use std::<|>collections::HashMap; | 1112 | use std::$0collections::HashMap; |
1026 | "#####, | 1113 | "#####, |
1027 | r#####" | 1114 | r#####" |
1028 | use std::{collections::HashMap}; | 1115 | use std::{collections::HashMap}; |
@@ -1035,7 +1122,7 @@ fn doctest_toggle_ignore() { | |||
1035 | check_doc_test( | 1122 | check_doc_test( |
1036 | "toggle_ignore", | 1123 | "toggle_ignore", |
1037 | r#####" | 1124 | r#####" |
1038 | <|>#[test] | 1125 | $0#[test] |
1039 | fn arithmetics { | 1126 | fn arithmetics { |
1040 | assert_eq!(2 + 2, 5); | 1127 | assert_eq!(2 + 2, 5); |
1041 | } | 1128 | } |
@@ -1056,7 +1143,7 @@ fn doctest_unwrap_block() { | |||
1056 | "unwrap_block", | 1143 | "unwrap_block", |
1057 | r#####" | 1144 | r#####" |
1058 | fn foo() { | 1145 | fn foo() { |
1059 | if true {<|> | 1146 | if true {$0 |
1060 | println!("foo"); | 1147 | println!("foo"); |
1061 | } | 1148 | } |
1062 | } | 1149 | } |
@@ -1074,7 +1161,7 @@ fn doctest_wrap_return_type_in_result() { | |||
1074 | check_doc_test( | 1161 | check_doc_test( |
1075 | "wrap_return_type_in_result", | 1162 | "wrap_return_type_in_result", |
1076 | r#####" | 1163 | r#####" |
1077 | fn foo() -> i32<|> { 42i32 } | 1164 | fn foo() -> i32$0 { 42i32 } |
1078 | "#####, | 1165 | "#####, |
1079 | r#####" | 1166 | r#####" |
1080 | fn foo() -> Result<i32, ${0:_}> { Ok(42i32) } | 1167 | fn foo() -> Result<i32, ${0:_}> { Ok(42i32) } |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index d41084b59..9ea96eb73 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -4,7 +4,7 @@ pub(crate) mod import_assets; | |||
4 | use std::ops; | 4 | use std::ops; |
5 | 5 | ||
6 | use hir::HasSource; | 6 | use hir::HasSource; |
7 | use ide_db::RootDatabase; | 7 | use ide_db::{helpers::SnippetCap, RootDatabase}; |
8 | use itertools::Itertools; | 8 | use itertools::Itertools; |
9 | use syntax::{ | 9 | use syntax::{ |
10 | ast::edit::AstNodeEdit, | 10 | ast::edit::AstNodeEdit, |
@@ -16,10 +16,7 @@ use syntax::{ | |||
16 | SyntaxNode, TextSize, T, | 16 | SyntaxNode, TextSize, T, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}; |
20 | assist_config::SnippetCap, | ||
21 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | ||
22 | }; | ||
23 | 20 | ||
24 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { | 21 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { |
25 | extract_trivial_expression(&block) | 22 | extract_trivial_expression(&block) |
@@ -37,7 +34,7 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { | |||
37 | non_trivial_children.next().is_some() | 34 | non_trivial_children.next().is_some() |
38 | }; | 35 | }; |
39 | 36 | ||
40 | if let Some(expr) = block.expr() { | 37 | if let Some(expr) = block.tail_expr() { |
41 | if has_anything_else(expr.syntax()) { | 38 | if has_anything_else(expr.syntax()) { |
42 | return None; | 39 | return None; |
43 | } | 40 | } |
@@ -94,14 +91,18 @@ pub fn filter_assoc_items( | |||
94 | ast::AssocItem::MacroCall(_) => None, | 91 | ast::AssocItem::MacroCall(_) => None, |
95 | } | 92 | } |
96 | .is_some() | 93 | .is_some() |
97 | }; | 94 | } |
98 | 95 | ||
99 | items | 96 | items |
100 | .iter() | 97 | .iter() |
101 | .map(|i| match i { | 98 | // Note: This throws away items with no source. |
102 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value), | 99 | .filter_map(|i| { |
103 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value), | 100 | let item = match i { |
104 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value), | 101 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db)?.value), |
102 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db)?.value), | ||
103 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db)?.value), | ||
104 | }; | ||
105 | Some(item) | ||
105 | }) | 106 | }) |
106 | .filter(has_def_name) | 107 | .filter(has_def_name) |
107 | .filter(|it| match it { | 108 | .filter(|it| match it { |
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index 66e6443cb..98acd61b1 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -61,7 +61,9 @@ use std::{str::FromStr, sync::Arc}; | |||
61 | 61 | ||
62 | use cfg::CfgOptions; | 62 | use cfg::CfgOptions; |
63 | use rustc_hash::FxHashMap; | 63 | use rustc_hash::FxHashMap; |
64 | use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; | 64 | use test_utils::{ |
65 | extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, | ||
66 | }; | ||
65 | use vfs::{file_set::FileSet, VfsPath}; | 67 | use vfs::{file_set::FileSet, VfsPath}; |
66 | 68 | ||
67 | use crate::{ | 69 | use crate::{ |
@@ -142,10 +144,14 @@ impl ChangeFixture { | |||
142 | 144 | ||
143 | for entry in fixture { | 145 | for entry in fixture { |
144 | let text = if entry.text.contains(CURSOR_MARKER) { | 146 | let text = if entry.text.contains(CURSOR_MARKER) { |
145 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); | 147 | if entry.text.contains(ESCAPED_CURSOR_MARKER) { |
146 | assert!(file_position.is_none()); | 148 | entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER) |
147 | file_position = Some((file_id, range_or_offset)); | 149 | } else { |
148 | text.to_string() | 150 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); |
151 | assert!(file_position.is_none()); | ||
152 | file_position = Some((file_id, range_or_offset)); | ||
153 | text.to_string() | ||
154 | } | ||
149 | } else { | 155 | } else { |
150 | entry.text.clone() | 156 | entry.text.clone() |
151 | }; | 157 | }; |
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index 9567bcc42..2dd8fbe67 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -190,10 +190,11 @@ pub struct CrateData { | |||
190 | pub proc_macro: Vec<ProcMacro>, | 190 | pub proc_macro: Vec<ProcMacro>, |
191 | } | 191 | } |
192 | 192 | ||
193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
194 | pub enum Edition { | 194 | pub enum Edition { |
195 | Edition2018, | ||
196 | Edition2015, | 195 | Edition2015, |
196 | Edition2018, | ||
197 | Edition2021, | ||
197 | } | 198 | } |
198 | 199 | ||
199 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 200 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
@@ -393,6 +394,7 @@ impl FromStr for Edition { | |||
393 | let res = match s { | 394 | let res = match s { |
394 | "2015" => Edition::Edition2015, | 395 | "2015" => Edition::Edition2015, |
395 | "2018" => Edition::Edition2018, | 396 | "2018" => Edition::Edition2018, |
397 | "2021" => Edition::Edition2021, | ||
396 | _ => return Err(ParseEditionError { invalid_input: s.to_string() }), | 398 | _ => return Err(ParseEditionError { invalid_input: s.to_string() }), |
397 | }; | 399 | }; |
398 | Ok(res) | 400 | Ok(res) |
@@ -404,6 +406,7 @@ impl fmt::Display for Edition { | |||
404 | f.write_str(match self { | 406 | f.write_str(match self { |
405 | Edition::Edition2015 => "2015", | 407 | Edition::Edition2015 => "2015", |
406 | Edition::Edition2018 => "2018", | 408 | Edition::Edition2018 => "2018", |
409 | Edition::Edition2021 => "2021", | ||
407 | }) | 410 | }) |
408 | } | 411 | } |
409 | } | 412 | } |
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml index c68e391c1..73247d130 100644 --- a/crates/cfg/Cargo.toml +++ b/crates/cfg/Cargo.toml | |||
@@ -17,4 +17,4 @@ tt = { path = "../tt", version = "0.0.0" } | |||
17 | [dev-dependencies] | 17 | [dev-dependencies] |
18 | mbe = { path = "../mbe" } | 18 | mbe = { path = "../mbe" } |
19 | syntax = { path = "../syntax" } | 19 | syntax = { path = "../syntax" } |
20 | expect-test = "1.0" | 20 | expect-test = "1.1" |
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml index 35e169a28..99a1bdd54 100644 --- a/crates/completion/Cargo.toml +++ b/crates/completion/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | itertools = "0.9.0" | 13 | itertools = "0.10.0" |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | rustc-hash = "1.1.0" | 15 | rustc-hash = "1.1.0" |
16 | either = "1.6.1" | 16 | either = "1.6.1" |
@@ -28,4 +28,4 @@ test_utils = { path = "../test_utils", version = "0.0.0" } | |||
28 | hir = { path = "../hir", version = "0.0.0" } | 28 | hir = { path = "../hir", version = "0.0.0" } |
29 | 29 | ||
30 | [dev-dependencies] | 30 | [dev-dependencies] |
31 | expect-test = "1.0" | 31 | expect-test = "1.1" |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index d9fe13485..00c9e76f0 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -106,8 +106,9 @@ impl Completions { | |||
106 | func: hir::Function, | 106 | func: hir::Function, |
107 | local_name: Option<String>, | 107 | local_name: Option<String>, |
108 | ) { | 108 | ) { |
109 | let item = render_fn(RenderContext::new(ctx), None, local_name, func); | 109 | if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { |
110 | self.add(item) | 110 | self.add(item) |
111 | } | ||
111 | } | 112 | } |
112 | 113 | ||
113 | pub(crate) fn add_variant_pat( | 114 | pub(crate) fn add_variant_pat( |
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs index 19ce2482f..e5522980d 100644 --- a/crates/completion/src/completions/attribute.rs +++ b/crates/completion/src/completions/attribute.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
7 | use rustc_hash::FxHashSet; | 7 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstNode, SyntaxKind}; | 8 | use syntax::{ast, AstNode, T}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | context::CompletionContext, | 11 | context::CompletionContext, |
@@ -21,19 +21,16 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) | |||
21 | 21 | ||
22 | let attribute = ctx.attribute_under_caret.as_ref()?; | 22 | let attribute = ctx.attribute_under_caret.as_ref()?; |
23 | match (attribute.path(), attribute.token_tree()) { | 23 | match (attribute.path(), attribute.token_tree()) { |
24 | (Some(path), Some(token_tree)) if path.to_string() == "derive" => { | 24 | (Some(path), Some(token_tree)) => { |
25 | complete_derive(acc, ctx, token_tree) | 25 | let path = path.syntax().text(); |
26 | } | 26 | if path == "derive" { |
27 | (Some(path), Some(token_tree)) if path.to_string() == "feature" => { | 27 | complete_derive(acc, ctx, token_tree) |
28 | complete_lint(acc, ctx, token_tree, FEATURES); | 28 | } else if path == "feature" { |
29 | } | 29 | complete_lint(acc, ctx, token_tree, FEATURES) |
30 | (Some(path), Some(token_tree)) | 30 | } else if path == "allow" || path == "warn" || path == "deny" || path == "forbid" { |
31 | if ["allow", "warn", "deny", "forbid"] | 31 | complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS); |
32 | .iter() | 32 | complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); |
33 | .any(|lint_level| lint_level == &path.to_string()) => | 33 | } |
34 | { | ||
35 | complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS); | ||
36 | complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); | ||
37 | } | 34 | } |
38 | (_, Some(_token_tree)) => {} | 35 | (_, Some(_token_tree)) => {} |
39 | _ => complete_attribute_start(acc, ctx, attribute), | 36 | _ => complete_attribute_start(acc, ctx, attribute), |
@@ -54,11 +51,8 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr | |||
54 | item = item.lookup_by(lookup); | 51 | item = item.lookup_by(lookup); |
55 | } | 52 | } |
56 | 53 | ||
57 | match (attr_completion.snippet, ctx.config.snippet_cap) { | 54 | if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) { |
58 | (Some(snippet), Some(cap)) => { | 55 | item = item.insert_snippet(cap, snippet); |
59 | item = item.insert_snippet(cap, snippet); | ||
60 | } | ||
61 | _ => {} | ||
62 | } | 56 | } |
63 | 57 | ||
64 | if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner { | 58 | if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner { |
@@ -98,7 +92,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
98 | attr(r#"crate_name = """#, Some("crate_name"), Some(r#"crate_name = "${0:crate_name}""#)) | 92 | attr(r#"crate_name = """#, Some("crate_name"), Some(r#"crate_name = "${0:crate_name}""#)) |
99 | .prefer_inner(), | 93 | .prefer_inner(), |
100 | attr("deny(…)", Some("deny"), Some("deny(${0:lint})")), | 94 | attr("deny(…)", Some("deny"), Some("deny(${0:lint})")), |
101 | attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)), | 95 | attr(r#"deprecated"#, Some("deprecated"), Some(r#"deprecated"#)), |
102 | attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)), | 96 | attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)), |
103 | attr( | 97 | attr( |
104 | r#"export_name = "…""#, | 98 | r#"export_name = "…""#, |
@@ -121,7 +115,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
121 | ), | 115 | ), |
122 | attr("macro_export", None, None), | 116 | attr("macro_export", None, None), |
123 | attr("macro_use", None, None), | 117 | attr("macro_use", None, None), |
124 | attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)), | 118 | attr(r#"must_use"#, Some("must_use"), Some(r#"must_use"#)), |
125 | attr("no_link", None, None).prefer_inner(), | 119 | attr("no_link", None, None).prefer_inner(), |
126 | attr("no_implicit_prelude", None, None).prefer_inner(), | 120 | attr("no_implicit_prelude", None, None).prefer_inner(), |
127 | attr("no_main", None, None).prefer_inner(), | 121 | attr("no_main", None, None).prefer_inner(), |
@@ -136,11 +130,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
136 | attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}")) | 130 | attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}")) |
137 | .prefer_inner(), | 131 | .prefer_inner(), |
138 | attr("repr(…)", Some("repr"), Some("repr(${0:C})")), | 132 | attr("repr(…)", Some("repr"), Some("repr(${0:C})")), |
139 | attr( | 133 | attr("should_panic", Some("should_panic"), Some(r#"should_panic"#)), |
140 | "should_panic(…)", | ||
141 | Some("should_panic"), | ||
142 | Some(r#"should_panic(expected = "${0:reason}")"#), | ||
143 | ), | ||
144 | attr( | 134 | attr( |
145 | r#"target_feature = "…""#, | 135 | r#"target_feature = "…""#, |
146 | Some("target_feature"), | 136 | Some("target_feature"), |
@@ -215,8 +205,7 @@ fn complete_lint( | |||
215 | fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { | 205 | fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { |
216 | match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { | 206 | match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { |
217 | (Some(left_paren), Some(right_paren)) | 207 | (Some(left_paren), Some(right_paren)) |
218 | if left_paren.kind() == SyntaxKind::L_PAREN | 208 | if left_paren.kind() == T!['('] && right_paren.kind() == T![')'] => |
219 | && right_paren.kind() == SyntaxKind::R_PAREN => | ||
220 | { | 209 | { |
221 | let mut input_derives = FxHashSet::default(); | 210 | let mut input_derives = FxHashSet::default(); |
222 | let mut current_derive = String::new(); | 211 | let mut current_derive = String::new(); |
@@ -228,13 +217,13 @@ fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<Strin | |||
228 | .skip(1) | 217 | .skip(1) |
229 | .take_while(|token| token != &right_paren) | 218 | .take_while(|token| token != &right_paren) |
230 | { | 219 | { |
231 | if SyntaxKind::COMMA == token.kind() { | 220 | if T![,] == token.kind() { |
232 | if !current_derive.is_empty() { | 221 | if !current_derive.is_empty() { |
233 | input_derives.insert(current_derive); | 222 | input_derives.insert(current_derive); |
234 | current_derive = String::new(); | 223 | current_derive = String::new(); |
235 | } | 224 | } |
236 | } else { | 225 | } else { |
237 | current_derive.push_str(token.to_string().trim()); | 226 | current_derive.push_str(token.text().trim()); |
238 | } | 227 | } |
239 | } | 228 | } |
240 | 229 | ||
@@ -417,7 +406,7 @@ mod tests { | |||
417 | fn empty_derive_completion() { | 406 | fn empty_derive_completion() { |
418 | check( | 407 | check( |
419 | r#" | 408 | r#" |
420 | #[derive(<|>)] | 409 | #[derive($0)] |
421 | struct Test {} | 410 | struct Test {} |
422 | "#, | 411 | "#, |
423 | expect![[r#" | 412 | expect![[r#" |
@@ -438,7 +427,7 @@ struct Test {} | |||
438 | fn no_completion_for_incorrect_derive() { | 427 | fn no_completion_for_incorrect_derive() { |
439 | check( | 428 | check( |
440 | r#" | 429 | r#" |
441 | #[derive{<|>)] | 430 | #[derive{$0)] |
442 | struct Test {} | 431 | struct Test {} |
443 | "#, | 432 | "#, |
444 | expect![[r#""#]], | 433 | expect![[r#""#]], |
@@ -449,7 +438,7 @@ struct Test {} | |||
449 | fn derive_with_input_completion() { | 438 | fn derive_with_input_completion() { |
450 | check( | 439 | check( |
451 | r#" | 440 | r#" |
452 | #[derive(serde::Serialize, PartialEq, <|>)] | 441 | #[derive(serde::Serialize, PartialEq, $0)] |
453 | struct Test {} | 442 | struct Test {} |
454 | "#, | 443 | "#, |
455 | expect![[r#" | 444 | expect![[r#" |
@@ -468,7 +457,7 @@ struct Test {} | |||
468 | #[test] | 457 | #[test] |
469 | fn test_attribute_completion() { | 458 | fn test_attribute_completion() { |
470 | check( | 459 | check( |
471 | r#"#[<|>]"#, | 460 | r#"#[$0]"#, |
472 | expect![[r#" | 461 | expect![[r#" |
473 | at allow(…) | 462 | at allow(…) |
474 | at automatically_derived | 463 | at automatically_derived |
@@ -476,7 +465,7 @@ struct Test {} | |||
476 | at cfg(…) | 465 | at cfg(…) |
477 | at cold | 466 | at cold |
478 | at deny(…) | 467 | at deny(…) |
479 | at deprecated = "…" | 468 | at deprecated |
480 | at derive(…) | 469 | at derive(…) |
481 | at export_name = "…" | 470 | at export_name = "…" |
482 | at doc = "…" | 471 | at doc = "…" |
@@ -488,7 +477,7 @@ struct Test {} | |||
488 | at link_section = "…" | 477 | at link_section = "…" |
489 | at macro_export | 478 | at macro_export |
490 | at macro_use | 479 | at macro_use |
491 | at must_use = "…" | 480 | at must_use |
492 | at no_mangle | 481 | at no_mangle |
493 | at non_exhaustive | 482 | at non_exhaustive |
494 | at path = "…" | 483 | at path = "…" |
@@ -496,7 +485,7 @@ struct Test {} | |||
496 | at proc_macro_attribute | 485 | at proc_macro_attribute |
497 | at proc_macro_derive(…) | 486 | at proc_macro_derive(…) |
498 | at repr(…) | 487 | at repr(…) |
499 | at should_panic(…) | 488 | at should_panic |
500 | at target_feature = "…" | 489 | at target_feature = "…" |
501 | at test | 490 | at test |
502 | at track_caller | 491 | at track_caller |
@@ -508,13 +497,13 @@ struct Test {} | |||
508 | 497 | ||
509 | #[test] | 498 | #[test] |
510 | fn test_attribute_completion_inside_nested_attr() { | 499 | fn test_attribute_completion_inside_nested_attr() { |
511 | check(r#"#[cfg(<|>)]"#, expect![[]]) | 500 | check(r#"#[cfg($0)]"#, expect![[]]) |
512 | } | 501 | } |
513 | 502 | ||
514 | #[test] | 503 | #[test] |
515 | fn test_inner_attribute_completion() { | 504 | fn test_inner_attribute_completion() { |
516 | check( | 505 | check( |
517 | r"#![<|>]", | 506 | r"#![$0]", |
518 | expect![[r#" | 507 | expect![[r#" |
519 | at allow(…) | 508 | at allow(…) |
520 | at automatically_derived | 509 | at automatically_derived |
@@ -523,7 +512,7 @@ struct Test {} | |||
523 | at cold | 512 | at cold |
524 | at crate_name = "" | 513 | at crate_name = "" |
525 | at deny(…) | 514 | at deny(…) |
526 | at deprecated = "…" | 515 | at deprecated |
527 | at derive(…) | 516 | at derive(…) |
528 | at export_name = "…" | 517 | at export_name = "…" |
529 | at doc = "…" | 518 | at doc = "…" |
@@ -537,7 +526,7 @@ struct Test {} | |||
537 | at link_section = "…" | 526 | at link_section = "…" |
538 | at macro_export | 527 | at macro_export |
539 | at macro_use | 528 | at macro_use |
540 | at must_use = "…" | 529 | at must_use |
541 | at no_link | 530 | at no_link |
542 | at no_implicit_prelude | 531 | at no_implicit_prelude |
543 | at no_main | 532 | at no_main |
@@ -551,7 +540,7 @@ struct Test {} | |||
551 | at proc_macro_derive(…) | 540 | at proc_macro_derive(…) |
552 | at recursion_limit = … | 541 | at recursion_limit = … |
553 | at repr(…) | 542 | at repr(…) |
554 | at should_panic(…) | 543 | at should_panic |
555 | at target_feature = "…" | 544 | at target_feature = "…" |
556 | at test | 545 | at test |
557 | at track_caller | 546 | at track_caller |
diff --git a/crates/completion/src/completions/dot.rs b/crates/completion/src/completions/dot.rs index 551ef1771..d04eef65a 100644 --- a/crates/completion/src/completions/dot.rs +++ b/crates/completion/src/completions/dot.rs | |||
@@ -79,7 +79,7 @@ struct S { foo: u32 } | |||
79 | impl S { | 79 | impl S { |
80 | fn bar(&self) {} | 80 | fn bar(&self) {} |
81 | } | 81 | } |
82 | fn foo(s: S) { s.<|> } | 82 | fn foo(s: S) { s.$0 } |
83 | "#, | 83 | "#, |
84 | expect![[r#" | 84 | expect![[r#" |
85 | fd foo u32 | 85 | fd foo u32 |
@@ -94,7 +94,7 @@ fn foo(s: S) { s.<|> } | |||
94 | r#" | 94 | r#" |
95 | struct S { the_field: (u32,) } | 95 | struct S { the_field: (u32,) } |
96 | impl S { | 96 | impl S { |
97 | fn foo(self) { self.<|> } | 97 | fn foo(self) { self.$0 } |
98 | } | 98 | } |
99 | "#, | 99 | "#, |
100 | expect![[r#" | 100 | expect![[r#" |
@@ -110,7 +110,7 @@ impl S { | |||
110 | r#" | 110 | r#" |
111 | struct A { the_field: (u32, i32) } | 111 | struct A { the_field: (u32, i32) } |
112 | impl A { | 112 | impl A { |
113 | fn foo(&self) { self.<|> } | 113 | fn foo(&self) { self.$0 } |
114 | } | 114 | } |
115 | "#, | 115 | "#, |
116 | expect![[r#" | 116 | expect![[r#" |
@@ -126,7 +126,7 @@ impl A { | |||
126 | check( | 126 | check( |
127 | r#" | 127 | r#" |
128 | struct A { the_field: u32 } | 128 | struct A { the_field: u32 } |
129 | fn foo(a: A) { a.<|>() } | 129 | fn foo(a: A) { a.$0() } |
130 | "#, | 130 | "#, |
131 | expect![[""]], | 131 | expect![[""]], |
132 | ); | 132 | ); |
@@ -144,7 +144,7 @@ mod inner { | |||
144 | pub(crate) super_field: u32, | 144 | pub(crate) super_field: u32, |
145 | } | 145 | } |
146 | } | 146 | } |
147 | fn foo(a: inner::A) { a.<|> } | 147 | fn foo(a: inner::A) { a.$0 } |
148 | "#, | 148 | "#, |
149 | expect![[r#" | 149 | expect![[r#" |
150 | fd pub_field u32 | 150 | fd pub_field u32 |
@@ -162,7 +162,7 @@ mod m { | |||
162 | pub(crate) fn the_method(&self) {} | 162 | pub(crate) fn the_method(&self) {} |
163 | } | 163 | } |
164 | } | 164 | } |
165 | fn foo(a: A) { a.<|> } | 165 | fn foo(a: A) { a.$0 } |
166 | "#, | 166 | "#, |
167 | expect![[r#" | 167 | expect![[r#" |
168 | me the_method() pub(crate) fn the_method(&self) | 168 | me the_method() pub(crate) fn the_method(&self) |
@@ -175,7 +175,7 @@ fn foo(a: A) { a.<|> } | |||
175 | check( | 175 | check( |
176 | r#" | 176 | r#" |
177 | union U { field: u8, other: u16 } | 177 | union U { field: u8, other: u16 } |
178 | fn foo(u: U) { u.<|> } | 178 | fn foo(u: U) { u.$0 } |
179 | "#, | 179 | "#, |
180 | expect![[r#" | 180 | expect![[r#" |
181 | fd field u8 | 181 | fd field u8 |
@@ -195,7 +195,7 @@ impl A<u32> { | |||
195 | impl A<i32> { | 195 | impl A<i32> { |
196 | fn the_other_method(&self) {} | 196 | fn the_other_method(&self) {} |
197 | } | 197 | } |
198 | fn foo(a: A<u32>) { a.<|> } | 198 | fn foo(a: A<u32>) { a.$0 } |
199 | "#, | 199 | "#, |
200 | expect![[r#" | 200 | expect![[r#" |
201 | me the_method() fn the_method(&self) | 201 | me the_method() fn the_method(&self) |
@@ -210,7 +210,7 @@ fn foo(a: A<u32>) { a.<|> } | |||
210 | struct A {} | 210 | struct A {} |
211 | trait Trait { fn the_method(&self); } | 211 | trait Trait { fn the_method(&self); } |
212 | impl Trait for A {} | 212 | impl Trait for A {} |
213 | fn foo(a: A) { a.<|> } | 213 | fn foo(a: A) { a.$0 } |
214 | "#, | 214 | "#, |
215 | expect![[r#" | 215 | expect![[r#" |
216 | me the_method() fn the_method(&self) | 216 | me the_method() fn the_method(&self) |
@@ -225,7 +225,7 @@ fn foo(a: A) { a.<|> } | |||
225 | struct A {} | 225 | struct A {} |
226 | trait Trait { fn the_method(&self); } | 226 | trait Trait { fn the_method(&self); } |
227 | impl<T> Trait for T {} | 227 | impl<T> Trait for T {} |
228 | fn foo(a: &A) { a.<|> } | 228 | fn foo(a: &A) { a.$0 } |
229 | ", | 229 | ", |
230 | expect![[r#" | 230 | expect![[r#" |
231 | me the_method() fn the_method(&self) | 231 | me the_method() fn the_method(&self) |
@@ -243,7 +243,7 @@ mod m { | |||
243 | } | 243 | } |
244 | use m::Trait; | 244 | use m::Trait; |
245 | impl Trait for A {} | 245 | impl Trait for A {} |
246 | fn foo(a: A) { a.<|> } | 246 | fn foo(a: A) { a.$0 } |
247 | ", | 247 | ", |
248 | expect![[r#" | 248 | expect![[r#" |
249 | me the_method() fn the_method(&self) | 249 | me the_method() fn the_method(&self) |
@@ -260,7 +260,7 @@ impl A { | |||
260 | fn the_method() {} | 260 | fn the_method() {} |
261 | } | 261 | } |
262 | fn foo(a: A) { | 262 | fn foo(a: A) { |
263 | a.<|> | 263 | a.$0 |
264 | } | 264 | } |
265 | "#, | 265 | "#, |
266 | expect![[""]], | 266 | expect![[""]], |
@@ -273,7 +273,7 @@ fn foo(a: A) { | |||
273 | r#" | 273 | r#" |
274 | fn foo() { | 274 | fn foo() { |
275 | let b = (0, 3.14); | 275 | let b = (0, 3.14); |
276 | b.<|> | 276 | b.$0 |
277 | } | 277 | } |
278 | "#, | 278 | "#, |
279 | expect![[r#" | 279 | expect![[r#" |
@@ -295,7 +295,7 @@ struct T(S); | |||
295 | impl T { | 295 | impl T { |
296 | fn foo(&self) { | 296 | fn foo(&self) { |
297 | // FIXME: This doesn't work without the trailing `a` as `0.` is a float | 297 | // FIXME: This doesn't work without the trailing `a` as `0.` is a float |
298 | self.0.a<|> | 298 | self.0.a$0 |
299 | } | 299 | } |
300 | } | 300 | } |
301 | "#, | 301 | "#, |
@@ -311,7 +311,7 @@ impl T { | |||
311 | r#" | 311 | r#" |
312 | struct A { the_field: u32 } | 312 | struct A { the_field: u32 } |
313 | const X: u32 = { | 313 | const X: u32 = { |
314 | A { the_field: 92 }.<|> | 314 | A { the_field: 92 }.$0 |
315 | }; | 315 | }; |
316 | "#, | 316 | "#, |
317 | expect![[r#" | 317 | expect![[r#" |
@@ -327,7 +327,7 @@ const X: u32 = { | |||
327 | macro_rules! m { ($e:expr) => { $e } } | 327 | macro_rules! m { ($e:expr) => { $e } } |
328 | struct A { the_field: u32 } | 328 | struct A { the_field: u32 } |
329 | fn foo(a: A) { | 329 | fn foo(a: A) { |
330 | m!(a.x<|>) | 330 | m!(a.x$0) |
331 | } | 331 | } |
332 | "#, | 332 | "#, |
333 | expect![[r#" | 333 | expect![[r#" |
@@ -344,7 +344,7 @@ fn foo(a: A) { | |||
344 | macro_rules! m { ($e:expr) => { $e } } | 344 | macro_rules! m { ($e:expr) => { $e } } |
345 | struct A { the_field: u32 } | 345 | struct A { the_field: u32 } |
346 | fn foo(a: A) { | 346 | fn foo(a: A) { |
347 | m!(a.<|>) | 347 | m!(a.$0) |
348 | } | 348 | } |
349 | "#, | 349 | "#, |
350 | expect![[r#" | 350 | expect![[r#" |
@@ -360,7 +360,7 @@ fn foo(a: A) { | |||
360 | macro_rules! m { ($e:expr) => { $e } } | 360 | macro_rules! m { ($e:expr) => { $e } } |
361 | struct A { the_field: u32 } | 361 | struct A { the_field: u32 } |
362 | fn foo(a: A) { | 362 | fn foo(a: A) { |
363 | m!(m!(m!(a.x<|>))) | 363 | m!(m!(m!(a.x$0))) |
364 | } | 364 | } |
365 | "#, | 365 | "#, |
366 | expect![[r#" | 366 | expect![[r#" |
@@ -373,20 +373,20 @@ fn foo(a: A) { | |||
373 | fn macro_expansion_resilient() { | 373 | fn macro_expansion_resilient() { |
374 | check( | 374 | check( |
375 | r#" | 375 | r#" |
376 | macro_rules! dbg { | 376 | macro_rules! d { |
377 | () => {}; | 377 | () => {}; |
378 | ($val:expr) => { | 378 | ($val:expr) => { |
379 | match $val { tmp => { tmp } } | 379 | match $val { tmp => { tmp } } |
380 | }; | 380 | }; |
381 | // Trailing comma with single argument is ignored | 381 | // Trailing comma with single argument is ignored |
382 | ($val:expr,) => { $crate::dbg!($val) }; | 382 | ($val:expr,) => { $crate::d!($val) }; |
383 | ($($val:expr),+ $(,)?) => { | 383 | ($($val:expr),+ $(,)?) => { |
384 | ($($crate::dbg!($val)),+,) | 384 | ($($crate::d!($val)),+,) |
385 | }; | 385 | }; |
386 | } | 386 | } |
387 | struct A { the_field: u32 } | 387 | struct A { the_field: u32 } |
388 | fn foo(a: A) { | 388 | fn foo(a: A) { |
389 | dbg!(a.<|>) | 389 | d!(a.$0) |
390 | } | 390 | } |
391 | "#, | 391 | "#, |
392 | expect![[r#" | 392 | expect![[r#" |
@@ -405,7 +405,7 @@ impl<T> HashSet<T> { | |||
405 | } | 405 | } |
406 | fn foo() { | 406 | fn foo() { |
407 | let s: HashSet<_>; | 407 | let s: HashSet<_>; |
408 | s.<|> | 408 | s.$0 |
409 | } | 409 | } |
410 | "#, | 410 | "#, |
411 | expect![[r#" | 411 | expect![[r#" |
@@ -421,7 +421,7 @@ fn foo() { | |||
421 | struct S; | 421 | struct S; |
422 | impl S { fn foo(&self) {} } | 422 | impl S { fn foo(&self) {} } |
423 | macro_rules! make_s { () => { S }; } | 423 | macro_rules! make_s { () => { S }; } |
424 | fn main() { make_s!().f<|>; } | 424 | fn main() { make_s!().f$0; } |
425 | "#, | 425 | "#, |
426 | expect![[r#" | 426 | expect![[r#" |
427 | me foo() fn foo(&self) | 427 | me foo() fn foo(&self) |
diff --git a/crates/completion/src/completions/fn_param.rs b/crates/completion/src/completions/fn_param.rs index e777a53c1..5505c3559 100644 --- a/crates/completion/src/completions/fn_param.rs +++ b/crates/completion/src/completions/fn_param.rs | |||
@@ -81,7 +81,7 @@ mod tests { | |||
81 | r#" | 81 | r#" |
82 | fn foo(file_id: FileId) {} | 82 | fn foo(file_id: FileId) {} |
83 | fn bar(file_id: FileId) {} | 83 | fn bar(file_id: FileId) {} |
84 | fn baz(file<|>) {} | 84 | fn baz(file$0) {} |
85 | "#, | 85 | "#, |
86 | expect![[r#" | 86 | expect![[r#" |
87 | bn file_id: FileId | 87 | bn file_id: FileId |
@@ -94,7 +94,7 @@ fn baz(file<|>) {} | |||
94 | check( | 94 | check( |
95 | r#" | 95 | r#" |
96 | fn foo(file_id: FileId) {} | 96 | fn foo(file_id: FileId) {} |
97 | fn baz(file<|>, x: i32) {} | 97 | fn baz(file$0, x: i32) {} |
98 | "#, | 98 | "#, |
99 | expect![[r#" | 99 | expect![[r#" |
100 | bn file_id: FileId | 100 | bn file_id: FileId |
@@ -110,7 +110,7 @@ pub(crate) trait SourceRoot { | |||
110 | pub fn contains(&self, file_id: FileId) -> bool; | 110 | pub fn contains(&self, file_id: FileId) -> bool; |
111 | pub fn module_map(&self) -> &ModuleMap; | 111 | pub fn module_map(&self) -> &ModuleMap; |
112 | pub fn lines(&self, file_id: FileId) -> &LineIndex; | 112 | pub fn lines(&self, file_id: FileId) -> &LineIndex; |
113 | pub fn syntax(&self, file<|>) | 113 | pub fn syntax(&self, file$0) |
114 | } | 114 | } |
115 | "#, | 115 | "#, |
116 | expect![[r#" | 116 | expect![[r#" |
@@ -124,7 +124,7 @@ pub(crate) trait SourceRoot { | |||
124 | check( | 124 | check( |
125 | r#" | 125 | r#" |
126 | fn outer(text: String) { | 126 | fn outer(text: String) { |
127 | fn inner(<|>) | 127 | fn inner($0) |
128 | } | 128 | } |
129 | "#, | 129 | "#, |
130 | expect![[r#" | 130 | expect![[r#" |
diff --git a/crates/completion/src/completions/keyword.rs b/crates/completion/src/completions/keyword.rs index 1859dec70..425a688ff 100644 --- a/crates/completion/src/completions/keyword.rs +++ b/crates/completion/src/completions/keyword.rs | |||
@@ -193,7 +193,7 @@ mod tests { | |||
193 | #[test] | 193 | #[test] |
194 | fn test_keywords_in_use_stmt() { | 194 | fn test_keywords_in_use_stmt() { |
195 | check( | 195 | check( |
196 | r"use <|>", | 196 | r"use $0", |
197 | expect![[r#" | 197 | expect![[r#" |
198 | kw crate:: | 198 | kw crate:: |
199 | kw self | 199 | kw self |
@@ -202,7 +202,7 @@ mod tests { | |||
202 | ); | 202 | ); |
203 | 203 | ||
204 | check( | 204 | check( |
205 | r"use a::<|>", | 205 | r"use a::$0", |
206 | expect![[r#" | 206 | expect![[r#" |
207 | kw self | 207 | kw self |
208 | kw super:: | 208 | kw super:: |
@@ -210,7 +210,7 @@ mod tests { | |||
210 | ); | 210 | ); |
211 | 211 | ||
212 | check( | 212 | check( |
213 | r"use a::{b, <|>}", | 213 | r"use a::{b, $0}", |
214 | expect![[r#" | 214 | expect![[r#" |
215 | kw self | 215 | kw self |
216 | kw super:: | 216 | kw super:: |
@@ -221,7 +221,7 @@ mod tests { | |||
221 | #[test] | 221 | #[test] |
222 | fn test_keywords_at_source_file_level() { | 222 | fn test_keywords_at_source_file_level() { |
223 | check( | 223 | check( |
224 | r"m<|>", | 224 | r"m$0", |
225 | expect![[r#" | 225 | expect![[r#" |
226 | kw fn | 226 | kw fn |
227 | kw use | 227 | kw use |
@@ -245,7 +245,7 @@ mod tests { | |||
245 | #[test] | 245 | #[test] |
246 | fn test_keywords_in_function() { | 246 | fn test_keywords_in_function() { |
247 | check( | 247 | check( |
248 | r"fn quux() { <|> }", | 248 | r"fn quux() { $0 }", |
249 | expect![[r#" | 249 | expect![[r#" |
250 | kw fn | 250 | kw fn |
251 | kw use | 251 | kw use |
@@ -271,7 +271,7 @@ mod tests { | |||
271 | #[test] | 271 | #[test] |
272 | fn test_keywords_inside_block() { | 272 | fn test_keywords_inside_block() { |
273 | check( | 273 | check( |
274 | r"fn quux() { if true { <|> } }", | 274 | r"fn quux() { if true { $0 } }", |
275 | expect![[r#" | 275 | expect![[r#" |
276 | kw fn | 276 | kw fn |
277 | kw use | 277 | kw use |
@@ -297,7 +297,7 @@ mod tests { | |||
297 | #[test] | 297 | #[test] |
298 | fn test_keywords_after_if() { | 298 | fn test_keywords_after_if() { |
299 | check( | 299 | check( |
300 | r#"fn quux() { if true { () } <|> }"#, | 300 | r#"fn quux() { if true { () } $0 }"#, |
301 | expect![[r#" | 301 | expect![[r#" |
302 | kw fn | 302 | kw fn |
303 | kw use | 303 | kw use |
@@ -322,7 +322,7 @@ mod tests { | |||
322 | ); | 322 | ); |
323 | check_edit( | 323 | check_edit( |
324 | "else", | 324 | "else", |
325 | r#"fn quux() { if true { () } <|> }"#, | 325 | r#"fn quux() { if true { () } $0 }"#, |
326 | r#"fn quux() { if true { () } else {$0} }"#, | 326 | r#"fn quux() { if true { () } else {$0} }"#, |
327 | ); | 327 | ); |
328 | } | 328 | } |
@@ -332,7 +332,7 @@ mod tests { | |||
332 | check( | 332 | check( |
333 | r#" | 333 | r#" |
334 | fn quux() -> i32 { | 334 | fn quux() -> i32 { |
335 | match () { () => <|> } | 335 | match () { () => $0 } |
336 | } | 336 | } |
337 | "#, | 337 | "#, |
338 | expect![[r#" | 338 | expect![[r#" |
@@ -350,7 +350,7 @@ fn quux() -> i32 { | |||
350 | #[test] | 350 | #[test] |
351 | fn test_keywords_in_trait_def() { | 351 | fn test_keywords_in_trait_def() { |
352 | check( | 352 | check( |
353 | r"trait My { <|> }", | 353 | r"trait My { $0 }", |
354 | expect![[r#" | 354 | expect![[r#" |
355 | kw fn | 355 | kw fn |
356 | kw const | 356 | kw const |
@@ -363,7 +363,7 @@ fn quux() -> i32 { | |||
363 | #[test] | 363 | #[test] |
364 | fn test_keywords_in_impl_def() { | 364 | fn test_keywords_in_impl_def() { |
365 | check( | 365 | check( |
366 | r"impl My { <|> }", | 366 | r"impl My { $0 }", |
367 | expect![[r#" | 367 | expect![[r#" |
368 | kw fn | 368 | kw fn |
369 | kw const | 369 | kw const |
@@ -378,7 +378,7 @@ fn quux() -> i32 { | |||
378 | #[test] | 378 | #[test] |
379 | fn test_keywords_in_loop() { | 379 | fn test_keywords_in_loop() { |
380 | check( | 380 | check( |
381 | r"fn my() { loop { <|> } }", | 381 | r"fn my() { loop { $0 } }", |
382 | expect![[r#" | 382 | expect![[r#" |
383 | kw fn | 383 | kw fn |
384 | kw use | 384 | kw use |
@@ -406,7 +406,7 @@ fn quux() -> i32 { | |||
406 | #[test] | 406 | #[test] |
407 | fn test_keywords_after_unsafe_in_item_list() { | 407 | fn test_keywords_after_unsafe_in_item_list() { |
408 | check( | 408 | check( |
409 | r"unsafe <|>", | 409 | r"unsafe $0", |
410 | expect![[r#" | 410 | expect![[r#" |
411 | kw fn | 411 | kw fn |
412 | kw trait | 412 | kw trait |
@@ -418,7 +418,7 @@ fn quux() -> i32 { | |||
418 | #[test] | 418 | #[test] |
419 | fn test_keywords_after_unsafe_in_block_expr() { | 419 | fn test_keywords_after_unsafe_in_block_expr() { |
420 | check( | 420 | check( |
421 | r"fn my_fn() { unsafe <|> }", | 421 | r"fn my_fn() { unsafe $0 }", |
422 | expect![[r#" | 422 | expect![[r#" |
423 | kw fn | 423 | kw fn |
424 | kw trait | 424 | kw trait |
@@ -430,19 +430,19 @@ fn quux() -> i32 { | |||
430 | #[test] | 430 | #[test] |
431 | fn test_mut_in_ref_and_in_fn_parameters_list() { | 431 | fn test_mut_in_ref_and_in_fn_parameters_list() { |
432 | check( | 432 | check( |
433 | r"fn my_fn(&<|>) {}", | 433 | r"fn my_fn(&$0) {}", |
434 | expect![[r#" | 434 | expect![[r#" |
435 | kw mut | 435 | kw mut |
436 | "#]], | 436 | "#]], |
437 | ); | 437 | ); |
438 | check( | 438 | check( |
439 | r"fn my_fn(<|>) {}", | 439 | r"fn my_fn($0) {}", |
440 | expect![[r#" | 440 | expect![[r#" |
441 | kw mut | 441 | kw mut |
442 | "#]], | 442 | "#]], |
443 | ); | 443 | ); |
444 | check( | 444 | check( |
445 | r"fn my_fn() { let &<|> }", | 445 | r"fn my_fn() { let &$0 }", |
446 | expect![[r#" | 446 | expect![[r#" |
447 | kw mut | 447 | kw mut |
448 | "#]], | 448 | "#]], |
@@ -452,13 +452,13 @@ fn quux() -> i32 { | |||
452 | #[test] | 452 | #[test] |
453 | fn test_where_keyword() { | 453 | fn test_where_keyword() { |
454 | check( | 454 | check( |
455 | r"trait A <|>", | 455 | r"trait A $0", |
456 | expect![[r#" | 456 | expect![[r#" |
457 | kw where | 457 | kw where |
458 | "#]], | 458 | "#]], |
459 | ); | 459 | ); |
460 | check( | 460 | check( |
461 | r"impl A <|>", | 461 | r"impl A $0", |
462 | expect![[r#" | 462 | expect![[r#" |
463 | kw where | 463 | kw where |
464 | "#]], | 464 | "#]], |
@@ -471,7 +471,7 @@ fn quux() -> i32 { | |||
471 | check( | 471 | check( |
472 | r#" | 472 | r#" |
473 | fn test() { | 473 | fn test() { |
474 | let x = 2; // A comment<|> | 474 | let x = 2; // A comment$0 |
475 | } | 475 | } |
476 | "#, | 476 | "#, |
477 | expect![[""]], | 477 | expect![[""]], |
@@ -479,7 +479,7 @@ fn test() { | |||
479 | check( | 479 | check( |
480 | r#" | 480 | r#" |
481 | /* | 481 | /* |
482 | Some multi-line comment<|> | 482 | Some multi-line comment$0 |
483 | */ | 483 | */ |
484 | "#, | 484 | "#, |
485 | expect![[""]], | 485 | expect![[""]], |
@@ -487,7 +487,7 @@ Some multi-line comment<|> | |||
487 | check( | 487 | check( |
488 | r#" | 488 | r#" |
489 | /// Some doc comment | 489 | /// Some doc comment |
490 | /// let test<|> = 1 | 490 | /// let test$0 = 1 |
491 | "#, | 491 | "#, |
492 | expect![[""]], | 492 | expect![[""]], |
493 | ); | 493 | ); |
@@ -501,7 +501,7 @@ Some multi-line comment<|> | |||
501 | use std::future::*; | 501 | use std::future::*; |
502 | struct A {} | 502 | struct A {} |
503 | impl Future for A {} | 503 | impl Future for A {} |
504 | fn foo(a: A) { a.<|> } | 504 | fn foo(a: A) { a.$0 } |
505 | 505 | ||
506 | //- /std/lib.rs crate:std | 506 | //- /std/lib.rs crate:std |
507 | pub mod future { | 507 | pub mod future { |
@@ -520,7 +520,7 @@ pub mod future { | |||
520 | use std::future::*; | 520 | use std::future::*; |
521 | fn foo() { | 521 | fn foo() { |
522 | let a = async {}; | 522 | let a = async {}; |
523 | a.<|> | 523 | a.$0 |
524 | } | 524 | } |
525 | 525 | ||
526 | //- /std/lib.rs crate:std | 526 | //- /std/lib.rs crate:std |
@@ -540,7 +540,7 @@ pub mod future { | |||
540 | #[test] | 540 | #[test] |
541 | fn after_let() { | 541 | fn after_let() { |
542 | check( | 542 | check( |
543 | r#"fn main() { let _ = <|> }"#, | 543 | r#"fn main() { let _ = $0 }"#, |
544 | expect![[r#" | 544 | expect![[r#" |
545 | kw match | 545 | kw match |
546 | kw while | 546 | kw while |
@@ -557,7 +557,7 @@ pub mod future { | |||
557 | check( | 557 | check( |
558 | r#" | 558 | r#" |
559 | struct Foo { | 559 | struct Foo { |
560 | <|> | 560 | $0 |
561 | pub f: i32, | 561 | pub f: i32, |
562 | } | 562 | } |
563 | "#, | 563 | "#, |
@@ -578,7 +578,7 @@ struct Foo { | |||
578 | } | 578 | } |
579 | fn foo() { | 579 | fn foo() { |
580 | Foo { | 580 | Foo { |
581 | <|> | 581 | $0 |
582 | } | 582 | } |
583 | } | 583 | } |
584 | "#, | 584 | "#, |
@@ -595,7 +595,7 @@ struct Foo { | |||
595 | } | 595 | } |
596 | fn foo() { | 596 | fn foo() { |
597 | Foo { | 597 | Foo { |
598 | f: <|> | 598 | f: $0 |
599 | } | 599 | } |
600 | } | 600 | } |
601 | "#, | 601 | "#, |
diff --git a/crates/completion/src/completions/macro_in_item_position.rs b/crates/completion/src/completions/macro_in_item_position.rs index 82884a181..2be299ac2 100644 --- a/crates/completion/src/completions/macro_in_item_position.rs +++ b/crates/completion/src/completions/macro_in_item_position.rs | |||
@@ -31,7 +31,7 @@ mod tests { | |||
31 | macro_rules! foo { () => {} } | 31 | macro_rules! foo { () => {} } |
32 | fn foo() {} | 32 | fn foo() {} |
33 | 33 | ||
34 | <|> | 34 | $0 |
35 | "#, | 35 | "#, |
36 | expect![[r#" | 36 | expect![[r#" |
37 | ma foo!(…) macro_rules! foo | 37 | ma foo!(…) macro_rules! foo |
diff --git a/crates/completion/src/completions/mod_.rs b/crates/completion/src/completions/mod_.rs index f77864b77..00e951ca9 100644 --- a/crates/completion/src/completions/mod_.rs +++ b/crates/completion/src/completions/mod_.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | //! Completes mod declarations. | 1 | //! Completes mod declarations. |
2 | 2 | ||
3 | use std::iter; | ||
4 | |||
3 | use hir::{Module, ModuleSource}; | 5 | use hir::{Module, ModuleSource}; |
4 | use ide_db::base_db::{SourceDatabaseExt, VfsPath}; | 6 | use ide_db::base_db::{SourceDatabaseExt, VfsPath}; |
5 | use ide_db::RootDatabase; | 7 | use ide_db::RootDatabase; |
@@ -9,12 +11,11 @@ use crate::{CompletionItem, CompletionItemKind}; | |||
9 | 11 | ||
10 | use crate::{context::CompletionContext, item::CompletionKind, Completions}; | 12 | use crate::{context::CompletionContext, item::CompletionKind, Completions}; |
11 | 13 | ||
12 | /// Complete mod declaration, i.e. `mod <|> ;` | 14 | /// Complete mod declaration, i.e. `mod $0 ;` |
13 | pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 15 | pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
14 | let mod_under_caret = match &ctx.mod_declaration_under_caret { | 16 | let mod_under_caret = match &ctx.mod_declaration_under_caret { |
15 | Some(mod_under_caret) if mod_under_caret.item_list().is_some() => return None, | 17 | Some(mod_under_caret) if mod_under_caret.item_list().is_none() => mod_under_caret, |
16 | Some(mod_under_caret) => mod_under_caret, | 18 | _ => return None, |
17 | None => return None, | ||
18 | }; | 19 | }; |
19 | 20 | ||
20 | let _p = profile::span("completion::complete_mod"); | 21 | let _p = profile::span("completion::complete_mod"); |
@@ -49,9 +50,13 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op | |||
49 | .filter_map(|submodule_file| { | 50 | .filter_map(|submodule_file| { |
50 | let submodule_path = source_root.path_for_file(&submodule_file)?; | 51 | let submodule_path = source_root.path_for_file(&submodule_file)?; |
51 | let directory_with_submodule = submodule_path.parent()?; | 52 | let directory_with_submodule = submodule_path.parent()?; |
52 | match submodule_path.name_and_extension()? { | 53 | let (name, ext) = submodule_path.name_and_extension()?; |
53 | ("lib", Some("rs")) | ("main", Some("rs")) => None, | 54 | if ext != Some("rs") { |
54 | ("mod", Some("rs")) => { | 55 | return None; |
56 | } | ||
57 | match name { | ||
58 | "lib" | "main" => None, | ||
59 | "mod" => { | ||
55 | if directory_with_submodule.parent()? == directory_to_look_for_submodules { | 60 | if directory_with_submodule.parent()? == directory_to_look_for_submodules { |
56 | match directory_with_submodule.name_and_extension()? { | 61 | match directory_with_submodule.name_and_extension()? { |
57 | (directory_name, None) => Some(directory_name.to_owned()), | 62 | (directory_name, None) => Some(directory_name.to_owned()), |
@@ -61,9 +66,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op | |||
61 | None | 66 | None |
62 | } | 67 | } |
63 | } | 68 | } |
64 | (file_name, Some("rs")) | 69 | file_name if directory_with_submodule == directory_to_look_for_submodules => { |
65 | if directory_with_submodule == directory_to_look_for_submodules => | ||
66 | { | ||
67 | Some(file_name.to_owned()) | 70 | Some(file_name.to_owned()) |
68 | } | 71 | } |
69 | _ => None, | 72 | _ => None, |
@@ -73,7 +76,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op | |||
73 | .for_each(|submodule_name| { | 76 | .for_each(|submodule_name| { |
74 | let mut label = submodule_name; | 77 | let mut label = submodule_name; |
75 | if mod_under_caret.semicolon_token().is_none() { | 78 | if mod_under_caret.semicolon_token().is_none() { |
76 | label.push(';') | 79 | label.push(';'); |
77 | } | 80 | } |
78 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label) | 81 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label) |
79 | .kind(CompletionItemKind::Module) | 82 | .kind(CompletionItemKind::Module) |
@@ -89,11 +92,13 @@ fn directory_to_look_for_submodules( | |||
89 | module_file_path: &VfsPath, | 92 | module_file_path: &VfsPath, |
90 | ) -> Option<VfsPath> { | 93 | ) -> Option<VfsPath> { |
91 | let directory_with_module_path = module_file_path.parent()?; | 94 | let directory_with_module_path = module_file_path.parent()?; |
92 | let base_directory = match module_file_path.name_and_extension()? { | 95 | let (name, ext) = module_file_path.name_and_extension()?; |
93 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { | 96 | if ext != Some("rs") { |
94 | Some(directory_with_module_path) | 97 | return None; |
95 | } | 98 | } |
96 | (regular_rust_file_name, Some("rs")) => { | 99 | let base_directory = match name { |
100 | "mod" | "lib" | "main" => Some(directory_with_module_path), | ||
101 | regular_rust_file_name => { | ||
97 | if matches!( | 102 | if matches!( |
98 | ( | 103 | ( |
99 | directory_with_module_path | 104 | directory_with_module_path |
@@ -110,37 +115,25 @@ fn directory_to_look_for_submodules( | |||
110 | directory_with_module_path.join(regular_rust_file_name) | 115 | directory_with_module_path.join(regular_rust_file_name) |
111 | } | 116 | } |
112 | } | 117 | } |
113 | _ => None, | ||
114 | }?; | 118 | }?; |
115 | 119 | ||
116 | let mut resulting_path = base_directory; | 120 | module_chain_to_containing_module_file(module, db) |
117 | for module in module_chain_to_containing_module_file(module, db) { | 121 | .into_iter() |
118 | if let Some(name) = module.name(db) { | 122 | .filter_map(|module| module.name(db)) |
119 | resulting_path = resulting_path.join(&name.to_string())?; | 123 | .try_fold(base_directory, |path, name| path.join(&name.to_string())) |
120 | } | ||
121 | } | ||
122 | |||
123 | Some(resulting_path) | ||
124 | } | 124 | } |
125 | 125 | ||
126 | fn module_chain_to_containing_module_file( | 126 | fn module_chain_to_containing_module_file( |
127 | current_module: Module, | 127 | current_module: Module, |
128 | db: &RootDatabase, | 128 | db: &RootDatabase, |
129 | ) -> Vec<Module> { | 129 | ) -> Vec<Module> { |
130 | let mut path = Vec::new(); | 130 | let mut path = |
131 | 131 | iter::successors(Some(current_module), |current_module| current_module.parent(db)) | |
132 | let mut current_module = Some(current_module); | 132 | .take_while(|current_module| { |
133 | while let Some(ModuleSource::Module(_)) = | 133 | matches!(current_module.definition_source(db).value, ModuleSource::Module(_)) |
134 | current_module.map(|module| module.definition_source(db).value) | 134 | }) |
135 | { | 135 | .collect::<Vec<_>>(); |
136 | if let Some(module) = current_module { | 136 | path.reverse(); |
137 | path.insert(0, module); | ||
138 | current_module = module.parent(db); | ||
139 | } else { | ||
140 | current_module = None; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | path | 137 | path |
145 | } | 138 | } |
146 | 139 | ||
@@ -159,7 +152,7 @@ mod tests { | |||
159 | check( | 152 | check( |
160 | r#" | 153 | r#" |
161 | //- /lib.rs | 154 | //- /lib.rs |
162 | mod <|> | 155 | mod $0 |
163 | //- /foo.rs | 156 | //- /foo.rs |
164 | fn foo() {} | 157 | fn foo() {} |
165 | //- /foo/ignored_foo.rs | 158 | //- /foo/ignored_foo.rs |
@@ -181,7 +174,7 @@ mod tests { | |||
181 | check( | 174 | check( |
182 | r#" | 175 | r#" |
183 | //- /lib.rs | 176 | //- /lib.rs |
184 | mod <|> { | 177 | mod $0 { |
185 | 178 | ||
186 | } | 179 | } |
187 | //- /foo.rs | 180 | //- /foo.rs |
@@ -196,7 +189,7 @@ mod tests { | |||
196 | check( | 189 | check( |
197 | r#" | 190 | r#" |
198 | //- /main.rs | 191 | //- /main.rs |
199 | mod <|> | 192 | mod $0 |
200 | //- /foo.rs | 193 | //- /foo.rs |
201 | fn foo() {} | 194 | fn foo() {} |
202 | //- /foo/ignored_foo.rs | 195 | //- /foo/ignored_foo.rs |
@@ -219,7 +212,7 @@ mod tests { | |||
219 | r#" | 212 | r#" |
220 | //- /main.rs | 213 | //- /main.rs |
221 | mod tests { | 214 | mod tests { |
222 | mod <|>; | 215 | mod $0; |
223 | } | 216 | } |
224 | //- /tests/foo.rs | 217 | //- /tests/foo.rs |
225 | fn foo() {} | 218 | fn foo() {} |
@@ -237,7 +230,7 @@ mod tests { | |||
237 | //- /lib.rs | 230 | //- /lib.rs |
238 | mod foo; | 231 | mod foo; |
239 | //- /foo.rs | 232 | //- /foo.rs |
240 | mod <|>; | 233 | mod $0; |
241 | //- /foo/bar.rs | 234 | //- /foo/bar.rs |
242 | fn bar() {} | 235 | fn bar() {} |
243 | //- /foo/bar/ignored_bar.rs | 236 | //- /foo/bar/ignored_bar.rs |
@@ -262,7 +255,7 @@ mod tests { | |||
262 | mod foo; | 255 | mod foo; |
263 | //- /foo.rs | 256 | //- /foo.rs |
264 | mod bar { | 257 | mod bar { |
265 | mod <|> | 258 | mod $0 |
266 | } | 259 | } |
267 | //- /foo/bar/baz.rs | 260 | //- /foo/bar/baz.rs |
268 | fn baz() {} | 261 | fn baz() {} |
@@ -288,7 +281,7 @@ mod tests { | |||
288 | // //- /src/bin.rs | 281 | // //- /src/bin.rs |
289 | // fn main() {} | 282 | // fn main() {} |
290 | // //- /src/bin/foo.rs | 283 | // //- /src/bin/foo.rs |
291 | // mod <|> | 284 | // mod $0 |
292 | // //- /src/bin/bar.rs | 285 | // //- /src/bin/bar.rs |
293 | // fn bar() {} | 286 | // fn bar() {} |
294 | // //- /src/bin/bar/bar_ignored.rs | 287 | // //- /src/bin/bar/bar_ignored.rs |
@@ -307,7 +300,7 @@ mod tests { | |||
307 | //- /src/bin.rs crate:main | 300 | //- /src/bin.rs crate:main |
308 | fn main() {} | 301 | fn main() {} |
309 | //- /src/bin/foo.rs | 302 | //- /src/bin/foo.rs |
310 | mod <|> | 303 | mod $0 |
311 | //- /src/bin/bar.rs | 304 | //- /src/bin/bar.rs |
312 | mod foo; | 305 | mod foo; |
313 | fn bar() {} | 306 | fn bar() {} |
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs index eee31098d..595160ff5 100644 --- a/crates/completion/src/completions/pattern.rs +++ b/crates/completion/src/completions/pattern.rs | |||
@@ -71,7 +71,7 @@ static FOO: E = E::X; | |||
71 | struct Bar { f: u32 } | 71 | struct Bar { f: u32 } |
72 | 72 | ||
73 | fn foo() { | 73 | fn foo() { |
74 | match E::X { <|> } | 74 | match E::X { $0 } |
75 | } | 75 | } |
76 | "#, | 76 | "#, |
77 | expect![[r#" | 77 | expect![[r#" |
@@ -92,7 +92,7 @@ macro_rules! m { ($e:expr) => { $e } } | |||
92 | enum E { X } | 92 | enum E { X } |
93 | 93 | ||
94 | fn foo() { | 94 | fn foo() { |
95 | m!(match E::X { <|> }) | 95 | m!(match E::X { $0 }) |
96 | } | 96 | } |
97 | "#, | 97 | "#, |
98 | expect![[r#" | 98 | expect![[r#" |
@@ -115,7 +115,7 @@ static FOO: E = E::X; | |||
115 | struct Bar { f: u32 } | 115 | struct Bar { f: u32 } |
116 | 116 | ||
117 | fn foo() { | 117 | fn foo() { |
118 | let <|> | 118 | let $0 |
119 | } | 119 | } |
120 | "#, | 120 | "#, |
121 | expect![[r#" | 121 | expect![[r#" |
@@ -133,7 +133,7 @@ enum E { X } | |||
133 | static FOO: E = E::X; | 133 | static FOO: E = E::X; |
134 | struct Bar { f: u32 } | 134 | struct Bar { f: u32 } |
135 | 135 | ||
136 | fn foo(<|>) { | 136 | fn foo($0) { |
137 | } | 137 | } |
138 | "#, | 138 | "#, |
139 | expect![[r#" | 139 | expect![[r#" |
@@ -149,7 +149,7 @@ fn foo(<|>) { | |||
149 | struct Bar { f: u32 } | 149 | struct Bar { f: u32 } |
150 | 150 | ||
151 | fn foo() { | 151 | fn foo() { |
152 | let <|> | 152 | let $0 |
153 | } | 153 | } |
154 | "#, | 154 | "#, |
155 | expect![[r#" | 155 | expect![[r#" |
@@ -165,7 +165,7 @@ fn foo() { | |||
165 | struct Foo { bar: String, baz: String } | 165 | struct Foo { bar: String, baz: String } |
166 | struct Bar(String, String); | 166 | struct Bar(String, String); |
167 | struct Baz; | 167 | struct Baz; |
168 | fn outer(<|>) {} | 168 | fn outer($0) {} |
169 | "#, | 169 | "#, |
170 | expect![[r#" | 170 | expect![[r#" |
171 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | 171 | bn Foo Foo { bar$1, baz$2 }: Foo$0 |
@@ -182,7 +182,7 @@ struct Foo { bar: String, baz: String } | |||
182 | struct Bar(String, String); | 182 | struct Bar(String, String); |
183 | struct Baz; | 183 | struct Baz; |
184 | fn outer() { | 184 | fn outer() { |
185 | let <|> | 185 | let $0 |
186 | } | 186 | } |
187 | "#, | 187 | "#, |
188 | expect![[r#" | 188 | expect![[r#" |
@@ -201,7 +201,7 @@ struct Bar(String, String); | |||
201 | struct Baz; | 201 | struct Baz; |
202 | fn outer() { | 202 | fn outer() { |
203 | match () { | 203 | match () { |
204 | <|> | 204 | $0 |
205 | } | 205 | } |
206 | } | 206 | } |
207 | "#, | 207 | "#, |
@@ -225,7 +225,7 @@ use foo::*; | |||
225 | 225 | ||
226 | fn outer() { | 226 | fn outer() { |
227 | match () { | 227 | match () { |
228 | <|> | 228 | $0 |
229 | } | 229 | } |
230 | } | 230 | } |
231 | "#, | 231 | "#, |
@@ -244,7 +244,7 @@ fn outer() { | |||
244 | struct Foo(i32); | 244 | struct Foo(i32); |
245 | fn main() { | 245 | fn main() { |
246 | match Foo(92) { | 246 | match Foo(92) { |
247 | <|>(92) => (), | 247 | $0(92) => (), |
248 | } | 248 | } |
249 | } | 249 | } |
250 | "#, | 250 | "#, |
diff --git a/crates/completion/src/completions/postfix.rs b/crates/completion/src/completions/postfix.rs index 3883d6d21..9c34ed0b6 100644 --- a/crates/completion/src/completions/postfix.rs +++ b/crates/completion/src/completions/postfix.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! Postfix completions, like `Ok(10).ifl<|>` => `if let Ok() = Ok(10) { <|> }`. | 1 | //! Postfix completions, like `Ok(10).ifl$0` => `if let Ok() = Ok(10) { $0 }`. |
2 | 2 | ||
3 | mod format_like; | 3 | mod format_like; |
4 | 4 | ||
5 | use ide_db::ty_filter::TryEnum; | 5 | use ide_db::{helpers::SnippetCap, ty_filter::TryEnum}; |
6 | use syntax::{ | 6 | use syntax::{ |
7 | ast::{self, AstNode, AstToken}, | 7 | ast::{self, AstNode, AstToken}, |
8 | SyntaxKind::{BLOCK_EXPR, EXPR_STMT}, | 8 | SyntaxKind::{BLOCK_EXPR, EXPR_STMT}, |
@@ -10,9 +10,8 @@ use syntax::{ | |||
10 | }; | 10 | }; |
11 | use text_edit::TextEdit; | 11 | use text_edit::TextEdit; |
12 | 12 | ||
13 | use self::format_like::add_format_like_completions; | ||
14 | use crate::{ | 13 | use crate::{ |
15 | config::SnippetCap, | 14 | completions::postfix::format_like::add_format_like_completions, |
16 | context::CompletionContext, | 15 | context::CompletionContext, |
17 | item::{Builder, CompletionKind}, | 16 | item::{Builder, CompletionKind}, |
18 | CompletionItem, CompletionItemKind, Completions, | 17 | CompletionItem, CompletionItemKind, Completions, |
@@ -36,11 +35,14 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
36 | None => return, | 35 | None => return, |
37 | }; | 36 | }; |
38 | 37 | ||
38 | let ref_removed_ty = | ||
39 | std::iter::successors(Some(receiver_ty.clone()), |ty| ty.remove_ref()).last().unwrap(); | ||
40 | |||
39 | let cap = match ctx.config.snippet_cap { | 41 | let cap = match ctx.config.snippet_cap { |
40 | Some(it) => it, | 42 | Some(it) => it, |
41 | None => return, | 43 | None => return, |
42 | }; | 44 | }; |
43 | let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty); | 45 | let try_enum = TryEnum::from_ty(&ctx.sema, &ref_removed_ty); |
44 | if let Some(try_enum) = &try_enum { | 46 | if let Some(try_enum) = &try_enum { |
45 | match try_enum { | 47 | match try_enum { |
46 | TryEnum::Result => { | 48 | TryEnum::Result => { |
@@ -311,7 +313,7 @@ mod tests { | |||
311 | r#" | 313 | r#" |
312 | fn main() { | 314 | fn main() { |
313 | let bar = true; | 315 | let bar = true; |
314 | bar.<|> | 316 | bar.$0 |
315 | } | 317 | } |
316 | "#, | 318 | "#, |
317 | expect![[r#" | 319 | expect![[r#" |
@@ -343,7 +345,7 @@ fn foo(elt: bool) -> bool { | |||
343 | 345 | ||
344 | fn main() { | 346 | fn main() { |
345 | let bar = true; | 347 | let bar = true; |
346 | foo(bar.<|>) | 348 | foo(bar.$0) |
347 | } | 349 | } |
348 | "#, | 350 | "#, |
349 | expect![[r#" | 351 | expect![[r#" |
@@ -369,7 +371,7 @@ fn main() { | |||
369 | r#" | 371 | r#" |
370 | fn main() { | 372 | fn main() { |
371 | let bar: u8 = 12; | 373 | let bar: u8 = 12; |
372 | bar.<|> | 374 | bar.$0 |
373 | } | 375 | } |
374 | "#, | 376 | "#, |
375 | expect![[r#" | 377 | expect![[r#" |
@@ -393,7 +395,7 @@ fn main() { | |||
393 | check( | 395 | check( |
394 | r#" | 396 | r#" |
395 | fn main() { | 397 | fn main() { |
396 | baz.l<|> | 398 | baz.l$0 |
397 | res | 399 | res |
398 | } | 400 | } |
399 | "#, | 401 | "#, |
@@ -425,7 +427,7 @@ enum Option<T> { Some(T), None } | |||
425 | 427 | ||
426 | fn main() { | 428 | fn main() { |
427 | let bar = Option::Some(true); | 429 | let bar = Option::Some(true); |
428 | bar.<|> | 430 | bar.$0 |
429 | } | 431 | } |
430 | "#, | 432 | "#, |
431 | r#" | 433 | r#" |
@@ -450,7 +452,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
450 | 452 | ||
451 | fn main() { | 453 | fn main() { |
452 | let bar = Result::Ok(true); | 454 | let bar = Result::Ok(true); |
453 | bar.<|> | 455 | bar.$0 |
454 | } | 456 | } |
455 | "#, | 457 | "#, |
456 | r#" | 458 | r#" |
@@ -469,7 +471,7 @@ fn main() { | |||
469 | 471 | ||
470 | #[test] | 472 | #[test] |
471 | fn postfix_completion_works_for_ambiguous_float_literal() { | 473 | fn postfix_completion_works_for_ambiguous_float_literal() { |
472 | check_edit("refm", r#"fn main() { 42.<|> }"#, r#"fn main() { &mut 42 }"#) | 474 | check_edit("refm", r#"fn main() { 42.$0 }"#, r#"fn main() { &mut 42 }"#) |
473 | } | 475 | } |
474 | 476 | ||
475 | #[test] | 477 | #[test] |
@@ -480,7 +482,7 @@ fn main() { | |||
480 | macro_rules! m { ($e:expr) => { $e } } | 482 | macro_rules! m { ($e:expr) => { $e } } |
481 | fn main() { | 483 | fn main() { |
482 | let bar: u8 = 12; | 484 | let bar: u8 = 12; |
483 | m!(bar.d<|>) | 485 | m!(bar.d$0) |
484 | } | 486 | } |
485 | "#, | 487 | "#, |
486 | r#" | 488 | r#" |
@@ -495,55 +497,68 @@ fn main() { | |||
495 | 497 | ||
496 | #[test] | 498 | #[test] |
497 | fn postfix_completion_for_references() { | 499 | fn postfix_completion_for_references() { |
498 | check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#); | 500 | check_edit("dbg", r#"fn main() { &&42.$0 }"#, r#"fn main() { dbg!(&&42) }"#); |
499 | check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#); | 501 | check_edit("refm", r#"fn main() { &&42.$0 }"#, r#"fn main() { &&&mut 42 }"#); |
502 | check_edit( | ||
503 | "ifl", | ||
504 | r#" | ||
505 | enum Option<T> { Some(T), None } | ||
506 | |||
507 | fn main() { | ||
508 | let bar = &Option::Some(true); | ||
509 | bar.$0 | ||
510 | } | ||
511 | "#, | ||
512 | r#" | ||
513 | enum Option<T> { Some(T), None } | ||
514 | |||
515 | fn main() { | ||
516 | let bar = &Option::Some(true); | ||
517 | if let Some($1) = bar { | ||
518 | $0 | ||
519 | } | ||
520 | } | ||
521 | "#, | ||
522 | ) | ||
500 | } | 523 | } |
501 | 524 | ||
502 | #[test] | 525 | #[test] |
503 | fn postfix_completion_for_format_like_strings() { | 526 | fn postfix_completion_for_format_like_strings() { |
504 | check_edit( | 527 | check_edit( |
505 | "format", | 528 | "format", |
506 | r#"fn main() { "{some_var:?}".<|> }"#, | 529 | r#"fn main() { "{some_var:?}".$0 }"#, |
507 | r#"fn main() { format!("{:?}", some_var) }"#, | 530 | r#"fn main() { format!("{:?}", some_var) }"#, |
508 | ); | 531 | ); |
509 | check_edit( | 532 | check_edit( |
510 | "panic", | 533 | "panic", |
511 | r#"fn main() { "Panic with {a}".<|> }"#, | 534 | r#"fn main() { "Panic with {a}".$0 }"#, |
512 | r#"fn main() { panic!("Panic with {}", a) }"#, | 535 | r#"fn main() { panic!("Panic with {}", a) }"#, |
513 | ); | 536 | ); |
514 | check_edit( | 537 | check_edit( |
515 | "println", | 538 | "println", |
516 | r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".<|> }"#, | 539 | r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"#, |
517 | r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#, | 540 | r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#, |
518 | ); | 541 | ); |
519 | check_edit( | 542 | check_edit( |
520 | "loge", | 543 | "loge", |
521 | r#"fn main() { "{2+2}".<|> }"#, | 544 | r#"fn main() { "{2+2}".$0 }"#, |
522 | r#"fn main() { log::error!("{}", 2+2) }"#, | 545 | r#"fn main() { log::error!("{}", 2+2) }"#, |
523 | ); | 546 | ); |
524 | check_edit( | 547 | check_edit( |
525 | "logt", | 548 | "logt", |
526 | r#"fn main() { "{2+2}".<|> }"#, | 549 | r#"fn main() { "{2+2}".$0 }"#, |
527 | r#"fn main() { log::trace!("{}", 2+2) }"#, | 550 | r#"fn main() { log::trace!("{}", 2+2) }"#, |
528 | ); | 551 | ); |
529 | check_edit( | 552 | check_edit( |
530 | "logd", | 553 | "logd", |
531 | r#"fn main() { "{2+2}".<|> }"#, | 554 | r#"fn main() { "{2+2}".$0 }"#, |
532 | r#"fn main() { log::debug!("{}", 2+2) }"#, | 555 | r#"fn main() { log::debug!("{}", 2+2) }"#, |
533 | ); | 556 | ); |
534 | check_edit( | 557 | check_edit("logi", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::info!("{}", 2+2) }"#); |
535 | "logi", | 558 | check_edit("logw", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::warn!("{}", 2+2) }"#); |
536 | r#"fn main() { "{2+2}".<|> }"#, | ||
537 | r#"fn main() { log::info!("{}", 2+2) }"#, | ||
538 | ); | ||
539 | check_edit( | ||
540 | "logw", | ||
541 | r#"fn main() { "{2+2}".<|> }"#, | ||
542 | r#"fn main() { log::warn!("{}", 2+2) }"#, | ||
543 | ); | ||
544 | check_edit( | 559 | check_edit( |
545 | "loge", | 560 | "loge", |
546 | r#"fn main() { "{2+2}".<|> }"#, | 561 | r#"fn main() { "{2+2}".$0 }"#, |
547 | r#"fn main() { log::error!("{}", 2+2) }"#, | 562 | r#"fn main() { log::error!("{}", 2+2) }"#, |
548 | ); | 563 | ); |
549 | } | 564 | } |
diff --git a/crates/completion/src/completions/postfix/format_like.rs b/crates/completion/src/completions/postfix/format_like.rs index def4b13fb..3afc63021 100644 --- a/crates/completion/src/completions/postfix/format_like.rs +++ b/crates/completion/src/completions/postfix/format_like.rs | |||
@@ -14,12 +14,11 @@ | |||
14 | // + `logw` -> `log::warn!(...)` | 14 | // + `logw` -> `log::warn!(...)` |
15 | // + `loge` -> `log::error!(...)` | 15 | // + `loge` -> `log::error!(...)` |
16 | 16 | ||
17 | use crate::{ | 17 | use ide_db::helpers::SnippetCap; |
18 | completions::postfix::postfix_snippet, config::SnippetCap, context::CompletionContext, | ||
19 | Completions, | ||
20 | }; | ||
21 | use syntax::ast::{self, AstToken}; | 18 | use syntax::ast::{self, AstToken}; |
22 | 19 | ||
20 | use crate::{completions::postfix::postfix_snippet, context::CompletionContext, Completions}; | ||
21 | |||
23 | /// Mapping ("postfix completion item" => "macro to use") | 22 | /// Mapping ("postfix completion item" => "macro to use") |
24 | static KINDS: &[(&str, &str)] = &[ | 23 | static KINDS: &[(&str, &str)] = &[ |
25 | ("format", "format!"), | 24 | ("format", "format!"), |
diff --git a/crates/completion/src/completions/qualified_path.rs b/crates/completion/src/completions/qualified_path.rs index 882c4dcbc..fa9e6e810 100644 --- a/crates/completion/src/completions/qualified_path.rs +++ b/crates/completion/src/completions/qualified_path.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! Completion of paths, i.e. `some::prefix::<|>`. | 1 | //! Completion of paths, i.e. `some::prefix::$0`. |
2 | 2 | ||
3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; | 3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
@@ -38,7 +38,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
38 | if let ScopeDef::Unknown = def { | 38 | if let ScopeDef::Unknown = def { |
39 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | 39 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { |
40 | if name_ref.syntax().text() == name.to_string().as_str() { | 40 | if name_ref.syntax().text() == name.to_string().as_str() { |
41 | // for `use self::foo<|>`, don't suggest `foo` as a completion | 41 | // for `use self::foo$0`, don't suggest `foo` as a completion |
42 | mark::hit!(dont_complete_current_use); | 42 | mark::hit!(dont_complete_current_use); |
43 | continue; | 43 | continue; |
44 | } | 44 | } |
@@ -173,7 +173,7 @@ mod tests { | |||
173 | #[test] | 173 | #[test] |
174 | fn dont_complete_current_use() { | 174 | fn dont_complete_current_use() { |
175 | mark::check!(dont_complete_current_use); | 175 | mark::check!(dont_complete_current_use); |
176 | check(r#"use self::foo<|>;"#, expect![[""]]); | 176 | check(r#"use self::foo$0;"#, expect![[""]]); |
177 | } | 177 | } |
178 | 178 | ||
179 | #[test] | 179 | #[test] |
@@ -181,7 +181,7 @@ mod tests { | |||
181 | check( | 181 | check( |
182 | r#" | 182 | r#" |
183 | mod foo { pub struct S; } | 183 | mod foo { pub struct S; } |
184 | use self::{foo::*, bar<|>}; | 184 | use self::{foo::*, bar$0}; |
185 | "#, | 185 | "#, |
186 | expect![[r#" | 186 | expect![[r#" |
187 | st S | 187 | st S |
@@ -192,18 +192,18 @@ use self::{foo::*, bar<|>}; | |||
192 | 192 | ||
193 | #[test] | 193 | #[test] |
194 | fn dont_complete_primitive_in_use() { | 194 | fn dont_complete_primitive_in_use() { |
195 | check_builtin(r#"use self::<|>;"#, expect![[""]]); | 195 | check_builtin(r#"use self::$0;"#, expect![[""]]); |
196 | } | 196 | } |
197 | 197 | ||
198 | #[test] | 198 | #[test] |
199 | fn dont_complete_primitive_in_module_scope() { | 199 | fn dont_complete_primitive_in_module_scope() { |
200 | check_builtin(r#"fn foo() { self::<|> }"#, expect![[""]]); | 200 | check_builtin(r#"fn foo() { self::$0 }"#, expect![[""]]); |
201 | } | 201 | } |
202 | 202 | ||
203 | #[test] | 203 | #[test] |
204 | fn completes_primitives() { | 204 | fn completes_primitives() { |
205 | check_builtin( | 205 | check_builtin( |
206 | r#"fn main() { let _: <|> = 92; }"#, | 206 | r#"fn main() { let _: $0 = 92; }"#, |
207 | expect![[r#" | 207 | expect![[r#" |
208 | bt u32 | 208 | bt u32 |
209 | bt bool | 209 | bt bool |
@@ -230,7 +230,7 @@ use self::{foo::*, bar<|>}; | |||
230 | fn completes_mod_with_same_name_as_function() { | 230 | fn completes_mod_with_same_name_as_function() { |
231 | check( | 231 | check( |
232 | r#" | 232 | r#" |
233 | use self::my::<|>; | 233 | use self::my::$0; |
234 | 234 | ||
235 | mod my { pub struct Bar; } | 235 | mod my { pub struct Bar; } |
236 | fn my() {} | 236 | fn my() {} |
@@ -245,7 +245,7 @@ fn my() {} | |||
245 | fn filters_visibility() { | 245 | fn filters_visibility() { |
246 | check( | 246 | check( |
247 | r#" | 247 | r#" |
248 | use self::my::<|>; | 248 | use self::my::$0; |
249 | 249 | ||
250 | mod my { | 250 | mod my { |
251 | struct Bar; | 251 | struct Bar; |
@@ -264,7 +264,7 @@ mod my { | |||
264 | fn completes_use_item_starting_with_self() { | 264 | fn completes_use_item_starting_with_self() { |
265 | check( | 265 | check( |
266 | r#" | 266 | r#" |
267 | use self::m::<|>; | 267 | use self::m::$0; |
268 | 268 | ||
269 | mod m { pub struct Bar; } | 269 | mod m { pub struct Bar; } |
270 | "#, | 270 | "#, |
@@ -282,7 +282,7 @@ mod m { pub struct Bar; } | |||
282 | mod foo; | 282 | mod foo; |
283 | struct Spam; | 283 | struct Spam; |
284 | //- /foo.rs | 284 | //- /foo.rs |
285 | use crate::Sp<|> | 285 | use crate::Sp$0 |
286 | "#, | 286 | "#, |
287 | expect![[r#" | 287 | expect![[r#" |
288 | md foo | 288 | md foo |
@@ -299,7 +299,7 @@ use crate::Sp<|> | |||
299 | mod foo; | 299 | mod foo; |
300 | struct Spam; | 300 | struct Spam; |
301 | //- /foo.rs | 301 | //- /foo.rs |
302 | use crate::{Sp<|>}; | 302 | use crate::{Sp$0}; |
303 | "#, | 303 | "#, |
304 | expect![[r#" | 304 | expect![[r#" |
305 | md foo | 305 | md foo |
@@ -320,7 +320,7 @@ pub mod bar { | |||
320 | } | 320 | } |
321 | } | 321 | } |
322 | //- /foo.rs | 322 | //- /foo.rs |
323 | use crate::{bar::{baz::Sp<|>}}; | 323 | use crate::{bar::{baz::Sp$0}}; |
324 | "#, | 324 | "#, |
325 | expect![[r#" | 325 | expect![[r#" |
326 | st Spam | 326 | st Spam |
@@ -333,7 +333,7 @@ use crate::{bar::{baz::Sp<|>}}; | |||
333 | check( | 333 | check( |
334 | r#" | 334 | r#" |
335 | enum E { Foo, Bar(i32) } | 335 | enum E { Foo, Bar(i32) } |
336 | fn foo() { let _ = E::<|> } | 336 | fn foo() { let _ = E::$0 } |
337 | "#, | 337 | "#, |
338 | expect![[r#" | 338 | expect![[r#" |
339 | ev Foo () | 339 | ev Foo () |
@@ -356,7 +356,7 @@ impl S { | |||
356 | type T = i32; | 356 | type T = i32; |
357 | } | 357 | } |
358 | 358 | ||
359 | fn foo() { let _ = S::<|> } | 359 | fn foo() { let _ = S::$0 } |
360 | "#, | 360 | "#, |
361 | expect![[r#" | 361 | expect![[r#" |
362 | fn a() fn a() | 362 | fn a() fn a() |
@@ -384,7 +384,7 @@ mod m { | |||
384 | } | 384 | } |
385 | } | 385 | } |
386 | 386 | ||
387 | fn foo() { let _ = S::<|> } | 387 | fn foo() { let _ = S::$0 } |
388 | "#, | 388 | "#, |
389 | expect![[r#" | 389 | expect![[r#" |
390 | fn public_method() pub(crate) fn public_method() | 390 | fn public_method() pub(crate) fn public_method() |
@@ -401,7 +401,7 @@ fn foo() { let _ = S::<|> } | |||
401 | enum E {}; | 401 | enum E {}; |
402 | impl E { fn m() { } } | 402 | impl E { fn m() { } } |
403 | 403 | ||
404 | fn foo() { let _ = E::<|> } | 404 | fn foo() { let _ = E::$0 } |
405 | "#, | 405 | "#, |
406 | expect![[r#" | 406 | expect![[r#" |
407 | fn m() fn m() | 407 | fn m() fn m() |
@@ -416,7 +416,7 @@ fn foo() { let _ = E::<|> } | |||
416 | union U {}; | 416 | union U {}; |
417 | impl U { fn m() { } } | 417 | impl U { fn m() { } } |
418 | 418 | ||
419 | fn foo() { let _ = U::<|> } | 419 | fn foo() { let _ = U::$0 } |
420 | "#, | 420 | "#, |
421 | expect![[r#" | 421 | expect![[r#" |
422 | fn m() fn m() | 422 | fn m() fn m() |
@@ -429,7 +429,7 @@ fn foo() { let _ = U::<|> } | |||
429 | check( | 429 | check( |
430 | r#" | 430 | r#" |
431 | //- /main.rs crate:main deps:foo | 431 | //- /main.rs crate:main deps:foo |
432 | use foo::<|>; | 432 | use foo::$0; |
433 | 433 | ||
434 | //- /foo/lib.rs crate:foo | 434 | //- /foo/lib.rs crate:foo |
435 | pub mod bar { pub struct S; } | 435 | pub mod bar { pub struct S; } |
@@ -446,7 +446,7 @@ pub mod bar { pub struct S; } | |||
446 | r#" | 446 | r#" |
447 | trait Trait { fn m(); } | 447 | trait Trait { fn m(); } |
448 | 448 | ||
449 | fn foo() { let _ = Trait::<|> } | 449 | fn foo() { let _ = Trait::$0 } |
450 | "#, | 450 | "#, |
451 | expect![[r#" | 451 | expect![[r#" |
452 | fn m() fn m() | 452 | fn m() fn m() |
@@ -463,7 +463,7 @@ trait Trait { fn m(); } | |||
463 | struct S; | 463 | struct S; |
464 | impl Trait for S {} | 464 | impl Trait for S {} |
465 | 465 | ||
466 | fn foo() { let _ = S::<|> } | 466 | fn foo() { let _ = S::$0 } |
467 | "#, | 467 | "#, |
468 | expect![[r#" | 468 | expect![[r#" |
469 | fn m() fn m() | 469 | fn m() fn m() |
@@ -480,7 +480,7 @@ trait Trait { fn m(); } | |||
480 | struct S; | 480 | struct S; |
481 | impl Trait for S {} | 481 | impl Trait for S {} |
482 | 482 | ||
483 | fn foo() { let _ = <S as Trait>::<|> } | 483 | fn foo() { let _ = <S as Trait>::$0 } |
484 | "#, | 484 | "#, |
485 | expect![[r#" | 485 | expect![[r#" |
486 | fn m() fn m() | 486 | fn m() fn m() |
@@ -506,7 +506,7 @@ trait Sub: Super { | |||
506 | fn submethod(&self) {} | 506 | fn submethod(&self) {} |
507 | } | 507 | } |
508 | 508 | ||
509 | fn foo<T: Sub>() { T::<|> } | 509 | fn foo<T: Sub>() { T::$0 } |
510 | "#, | 510 | "#, |
511 | expect![[r#" | 511 | expect![[r#" |
512 | ta SubTy type SubTy; | 512 | ta SubTy type SubTy; |
@@ -544,7 +544,7 @@ impl<T> Super for Wrap<T> {} | |||
544 | impl<T> Sub for Wrap<T> { | 544 | impl<T> Sub for Wrap<T> { |
545 | fn subfunc() { | 545 | fn subfunc() { |
546 | // Should be able to assume `Self: Sub + Super` | 546 | // Should be able to assume `Self: Sub + Super` |
547 | Self::<|> | 547 | Self::$0 |
548 | } | 548 | } |
549 | } | 549 | } |
550 | "#, | 550 | "#, |
@@ -570,7 +570,7 @@ impl S { fn foo() {} } | |||
570 | type T = S; | 570 | type T = S; |
571 | impl T { fn bar() {} } | 571 | impl T { fn bar() {} } |
572 | 572 | ||
573 | fn main() { T::<|>; } | 573 | fn main() { T::$0; } |
574 | "#, | 574 | "#, |
575 | expect![[r#" | 575 | expect![[r#" |
576 | fn foo() fn foo() | 576 | fn foo() fn foo() |
@@ -586,7 +586,7 @@ fn main() { T::<|>; } | |||
586 | #[macro_export] | 586 | #[macro_export] |
587 | macro_rules! foo { () => {} } | 587 | macro_rules! foo { () => {} } |
588 | 588 | ||
589 | fn main() { let _ = crate::<|> } | 589 | fn main() { let _ = crate::$0 } |
590 | "#, | 590 | "#, |
591 | expect![[r##" | 591 | expect![[r##" |
592 | fn main() fn main() | 592 | fn main() fn main() |
@@ -604,7 +604,7 @@ mod a { | |||
604 | const A: usize = 0; | 604 | const A: usize = 0; |
605 | mod b { | 605 | mod b { |
606 | const B: usize = 0; | 606 | const B: usize = 0; |
607 | mod c { use super::super::<|> } | 607 | mod c { use super::super::$0 } |
608 | } | 608 | } |
609 | } | 609 | } |
610 | "#, | 610 | "#, |
@@ -619,7 +619,7 @@ mod a { | |||
619 | fn completes_reexported_items_under_correct_name() { | 619 | fn completes_reexported_items_under_correct_name() { |
620 | check( | 620 | check( |
621 | r#" | 621 | r#" |
622 | fn foo() { self::m::<|> } | 622 | fn foo() { self::m::$0 } |
623 | 623 | ||
624 | mod m { | 624 | mod m { |
625 | pub use super::p::wrong_fn as right_fn; | 625 | pub use super::p::wrong_fn as right_fn; |
@@ -642,7 +642,7 @@ mod p { | |||
642 | check_edit( | 642 | check_edit( |
643 | "RightType", | 643 | "RightType", |
644 | r#" | 644 | r#" |
645 | fn foo() { self::m::<|> } | 645 | fn foo() { self::m::$0 } |
646 | 646 | ||
647 | mod m { | 647 | mod m { |
648 | pub use super::p::wrong_fn as right_fn; | 648 | pub use super::p::wrong_fn as right_fn; |
@@ -677,7 +677,7 @@ mod p { | |||
677 | check( | 677 | check( |
678 | r#" | 678 | r#" |
679 | macro_rules! m { ($e:expr) => { $e } } | 679 | macro_rules! m { ($e:expr) => { $e } } |
680 | fn main() { m!(self::f<|>); } | 680 | fn main() { m!(self::f$0); } |
681 | fn foo() {} | 681 | fn foo() {} |
682 | "#, | 682 | "#, |
683 | expect![[r#" | 683 | expect![[r#" |
@@ -691,7 +691,7 @@ fn foo() {} | |||
691 | fn function_mod_share_name() { | 691 | fn function_mod_share_name() { |
692 | check( | 692 | check( |
693 | r#" | 693 | r#" |
694 | fn foo() { self::m::<|> } | 694 | fn foo() { self::m::$0 } |
695 | 695 | ||
696 | mod m { | 696 | mod m { |
697 | pub mod z {} | 697 | pub mod z {} |
@@ -716,7 +716,7 @@ impl<K, V> HashMap<K, V, RandomState> { | |||
716 | pub fn new() -> HashMap<K, V, RandomState> { } | 716 | pub fn new() -> HashMap<K, V, RandomState> { } |
717 | } | 717 | } |
718 | fn foo() { | 718 | fn foo() { |
719 | HashMap::<|> | 719 | HashMap::$0 |
720 | } | 720 | } |
721 | "#, | 721 | "#, |
722 | expect![[r#" | 722 | expect![[r#" |
@@ -730,7 +730,7 @@ fn foo() { | |||
730 | check( | 730 | check( |
731 | r#" | 731 | r#" |
732 | mod foo { pub struct Foo; } | 732 | mod foo { pub struct Foo; } |
733 | #[foo::<|>] | 733 | #[foo::$0] |
734 | fn f() {} | 734 | fn f() {} |
735 | "#, | 735 | "#, |
736 | expect![[""]], | 736 | expect![[""]], |
@@ -749,7 +749,7 @@ fn foo( | |||
749 | } | 749 | } |
750 | 750 | ||
751 | fn main() { | 751 | fn main() { |
752 | fo<|> | 752 | fo$0 |
753 | } | 753 | } |
754 | "#, | 754 | "#, |
755 | expect![[r#" | 755 | expect![[r#" |
@@ -770,7 +770,7 @@ enum Foo { | |||
770 | 770 | ||
771 | impl Foo { | 771 | impl Foo { |
772 | fn foo(self) { | 772 | fn foo(self) { |
773 | Self::<|> | 773 | Self::$0 |
774 | } | 774 | } |
775 | } | 775 | } |
776 | "#, | 776 | "#, |
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs index 91bf4a8ad..bb6354ded 100644 --- a/crates/completion/src/completions/record.rs +++ b/crates/completion/src/completions/record.rs | |||
@@ -20,13 +20,17 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
20 | 20 | ||
21 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); | 21 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); |
22 | if impl_default_trait && !missing_fields.is_empty() { | 22 | if impl_default_trait && !missing_fields.is_empty() { |
23 | let completion_text = "..Default::default()"; | ||
24 | let completion_text = completion_text | ||
25 | .strip_prefix(ctx.token.to_string().as_str()) | ||
26 | .unwrap_or(completion_text); | ||
23 | acc.add( | 27 | acc.add( |
24 | CompletionItem::new( | 28 | CompletionItem::new( |
25 | CompletionKind::Snippet, | 29 | CompletionKind::Snippet, |
26 | ctx.source_range(), | 30 | ctx.source_range(), |
27 | "..Default::default()", | 31 | "..Default::default()", |
28 | ) | 32 | ) |
29 | .insert_text("..Default::default()") | 33 | .insert_text(completion_text) |
30 | .kind(CompletionItemKind::Field) | 34 | .kind(CompletionItemKind::Field) |
31 | .build(), | 35 | .build(), |
32 | ); | 36 | ); |
@@ -48,7 +52,10 @@ mod tests { | |||
48 | use expect_test::{expect, Expect}; | 52 | use expect_test::{expect, Expect}; |
49 | use ide_db::helpers::FamousDefs; | 53 | use ide_db::helpers::FamousDefs; |
50 | 54 | ||
51 | use crate::{test_utils::completion_list, CompletionKind}; | 55 | use crate::{ |
56 | test_utils::{self, completion_list}, | ||
57 | CompletionKind, | ||
58 | }; | ||
52 | 59 | ||
53 | fn check(ra_fixture: &str, expect: Expect) { | 60 | fn check(ra_fixture: &str, expect: Expect) { |
54 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 61 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
@@ -63,6 +70,18 @@ mod tests { | |||
63 | expect.assert_eq(&actual); | 70 | expect.assert_eq(&actual); |
64 | } | 71 | } |
65 | 72 | ||
73 | fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
74 | test_utils::check_edit( | ||
75 | what, | ||
76 | &format!( | ||
77 | "//- /main.rs crate:main deps:core{}\n{}", | ||
78 | ra_fixture_before, | ||
79 | FamousDefs::FIXTURE, | ||
80 | ), | ||
81 | &(ra_fixture_after.to_owned() + "\n"), | ||
82 | ); | ||
83 | } | ||
84 | |||
66 | #[test] | 85 | #[test] |
67 | fn test_record_literal_field_default() { | 86 | fn test_record_literal_field_default() { |
68 | let test_code = r#" | 87 | let test_code = r#" |
@@ -80,7 +99,7 @@ impl core::default::Default for S { | |||
80 | fn process(f: S) { | 99 | fn process(f: S) { |
81 | let other = S { | 100 | let other = S { |
82 | foo: 5, | 101 | foo: 5, |
83 | .<|> | 102 | .$0 |
84 | }; | 103 | }; |
85 | } | 104 | } |
86 | "#; | 105 | "#; |
@@ -102,6 +121,51 @@ fn process(f: S) { | |||
102 | } | 121 | } |
103 | 122 | ||
104 | #[test] | 123 | #[test] |
124 | fn test_record_literal_field_default_completion() { | ||
125 | check_edit( | ||
126 | "..Default::default()", | ||
127 | r#" | ||
128 | struct S { foo: u32, bar: usize } | ||
129 | |||
130 | impl core::default::Default for S { | ||
131 | fn default() -> Self { | ||
132 | S { | ||
133 | foo: 0, | ||
134 | bar: 0, | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | fn process(f: S) { | ||
140 | let other = S { | ||
141 | foo: 5, | ||
142 | .$0 | ||
143 | }; | ||
144 | } | ||
145 | "#, | ||
146 | r#" | ||
147 | struct S { foo: u32, bar: usize } | ||
148 | |||
149 | impl core::default::Default for S { | ||
150 | fn default() -> Self { | ||
151 | S { | ||
152 | foo: 0, | ||
153 | bar: 0, | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | fn process(f: S) { | ||
159 | let other = S { | ||
160 | foo: 5, | ||
161 | ..Default::default() | ||
162 | }; | ||
163 | } | ||
164 | "#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
105 | fn test_record_literal_field_without_default() { | 169 | fn test_record_literal_field_without_default() { |
106 | let test_code = r#" | 170 | let test_code = r#" |
107 | struct S { foo: u32, bar: usize } | 171 | struct S { foo: u32, bar: usize } |
@@ -109,7 +173,7 @@ struct S { foo: u32, bar: usize } | |||
109 | fn process(f: S) { | 173 | fn process(f: S) { |
110 | let other = S { | 174 | let other = S { |
111 | foo: 5, | 175 | foo: 5, |
112 | .<|> | 176 | .$0 |
113 | }; | 177 | }; |
114 | } | 178 | } |
115 | "#; | 179 | "#; |
@@ -137,7 +201,7 @@ struct S { foo: u32 } | |||
137 | 201 | ||
138 | fn process(f: S) { | 202 | fn process(f: S) { |
139 | match f { | 203 | match f { |
140 | S { f<|>: 92 } => (), | 204 | S { f$0: 92 } => (), |
141 | } | 205 | } |
142 | } | 206 | } |
143 | "#, | 207 | "#, |
@@ -155,7 +219,7 @@ enum E { S { foo: u32, bar: () } } | |||
155 | 219 | ||
156 | fn process(e: E) { | 220 | fn process(e: E) { |
157 | match e { | 221 | match e { |
158 | E::S { <|> } => (), | 222 | E::S { $0 } => (), |
159 | } | 223 | } |
160 | } | 224 | } |
161 | "#, | 225 | "#, |
@@ -175,7 +239,7 @@ struct S { foo: u32 } | |||
175 | 239 | ||
176 | fn process(f: S) { | 240 | fn process(f: S) { |
177 | m!(match f { | 241 | m!(match f { |
178 | S { f<|>: 92 } => (), | 242 | S { f$0: 92 } => (), |
179 | }) | 243 | }) |
180 | } | 244 | } |
181 | ", | 245 | ", |
@@ -199,7 +263,7 @@ fn main() { | |||
199 | foo1: 1, foo2: 2, | 263 | foo1: 1, foo2: 2, |
200 | bar: 3, baz: 4, | 264 | bar: 3, baz: 4, |
201 | }; | 265 | }; |
202 | if let S { foo1, foo2: a, <|> } = s {} | 266 | if let S { foo1, foo2: a, $0 } = s {} |
203 | } | 267 | } |
204 | "#, | 268 | "#, |
205 | expect![[r#" | 269 | expect![[r#" |
@@ -215,7 +279,7 @@ fn main() { | |||
215 | r#" | 279 | r#" |
216 | struct A { the_field: u32 } | 280 | struct A { the_field: u32 } |
217 | fn foo() { | 281 | fn foo() { |
218 | A { the<|> } | 282 | A { the$0 } |
219 | } | 283 | } |
220 | "#, | 284 | "#, |
221 | expect![[r#" | 285 | expect![[r#" |
@@ -230,7 +294,7 @@ fn foo() { | |||
230 | r#" | 294 | r#" |
231 | enum E { A { a: u32 } } | 295 | enum E { A { a: u32 } } |
232 | fn foo() { | 296 | fn foo() { |
233 | let _ = E::A { <|> } | 297 | let _ = E::A { $0 } |
234 | } | 298 | } |
235 | "#, | 299 | "#, |
236 | expect![[r#" | 300 | expect![[r#" |
@@ -247,7 +311,7 @@ struct A { a: u32 } | |||
247 | struct B { b: u32 } | 311 | struct B { b: u32 } |
248 | 312 | ||
249 | fn foo() { | 313 | fn foo() { |
250 | let _: A = B { <|> } | 314 | let _: A = B { $0 } |
251 | } | 315 | } |
252 | "#, | 316 | "#, |
253 | expect![[r#" | 317 | expect![[r#" |
@@ -263,7 +327,7 @@ fn foo() { | |||
263 | struct A<T> { a: T } | 327 | struct A<T> { a: T } |
264 | 328 | ||
265 | fn foo() { | 329 | fn foo() { |
266 | let _: A<u32> = A { <|> } | 330 | let _: A<u32> = A { $0 } |
267 | } | 331 | } |
268 | "#, | 332 | "#, |
269 | expect![[r#" | 333 | expect![[r#" |
@@ -279,7 +343,7 @@ fn foo() { | |||
279 | macro_rules! m { ($e:expr) => { $e } } | 343 | macro_rules! m { ($e:expr) => { $e } } |
280 | struct A { the_field: u32 } | 344 | struct A { the_field: u32 } |
281 | fn foo() { | 345 | fn foo() { |
282 | m!(A { the<|> }) | 346 | m!(A { the$0 }) |
283 | } | 347 | } |
284 | "#, | 348 | "#, |
285 | expect![[r#" | 349 | expect![[r#" |
@@ -299,7 +363,7 @@ struct S { | |||
299 | 363 | ||
300 | fn main() { | 364 | fn main() { |
301 | let foo1 = 1; | 365 | let foo1 = 1; |
302 | let s = S { foo1, foo2: 5, <|> } | 366 | let s = S { foo1, foo2: 5, $0 } |
303 | } | 367 | } |
304 | "#, | 368 | "#, |
305 | expect![[r#" | 369 | expect![[r#" |
@@ -317,7 +381,7 @@ struct S { foo1: u32, foo2: u32 } | |||
317 | 381 | ||
318 | fn main() { | 382 | fn main() { |
319 | let foo1 = 1; | 383 | let foo1 = 1; |
320 | let s = S { foo1, <|> .. loop {} } | 384 | let s = S { foo1, $0 .. loop {} } |
321 | } | 385 | } |
322 | "#, | 386 | "#, |
323 | expect![[r#" | 387 | expect![[r#" |
diff --git a/crates/completion/src/completions/snippet.rs b/crates/completion/src/completions/snippet.rs index 842590130..df17a15c5 100644 --- a/crates/completion/src/completions/snippet.rs +++ b/crates/completion/src/completions/snippet.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | //! This file provides snippet completions, like `pd` => `eprintln!(...)`. | 1 | //! This file provides snippet completions, like `pd` => `eprintln!(...)`. |
2 | 2 | ||
3 | use ide_db::helpers::SnippetCap; | ||
4 | |||
3 | use crate::{ | 5 | use crate::{ |
4 | config::SnippetCap, item::Builder, CompletionContext, CompletionItem, CompletionItemKind, | 6 | item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, |
5 | CompletionKind, Completions, | 7 | Completions, |
6 | }; | 8 | }; |
7 | 9 | ||
8 | fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { | 10 | fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { |
@@ -81,7 +83,7 @@ mod tests { | |||
81 | #[test] | 83 | #[test] |
82 | fn completes_snippets_in_expressions() { | 84 | fn completes_snippets_in_expressions() { |
83 | check( | 85 | check( |
84 | r#"fn foo(x: i32) { <|> }"#, | 86 | r#"fn foo(x: i32) { $0 }"#, |
85 | expect![[r#" | 87 | expect![[r#" |
86 | sn pd | 88 | sn pd |
87 | sn ppd | 89 | sn ppd |
@@ -91,8 +93,8 @@ mod tests { | |||
91 | 93 | ||
92 | #[test] | 94 | #[test] |
93 | fn should_not_complete_snippets_in_path() { | 95 | fn should_not_complete_snippets_in_path() { |
94 | check(r#"fn foo(x: i32) { ::foo<|> }"#, expect![[""]]); | 96 | check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]); |
95 | check(r#"fn foo(x: i32) { ::<|> }"#, expect![[""]]); | 97 | check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]); |
96 | } | 98 | } |
97 | 99 | ||
98 | #[test] | 100 | #[test] |
@@ -101,7 +103,7 @@ mod tests { | |||
101 | r#" | 103 | r#" |
102 | #[cfg(test)] | 104 | #[cfg(test)] |
103 | mod tests { | 105 | mod tests { |
104 | <|> | 106 | $0 |
105 | } | 107 | } |
106 | "#, | 108 | "#, |
107 | expect![[r#" | 109 | expect![[r#" |
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs index c4e0d0669..135ae49dc 100644 --- a/crates/completion/src/completions/trait_impl.rs +++ b/crates/completion/src/completions/trait_impl.rs | |||
@@ -15,7 +15,7 @@ | |||
15 | //! } | 15 | //! } |
16 | //! | 16 | //! |
17 | //! impl SomeTrait for () { | 17 | //! impl SomeTrait for () { |
18 | //! fn f<|> | 18 | //! fn f$0 |
19 | //! } | 19 | //! } |
20 | //! ``` | 20 | //! ``` |
21 | //! | 21 | //! |
@@ -27,7 +27,7 @@ | |||
27 | //! # } | 27 | //! # } |
28 | //! | 28 | //! |
29 | //! impl SomeTrait for () { | 29 | //! impl SomeTrait for () { |
30 | //! fn foo() {}<|> | 30 | //! fn foo() {}$0 |
31 | //! } | 31 | //! } |
32 | //! ``` | 32 | //! ``` |
33 | 33 | ||
@@ -82,7 +82,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
82 | 82 | ||
83 | fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { | 83 | fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { |
84 | let mut token = ctx.token.clone(); | 84 | let mut token = ctx.token.clone(); |
85 | // For keywork without name like `impl .. { fn <|> }`, the current position is inside | 85 | // For keywork without name like `impl .. { fn $0 }`, the current position is inside |
86 | // the whitespace token, which is outside `FN` syntax node. | 86 | // the whitespace token, which is outside `FN` syntax node. |
87 | // We need to follow the previous token in this case. | 87 | // We need to follow the previous token in this case. |
88 | if token.kind() == SyntaxKind::WHITESPACE { | 88 | if token.kind() == SyntaxKind::WHITESPACE { |
@@ -90,20 +90,20 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt | |||
90 | } | 90 | } |
91 | 91 | ||
92 | let impl_item_offset = match token.kind() { | 92 | let impl_item_offset = match token.kind() { |
93 | // `impl .. { const <|> }` | 93 | // `impl .. { const $0 }` |
94 | // ERROR 0 | 94 | // ERROR 0 |
95 | // CONST_KW <- * | 95 | // CONST_KW <- * |
96 | SyntaxKind::CONST_KW => 0, | 96 | T![const] => 0, |
97 | // `impl .. { fn/type <|> }` | 97 | // `impl .. { fn/type $0 }` |
98 | // FN/TYPE_ALIAS 0 | 98 | // FN/TYPE_ALIAS 0 |
99 | // FN_KW <- * | 99 | // FN_KW <- * |
100 | SyntaxKind::FN_KW | SyntaxKind::TYPE_KW => 0, | 100 | T![fn] | T![type] => 0, |
101 | // `impl .. { fn/type/const foo<|> }` | 101 | // `impl .. { fn/type/const foo$0 }` |
102 | // FN/TYPE_ALIAS/CONST 1 | 102 | // FN/TYPE_ALIAS/CONST 1 |
103 | // NAME 0 | 103 | // NAME 0 |
104 | // IDENT <- * | 104 | // IDENT <- * |
105 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1, | 105 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1, |
106 | // `impl .. { foo<|> }` | 106 | // `impl .. { foo$0 }` |
107 | // MACRO_CALL 3 | 107 | // MACRO_CALL 3 |
108 | // PATH 2 | 108 | // PATH 2 |
109 | // PATH_SEGMENT 1 | 109 | // PATH_SEGMENT 1 |
@@ -120,8 +120,8 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt | |||
120 | // <item> | 120 | // <item> |
121 | let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?; | 121 | let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?; |
122 | let kind = match impl_item.kind() { | 122 | let kind = match impl_item.kind() { |
123 | // `impl ... { const <|> fn/type/const }` | 123 | // `impl ... { const $0 fn/type/const }` |
124 | _ if token.kind() == SyntaxKind::CONST_KW => ImplCompletionKind::Const, | 124 | _ if token.kind() == T![const] => ImplCompletionKind::Const, |
125 | SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const, | 125 | SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const, |
126 | SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias, | 126 | SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias, |
127 | SyntaxKind::FN => ImplCompletionKind::Fn, | 127 | SyntaxKind::FN => ImplCompletionKind::Fn, |
@@ -156,19 +156,21 @@ fn add_function_impl( | |||
156 | }; | 156 | }; |
157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); |
158 | 158 | ||
159 | let function_decl = function_declaration(&func.source(ctx.db).value); | 159 | if let Some(src) = func.source(ctx.db) { |
160 | match ctx.config.snippet_cap { | 160 | let function_decl = function_declaration(&src.value); |
161 | Some(cap) => { | 161 | match ctx.config.snippet_cap { |
162 | let snippet = format!("{} {{\n $0\n}}", function_decl); | 162 | Some(cap) => { |
163 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | 163 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
164 | } | 164 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) |
165 | None => { | 165 | } |
166 | let header = format!("{} {{", function_decl); | 166 | None => { |
167 | builder.text_edit(TextEdit::replace(range, header)) | 167 | let header = format!("{} {{", function_decl); |
168 | builder.text_edit(TextEdit::replace(range, header)) | ||
169 | } | ||
168 | } | 170 | } |
171 | .kind(completion_kind) | ||
172 | .add_to(acc); | ||
169 | } | 173 | } |
170 | .kind(completion_kind) | ||
171 | .add_to(acc); | ||
172 | } | 174 | } |
173 | 175 | ||
174 | fn add_type_alias_impl( | 176 | fn add_type_alias_impl( |
@@ -200,16 +202,19 @@ fn add_const_impl( | |||
200 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 202 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
201 | 203 | ||
202 | if let Some(const_name) = const_name { | 204 | if let Some(const_name) = const_name { |
203 | let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); | 205 | if let Some(source) = const_.source(ctx.db) { |
204 | 206 | let snippet = make_const_compl_syntax(&source.value); | |
205 | let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); | 207 | |
206 | 208 | let range = | |
207 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) | 209 | TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); |
208 | .text_edit(TextEdit::replace(range, snippet)) | 210 | |
209 | .lookup_by(const_name) | 211 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) |
210 | .kind(CompletionItemKind::Const) | 212 | .text_edit(TextEdit::replace(range, snippet)) |
211 | .set_documentation(const_.docs(ctx.db)) | 213 | .lookup_by(const_name) |
212 | .add_to(acc); | 214 | .kind(CompletionItemKind::Const) |
215 | .set_documentation(const_.docs(ctx.db)) | ||
216 | .add_to(acc); | ||
217 | } | ||
213 | } | 218 | } |
214 | } | 219 | } |
215 | 220 | ||
@@ -262,7 +267,7 @@ trait Test { | |||
262 | struct T; | 267 | struct T; |
263 | 268 | ||
264 | impl Test for T { | 269 | impl Test for T { |
265 | t<|> | 270 | t$0 |
266 | } | 271 | } |
267 | "#, | 272 | "#, |
268 | expect![[" | 273 | expect![[" |
@@ -282,7 +287,7 @@ struct T; | |||
282 | 287 | ||
283 | impl Test for T { | 288 | impl Test for T { |
284 | fn test() { | 289 | fn test() { |
285 | t<|> | 290 | t$0 |
286 | } | 291 | } |
287 | } | 292 | } |
288 | ", | 293 | ", |
@@ -296,7 +301,7 @@ struct T; | |||
296 | 301 | ||
297 | impl Test for T { | 302 | impl Test for T { |
298 | fn test() { | 303 | fn test() { |
299 | fn t<|> | 304 | fn t$0 |
300 | } | 305 | } |
301 | } | 306 | } |
302 | ", | 307 | ", |
@@ -310,7 +315,7 @@ struct T; | |||
310 | 315 | ||
311 | impl Test for T { | 316 | impl Test for T { |
312 | fn test() { | 317 | fn test() { |
313 | fn <|> | 318 | fn $0 |
314 | } | 319 | } |
315 | } | 320 | } |
316 | ", | 321 | ", |
@@ -325,7 +330,7 @@ struct T; | |||
325 | 330 | ||
326 | impl Test for T { | 331 | impl Test for T { |
327 | fn test() { | 332 | fn test() { |
328 | foo.<|> | 333 | foo.$0 |
329 | } | 334 | } |
330 | } | 335 | } |
331 | ", | 336 | ", |
@@ -338,7 +343,7 @@ trait Test { fn test(_: i32); fn test2(); } | |||
338 | struct T; | 343 | struct T; |
339 | 344 | ||
340 | impl Test for T { | 345 | impl Test for T { |
341 | fn test(t<|>) | 346 | fn test(t$0) |
342 | } | 347 | } |
343 | ", | 348 | ", |
344 | expect![[""]], | 349 | expect![[""]], |
@@ -350,7 +355,7 @@ trait Test { fn test(_: fn()); fn test2(); } | |||
350 | struct T; | 355 | struct T; |
351 | 356 | ||
352 | impl Test for T { | 357 | impl Test for T { |
353 | fn test(f: fn <|>) | 358 | fn test(f: fn $0) |
354 | } | 359 | } |
355 | ", | 360 | ", |
356 | expect![[""]], | 361 | expect![[""]], |
@@ -365,7 +370,7 @@ trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); } | |||
365 | struct T; | 370 | struct T; |
366 | 371 | ||
367 | impl Test for T { | 372 | impl Test for T { |
368 | const TEST: fn <|> | 373 | const TEST: fn $0 |
369 | } | 374 | } |
370 | ", | 375 | ", |
371 | expect![[""]], | 376 | expect![[""]], |
@@ -377,7 +382,7 @@ trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | |||
377 | struct T; | 382 | struct T; |
378 | 383 | ||
379 | impl Test for T { | 384 | impl Test for T { |
380 | const TEST: T<|> | 385 | const TEST: T$0 |
381 | } | 386 | } |
382 | ", | 387 | ", |
383 | expect![[""]], | 388 | expect![[""]], |
@@ -389,7 +394,7 @@ trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | |||
389 | struct T; | 394 | struct T; |
390 | 395 | ||
391 | impl Test for T { | 396 | impl Test for T { |
392 | const TEST: u32 = f<|> | 397 | const TEST: u32 = f$0 |
393 | } | 398 | } |
394 | ", | 399 | ", |
395 | expect![[""]], | 400 | expect![[""]], |
@@ -402,7 +407,7 @@ struct T; | |||
402 | 407 | ||
403 | impl Test for T { | 408 | impl Test for T { |
404 | const TEST: u32 = { | 409 | const TEST: u32 = { |
405 | t<|> | 410 | t$0 |
406 | }; | 411 | }; |
407 | } | 412 | } |
408 | ", | 413 | ", |
@@ -416,7 +421,7 @@ struct T; | |||
416 | 421 | ||
417 | impl Test for T { | 422 | impl Test for T { |
418 | const TEST: u32 = { | 423 | const TEST: u32 = { |
419 | fn <|> | 424 | fn $0 |
420 | }; | 425 | }; |
421 | } | 426 | } |
422 | ", | 427 | ", |
@@ -430,7 +435,7 @@ struct T; | |||
430 | 435 | ||
431 | impl Test for T { | 436 | impl Test for T { |
432 | const TEST: u32 = { | 437 | const TEST: u32 = { |
433 | fn t<|> | 438 | fn t$0 |
434 | }; | 439 | }; |
435 | } | 440 | } |
436 | ", | 441 | ", |
@@ -446,7 +451,7 @@ trait Test { type Test; type Test2; fn test(); } | |||
446 | struct T; | 451 | struct T; |
447 | 452 | ||
448 | impl Test for T { | 453 | impl Test for T { |
449 | type Test = T<|>; | 454 | type Test = T$0; |
450 | } | 455 | } |
451 | ", | 456 | ", |
452 | expect![[""]], | 457 | expect![[""]], |
@@ -458,7 +463,7 @@ trait Test { type Test; type Test2; fn test(); } | |||
458 | struct T; | 463 | struct T; |
459 | 464 | ||
460 | impl Test for T { | 465 | impl Test for T { |
461 | type Test = fn <|>; | 466 | type Test = fn $0; |
462 | } | 467 | } |
463 | ", | 468 | ", |
464 | expect![[""]], | 469 | expect![[""]], |
@@ -476,7 +481,7 @@ trait Test { | |||
476 | struct T; | 481 | struct T; |
477 | 482 | ||
478 | impl Test for T { | 483 | impl Test for T { |
479 | t<|> | 484 | t$0 |
480 | } | 485 | } |
481 | "#, | 486 | "#, |
482 | r#" | 487 | r#" |
@@ -505,7 +510,7 @@ trait Test { | |||
505 | struct T; | 510 | struct T; |
506 | 511 | ||
507 | impl Test for T { | 512 | impl Test for T { |
508 | fn t<|> | 513 | fn t$0 |
509 | } | 514 | } |
510 | "#, | 515 | "#, |
511 | r#" | 516 | r#" |
@@ -535,7 +540,7 @@ struct T; | |||
535 | 540 | ||
536 | impl Test for T { | 541 | impl Test for T { |
537 | fn foo() {} | 542 | fn foo() {} |
538 | fn f<|> | 543 | fn f$0 |
539 | } | 544 | } |
540 | "#, | 545 | "#, |
541 | expect![[r#" | 546 | expect![[r#" |
@@ -555,7 +560,7 @@ trait Test { | |||
555 | struct T; | 560 | struct T; |
556 | 561 | ||
557 | impl Test for T { | 562 | impl Test for T { |
558 | fn f<|> | 563 | fn f$0 |
559 | } | 564 | } |
560 | "#, | 565 | "#, |
561 | r#" | 566 | r#" |
@@ -580,7 +585,7 @@ trait Test { | |||
580 | struct T; | 585 | struct T; |
581 | 586 | ||
582 | impl Test for T { | 587 | impl Test for T { |
583 | fn f<|> | 588 | fn f$0 |
584 | } | 589 | } |
585 | "#, | 590 | "#, |
586 | r#" | 591 | r#" |
@@ -609,7 +614,7 @@ trait Test { | |||
609 | } | 614 | } |
610 | 615 | ||
611 | impl Test for () { | 616 | impl Test for () { |
612 | type S<|> | 617 | type S$0 |
613 | } | 618 | } |
614 | "#, | 619 | "#, |
615 | " | 620 | " |
@@ -634,7 +639,7 @@ trait Test { | |||
634 | } | 639 | } |
635 | 640 | ||
636 | impl Test for () { | 641 | impl Test for () { |
637 | const S<|> | 642 | const S$0 |
638 | } | 643 | } |
639 | "#, | 644 | "#, |
640 | " | 645 | " |
@@ -656,7 +661,7 @@ trait Test { | |||
656 | } | 661 | } |
657 | 662 | ||
658 | impl Test for () { | 663 | impl Test for () { |
659 | const S<|> | 664 | const S$0 |
660 | } | 665 | } |
661 | "#, | 666 | "#, |
662 | " | 667 | " |
@@ -719,7 +724,7 @@ impl Test for T {{ | |||
719 | // Enumerate some possible next siblings. | 724 | // Enumerate some possible next siblings. |
720 | for next_sibling in &[ | 725 | for next_sibling in &[ |
721 | "", | 726 | "", |
722 | "fn other_fn() {}", // `const <|> fn` -> `const fn` | 727 | "fn other_fn() {}", // `const $0 fn` -> `const fn` |
723 | "type OtherType = i32;", | 728 | "type OtherType = i32;", |
724 | "const OTHER_CONST: i32 = 0;", | 729 | "const OTHER_CONST: i32 = 0;", |
725 | "async fn other_fn() {}", | 730 | "async fn other_fn() {}", |
@@ -728,9 +733,9 @@ impl Test for T {{ | |||
728 | "default type OtherType = i32;", | 733 | "default type OtherType = i32;", |
729 | "default const OTHER_CONST: i32 = 0;", | 734 | "default const OTHER_CONST: i32 = 0;", |
730 | ] { | 735 | ] { |
731 | test("bar", "fn <|>", "fn bar() {\n $0\n}", next_sibling); | 736 | test("bar", "fn $0", "fn bar() {\n $0\n}", next_sibling); |
732 | test("Foo", "type <|>", "type Foo = ", next_sibling); | 737 | test("Foo", "type $0", "type Foo = ", next_sibling); |
733 | test("CONST", "const <|>", "const CONST: u16 = ", next_sibling); | 738 | test("CONST", "const $0", "const CONST: u16 = ", next_sibling); |
734 | } | 739 | } |
735 | } | 740 | } |
736 | } | 741 | } |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 81a6d00e2..12cdb869d 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -46,7 +46,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
46 | acc.add_resolution(ctx, name.to_string(), &res) | 46 | acc.add_resolution(ctx, name.to_string(), &res) |
47 | }); | 47 | }); |
48 | 48 | ||
49 | if ctx.config.enable_autoimport_completions && ctx.config.resolve_additional_edits_lazily() { | 49 | if ctx.config.enable_autoimport_completions { |
50 | fuzzy_completion(acc, ctx); | 50 | fuzzy_completion(acc, ctx); |
51 | } | 51 | } |
52 | } | 52 | } |
@@ -85,7 +85,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
85 | // | 85 | // |
86 | // ``` | 86 | // ``` |
87 | // fn main() { | 87 | // fn main() { |
88 | // pda<|> | 88 | // pda$0 |
89 | // } | 89 | // } |
90 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } | 90 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } |
91 | // ``` | 91 | // ``` |
@@ -124,8 +124,8 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
124 | // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | 124 | // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding |
125 | // capability enabled. | 125 | // capability enabled. |
126 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 126 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
127 | let _p = profile::span("fuzzy_completion"); | ||
128 | let potential_import_name = ctx.token.to_string(); | 127 | let potential_import_name = ctx.token.to_string(); |
128 | let _p = profile::span("fuzzy_completion").detail(|| potential_import_name.clone()); | ||
129 | 129 | ||
130 | if potential_import_name.len() < 2 { | 130 | if potential_import_name.len() < 2 { |
131 | return None; | 131 | return None; |
@@ -142,6 +142,7 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
142 | Some(40), | 142 | Some(40), |
143 | potential_import_name, | 143 | potential_import_name, |
144 | true, | 144 | true, |
145 | true, | ||
145 | ) | 146 | ) |
146 | .filter_map(|import_candidate| { | 147 | .filter_map(|import_candidate| { |
147 | Some(match import_candidate { | 148 | Some(match import_candidate { |
@@ -191,12 +192,14 @@ mod tests { | |||
191 | use test_utils::mark; | 192 | use test_utils::mark; |
192 | 193 | ||
193 | use crate::{ | 194 | use crate::{ |
194 | test_utils::{check_edit, check_edit_with_config, completion_list_with_config}, | 195 | test_utils::{ |
196 | check_edit, check_edit_with_config, completion_list_with_config, TEST_CONFIG, | ||
197 | }, | ||
195 | CompletionConfig, CompletionKind, | 198 | CompletionConfig, CompletionKind, |
196 | }; | 199 | }; |
197 | 200 | ||
198 | fn check(ra_fixture: &str, expect: Expect) { | 201 | fn check(ra_fixture: &str, expect: Expect) { |
199 | check_with_config(CompletionConfig::default(), ra_fixture, expect); | 202 | check_with_config(TEST_CONFIG, ra_fixture, expect); |
200 | } | 203 | } |
201 | 204 | ||
202 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { | 205 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { |
@@ -204,20 +207,12 @@ mod tests { | |||
204 | expect.assert_eq(&actual) | 207 | expect.assert_eq(&actual) |
205 | } | 208 | } |
206 | 209 | ||
207 | fn fuzzy_completion_config() -> CompletionConfig { | ||
208 | let mut completion_config = CompletionConfig::default(); | ||
209 | completion_config | ||
210 | .active_resolve_capabilities | ||
211 | .insert(crate::CompletionResolveCapability::AdditionalTextEdits); | ||
212 | completion_config | ||
213 | } | ||
214 | |||
215 | #[test] | 210 | #[test] |
216 | fn self_fulfilling_completion() { | 211 | fn self_fulfilling_completion() { |
217 | mark::check!(self_fulfilling_completion); | 212 | mark::check!(self_fulfilling_completion); |
218 | check( | 213 | check( |
219 | r#" | 214 | r#" |
220 | use foo<|> | 215 | use foo$0 |
221 | use std::collections; | 216 | use std::collections; |
222 | "#, | 217 | "#, |
223 | expect![[r#" | 218 | expect![[r#" |
@@ -234,7 +229,7 @@ enum Enum { A, B } | |||
234 | fn quux(x: Option<Enum>) { | 229 | fn quux(x: Option<Enum>) { |
235 | match x { | 230 | match x { |
236 | None => (), | 231 | None => (), |
237 | Some(en<|> @ Enum::A) => (), | 232 | Some(en$0 @ Enum::A) => (), |
238 | } | 233 | } |
239 | } | 234 | } |
240 | "#, | 235 | "#, |
@@ -250,7 +245,7 @@ enum Enum { A, B } | |||
250 | fn quux(x: Option<Enum>) { | 245 | fn quux(x: Option<Enum>) { |
251 | match x { | 246 | match x { |
252 | None => (), | 247 | None => (), |
253 | Some(ref en<|>) => (), | 248 | Some(ref en$0) => (), |
254 | } | 249 | } |
255 | } | 250 | } |
256 | "#, | 251 | "#, |
@@ -266,7 +261,7 @@ enum Enum { A, B } | |||
266 | fn quux(x: Option<Enum>) { | 261 | fn quux(x: Option<Enum>) { |
267 | match x { | 262 | match x { |
268 | None => (), | 263 | None => (), |
269 | Some(En<|>) => (), | 264 | Some(En$0) => (), |
270 | } | 265 | } |
271 | } | 266 | } |
272 | "#, | 267 | "#, |
@@ -282,7 +277,7 @@ fn quux(x: Option<Enum>) { | |||
282 | r#" | 277 | r#" |
283 | fn quux(x: i32) { | 278 | fn quux(x: i32) { |
284 | let y = 92; | 279 | let y = 92; |
285 | 1 + <|>; | 280 | 1 + $0; |
286 | let z = (); | 281 | let z = (); |
287 | } | 282 | } |
288 | "#, | 283 | "#, |
@@ -304,7 +299,7 @@ fn quux() { | |||
304 | }; | 299 | }; |
305 | if let Some(a) = bar() { | 300 | if let Some(a) = bar() { |
306 | let b = 62; | 301 | let b = 62; |
307 | 1 + <|> | 302 | 1 + $0 |
308 | } | 303 | } |
309 | } | 304 | } |
310 | "#, | 305 | "#, |
@@ -321,7 +316,7 @@ fn quux() { | |||
321 | check( | 316 | check( |
322 | r#" | 317 | r#" |
323 | fn quux() { | 318 | fn quux() { |
324 | for x in &[1, 2, 3] { <|> } | 319 | for x in &[1, 2, 3] { $0 } |
325 | } | 320 | } |
326 | "#, | 321 | "#, |
327 | expect![[r#" | 322 | expect![[r#" |
@@ -339,7 +334,7 @@ fn quux() { | |||
339 | r#" | 334 | r#" |
340 | fn main() { | 335 | fn main() { |
341 | let wherewolf = 92; | 336 | let wherewolf = 92; |
342 | drop(where<|>) | 337 | drop(where$0) |
343 | } | 338 | } |
344 | "#, | 339 | "#, |
345 | r#" | 340 | r#" |
@@ -354,7 +349,7 @@ fn main() { | |||
354 | #[test] | 349 | #[test] |
355 | fn completes_generic_params() { | 350 | fn completes_generic_params() { |
356 | check( | 351 | check( |
357 | r#"fn quux<T>() { <|> }"#, | 352 | r#"fn quux<T>() { $0 }"#, |
358 | expect![[r#" | 353 | expect![[r#" |
359 | tp T | 354 | tp T |
360 | fn quux() fn quux<T>() | 355 | fn quux() fn quux<T>() |
@@ -365,7 +360,7 @@ fn main() { | |||
365 | #[test] | 360 | #[test] |
366 | fn completes_generic_params_in_struct() { | 361 | fn completes_generic_params_in_struct() { |
367 | check( | 362 | check( |
368 | r#"struct S<T> { x: <|>}"#, | 363 | r#"struct S<T> { x: $0}"#, |
369 | expect![[r#" | 364 | expect![[r#" |
370 | tp Self | 365 | tp Self |
371 | tp T | 366 | tp T |
@@ -377,7 +372,7 @@ fn main() { | |||
377 | #[test] | 372 | #[test] |
378 | fn completes_self_in_enum() { | 373 | fn completes_self_in_enum() { |
379 | check( | 374 | check( |
380 | r#"enum X { Y(<|>) }"#, | 375 | r#"enum X { Y($0) }"#, |
381 | expect![[r#" | 376 | expect![[r#" |
382 | tp Self | 377 | tp Self |
383 | en X | 378 | en X |
@@ -391,7 +386,7 @@ fn main() { | |||
391 | r#" | 386 | r#" |
392 | struct S; | 387 | struct S; |
393 | enum E {} | 388 | enum E {} |
394 | fn quux() { <|> } | 389 | fn quux() { $0 } |
395 | "#, | 390 | "#, |
396 | expect![[r#" | 391 | expect![[r#" |
397 | st S | 392 | st S |
@@ -408,7 +403,7 @@ fn quux() { <|> } | |||
408 | "_alpha", | 403 | "_alpha", |
409 | r#" | 404 | r#" |
410 | fn main() { | 405 | fn main() { |
411 | _<|> | 406 | _$0 |
412 | } | 407 | } |
413 | fn _alpha() {} | 408 | fn _alpha() {} |
414 | "#, | 409 | "#, |
@@ -426,7 +421,7 @@ fn _alpha() {} | |||
426 | check( | 421 | check( |
427 | r#" | 422 | r#" |
428 | //- /lib.rs crate:main deps:other_crate | 423 | //- /lib.rs crate:main deps:other_crate |
429 | use <|>; | 424 | use $0; |
430 | 425 | ||
431 | //- /other_crate/lib.rs crate:other_crate | 426 | //- /other_crate/lib.rs crate:other_crate |
432 | // nothing here | 427 | // nothing here |
@@ -444,7 +439,7 @@ use <|>; | |||
444 | struct Foo; | 439 | struct Foo; |
445 | mod m { | 440 | mod m { |
446 | struct Bar; | 441 | struct Bar; |
447 | fn quux() { <|> } | 442 | fn quux() { $0 } |
448 | } | 443 | } |
449 | "#, | 444 | "#, |
450 | expect![[r#" | 445 | expect![[r#" |
@@ -459,7 +454,7 @@ mod m { | |||
459 | check( | 454 | check( |
460 | r#" | 455 | r#" |
461 | struct Foo; | 456 | struct Foo; |
462 | fn x() -> <|> | 457 | fn x() -> $0 |
463 | "#, | 458 | "#, |
464 | expect![[r#" | 459 | expect![[r#" |
465 | st Foo | 460 | st Foo |
@@ -476,7 +471,7 @@ fn foo() { | |||
476 | let bar = 92; | 471 | let bar = 92; |
477 | { | 472 | { |
478 | let bar = 62; | 473 | let bar = 62; |
479 | drop(<|>) | 474 | drop($0) |
480 | } | 475 | } |
481 | } | 476 | } |
482 | "#, | 477 | "#, |
@@ -492,7 +487,7 @@ fn foo() { | |||
492 | #[test] | 487 | #[test] |
493 | fn completes_self_in_methods() { | 488 | fn completes_self_in_methods() { |
494 | check( | 489 | check( |
495 | r#"impl S { fn foo(&self) { <|> } }"#, | 490 | r#"impl S { fn foo(&self) { $0 } }"#, |
496 | expect![[r#" | 491 | expect![[r#" |
497 | bn self &{unknown} | 492 | bn self &{unknown} |
498 | tp Self | 493 | tp Self |
@@ -505,7 +500,7 @@ fn foo() { | |||
505 | check( | 500 | check( |
506 | r#" | 501 | r#" |
507 | //- /main.rs crate:main deps:std | 502 | //- /main.rs crate:main deps:std |
508 | fn foo() { let x: <|> } | 503 | fn foo() { let x: $0 } |
509 | 504 | ||
510 | //- /std/lib.rs crate:std | 505 | //- /std/lib.rs crate:std |
511 | #[prelude_import] | 506 | #[prelude_import] |
@@ -526,7 +521,7 @@ mod prelude { struct Option; } | |||
526 | check( | 521 | check( |
527 | r#" | 522 | r#" |
528 | //- /main.rs crate:main deps:core,std | 523 | //- /main.rs crate:main deps:core,std |
529 | fn foo() { let x: <|> } | 524 | fn foo() { let x: $0 } |
530 | 525 | ||
531 | //- /core/lib.rs crate:core | 526 | //- /core/lib.rs crate:core |
532 | #[prelude_import] | 527 | #[prelude_import] |
@@ -567,7 +562,7 @@ mod m2 { | |||
567 | macro_rules! baz { () => {} } | 562 | macro_rules! baz { () => {} } |
568 | } | 563 | } |
569 | 564 | ||
570 | fn main() { let v = <|> } | 565 | fn main() { let v = $0 } |
571 | "#, | 566 | "#, |
572 | expect![[r##" | 567 | expect![[r##" |
573 | md m1 | 568 | md m1 |
@@ -586,7 +581,7 @@ fn main() { let v = <|> } | |||
586 | check( | 581 | check( |
587 | r#" | 582 | r#" |
588 | macro_rules! foo { () => {} } | 583 | macro_rules! foo { () => {} } |
589 | fn foo() { <|> } | 584 | fn foo() { $0 } |
590 | "#, | 585 | "#, |
591 | expect![[r#" | 586 | expect![[r#" |
592 | fn foo() fn foo() | 587 | fn foo() fn foo() |
@@ -600,7 +595,7 @@ fn foo() { <|> } | |||
600 | check( | 595 | check( |
601 | r#" | 596 | r#" |
602 | macro_rules! foo { () => {} } | 597 | macro_rules! foo { () => {} } |
603 | fn main() { let x: <|> } | 598 | fn main() { let x: $0 } |
604 | "#, | 599 | "#, |
605 | expect![[r#" | 600 | expect![[r#" |
606 | fn main() fn main() | 601 | fn main() fn main() |
@@ -614,7 +609,7 @@ fn main() { let x: <|> } | |||
614 | check( | 609 | check( |
615 | r#" | 610 | r#" |
616 | macro_rules! foo { () => {} } | 611 | macro_rules! foo { () => {} } |
617 | fn main() { <|> } | 612 | fn main() { $0 } |
618 | "#, | 613 | "#, |
619 | expect![[r#" | 614 | expect![[r#" |
620 | fn main() fn main() | 615 | fn main() fn main() |
@@ -628,7 +623,7 @@ fn main() { <|> } | |||
628 | check( | 623 | check( |
629 | r#" | 624 | r#" |
630 | fn main() { | 625 | fn main() { |
631 | return f<|>; | 626 | return f$0; |
632 | fn frobnicate() {} | 627 | fn frobnicate() {} |
633 | } | 628 | } |
634 | "#, | 629 | "#, |
@@ -646,7 +641,7 @@ fn main() { | |||
646 | macro_rules! m { ($e:expr) => { $e } } | 641 | macro_rules! m { ($e:expr) => { $e } } |
647 | fn quux(x: i32) { | 642 | fn quux(x: i32) { |
648 | let y = 92; | 643 | let y = 92; |
649 | m!(<|>); | 644 | m!($0); |
650 | } | 645 | } |
651 | "#, | 646 | "#, |
652 | expect![[r#" | 647 | expect![[r#" |
@@ -665,7 +660,7 @@ fn quux(x: i32) { | |||
665 | macro_rules! m { ($e:expr) => { $e } } | 660 | macro_rules! m { ($e:expr) => { $e } } |
666 | fn quux(x: i32) { | 661 | fn quux(x: i32) { |
667 | let y = 92; | 662 | let y = 92; |
668 | m!(x<|>); | 663 | m!(x$0); |
669 | } | 664 | } |
670 | ", | 665 | ", |
671 | expect![[r#" | 666 | expect![[r#" |
@@ -684,7 +679,7 @@ fn quux(x: i32) { | |||
684 | macro_rules! m { ($e:expr) => { $e } } | 679 | macro_rules! m { ($e:expr) => { $e } } |
685 | fn quux(x: i32) { | 680 | fn quux(x: i32) { |
686 | let y = 92; | 681 | let y = 92; |
687 | m!(x<|> | 682 | m!(x$0 |
688 | } | 683 | } |
689 | "#, | 684 | "#, |
690 | expect![[r#" | 685 | expect![[r#" |
@@ -702,7 +697,7 @@ fn quux(x: i32) { | |||
702 | r#" | 697 | r#" |
703 | use spam::Quux; | 698 | use spam::Quux; |
704 | 699 | ||
705 | fn main() { <|> } | 700 | fn main() { $0 } |
706 | "#, | 701 | "#, |
707 | expect![[r#" | 702 | expect![[r#" |
708 | fn main() fn main() | 703 | fn main() fn main() |
@@ -719,7 +714,7 @@ enum Foo { Bar, Baz, Quux } | |||
719 | 714 | ||
720 | fn main() { | 715 | fn main() { |
721 | let foo = Foo::Quux; | 716 | let foo = Foo::Quux; |
722 | match foo { Qu<|> } | 717 | match foo { Qu$0 } |
723 | } | 718 | } |
724 | "#, | 719 | "#, |
725 | expect![[r#" | 720 | expect![[r#" |
@@ -739,7 +734,7 @@ enum Foo { Bar, Baz, Quux } | |||
739 | 734 | ||
740 | fn main() { | 735 | fn main() { |
741 | let foo = Foo::Quux; | 736 | let foo = Foo::Quux; |
742 | match &foo { Qu<|> } | 737 | match &foo { Qu$0 } |
743 | } | 738 | } |
744 | "#, | 739 | "#, |
745 | expect![[r#" | 740 | expect![[r#" |
@@ -759,7 +754,7 @@ enum Foo { Bar, Baz, Quux } | |||
759 | 754 | ||
760 | fn main() { | 755 | fn main() { |
761 | let foo = Foo::Quux; | 756 | let foo = Foo::Quux; |
762 | if let Qu<|> = foo { } | 757 | if let Qu$0 = foo { } |
763 | } | 758 | } |
764 | "#, | 759 | "#, |
765 | expect![[r#" | 760 | expect![[r#" |
@@ -776,7 +771,7 @@ fn main() { | |||
776 | check( | 771 | check( |
777 | r#" | 772 | r#" |
778 | enum Foo { Bar, Baz, Quux } | 773 | enum Foo { Bar, Baz, Quux } |
779 | fn main() { let foo: Foo = Q<|> } | 774 | fn main() { let foo: Foo = Q$0 } |
780 | "#, | 775 | "#, |
781 | expect![[r#" | 776 | expect![[r#" |
782 | ev Foo::Bar () | 777 | ev Foo::Bar () |
@@ -793,7 +788,7 @@ fn main() { let foo: Foo = Q<|> } | |||
793 | check( | 788 | check( |
794 | r#" | 789 | r#" |
795 | mod m { pub enum E { V } } | 790 | mod m { pub enum E { V } } |
796 | fn f() -> m::E { V<|> } | 791 | fn f() -> m::E { V$0 } |
797 | "#, | 792 | "#, |
798 | expect![[r#" | 793 | expect![[r#" |
799 | ev m::E::V () | 794 | ev m::E::V () |
@@ -808,7 +803,7 @@ fn f() -> m::E { V<|> } | |||
808 | check( | 803 | check( |
809 | r#" | 804 | r#" |
810 | struct Foo; | 805 | struct Foo; |
811 | #[<|>] | 806 | #[$0] |
812 | fn f() {} | 807 | fn f() {} |
813 | "#, | 808 | "#, |
814 | expect![[""]], | 809 | expect![[""]], |
@@ -822,7 +817,7 @@ fn f() {} | |||
822 | trait MyTrait {} | 817 | trait MyTrait {} |
823 | struct MyStruct {} | 818 | struct MyStruct {} |
824 | 819 | ||
825 | impl My<|> | 820 | impl My$0 |
826 | "#, | 821 | "#, |
827 | expect![[r#" | 822 | expect![[r#" |
828 | tp Self | 823 | tp Self |
@@ -835,7 +830,7 @@ impl My<|> | |||
835 | #[test] | 830 | #[test] |
836 | fn function_fuzzy_completion() { | 831 | fn function_fuzzy_completion() { |
837 | check_edit_with_config( | 832 | check_edit_with_config( |
838 | fuzzy_completion_config(), | 833 | TEST_CONFIG, |
839 | "stdin", | 834 | "stdin", |
840 | r#" | 835 | r#" |
841 | //- /lib.rs crate:dep | 836 | //- /lib.rs crate:dep |
@@ -845,7 +840,7 @@ pub mod io { | |||
845 | 840 | ||
846 | //- /main.rs crate:main deps:dep | 841 | //- /main.rs crate:main deps:dep |
847 | fn main() { | 842 | fn main() { |
848 | stdi<|> | 843 | stdi$0 |
849 | } | 844 | } |
850 | "#, | 845 | "#, |
851 | r#" | 846 | r#" |
@@ -861,7 +856,7 @@ fn main() { | |||
861 | #[test] | 856 | #[test] |
862 | fn macro_fuzzy_completion() { | 857 | fn macro_fuzzy_completion() { |
863 | check_edit_with_config( | 858 | check_edit_with_config( |
864 | fuzzy_completion_config(), | 859 | TEST_CONFIG, |
865 | "macro_with_curlies!", | 860 | "macro_with_curlies!", |
866 | r#" | 861 | r#" |
867 | //- /lib.rs crate:dep | 862 | //- /lib.rs crate:dep |
@@ -873,7 +868,7 @@ macro_rules! macro_with_curlies { | |||
873 | 868 | ||
874 | //- /main.rs crate:main deps:dep | 869 | //- /main.rs crate:main deps:dep |
875 | fn main() { | 870 | fn main() { |
876 | curli<|> | 871 | curli$0 |
877 | } | 872 | } |
878 | "#, | 873 | "#, |
879 | r#" | 874 | r#" |
@@ -889,7 +884,7 @@ fn main() { | |||
889 | #[test] | 884 | #[test] |
890 | fn struct_fuzzy_completion() { | 885 | fn struct_fuzzy_completion() { |
891 | check_edit_with_config( | 886 | check_edit_with_config( |
892 | fuzzy_completion_config(), | 887 | TEST_CONFIG, |
893 | "ThirdStruct", | 888 | "ThirdStruct", |
894 | r#" | 889 | r#" |
895 | //- /lib.rs crate:dep | 890 | //- /lib.rs crate:dep |
@@ -903,7 +898,7 @@ pub mod some_module { | |||
903 | use dep::{FirstStruct, some_module::SecondStruct}; | 898 | use dep::{FirstStruct, some_module::SecondStruct}; |
904 | 899 | ||
905 | fn main() { | 900 | fn main() { |
906 | this<|> | 901 | this$0 |
907 | } | 902 | } |
908 | "#, | 903 | "#, |
909 | r#" | 904 | r#" |
@@ -920,7 +915,7 @@ fn main() { | |||
920 | fn fuzzy_completions_come_in_specific_order() { | 915 | fn fuzzy_completions_come_in_specific_order() { |
921 | mark::check!(certain_fuzzy_order_test); | 916 | mark::check!(certain_fuzzy_order_test); |
922 | check_with_config( | 917 | check_with_config( |
923 | fuzzy_completion_config(), | 918 | TEST_CONFIG, |
924 | r#" | 919 | r#" |
925 | //- /lib.rs crate:dep | 920 | //- /lib.rs crate:dep |
926 | pub struct FirstStruct; | 921 | pub struct FirstStruct; |
@@ -941,7 +936,7 @@ pub mod some_module { | |||
941 | use dep::{FirstStruct, some_module::SecondStruct}; | 936 | use dep::{FirstStruct, some_module::SecondStruct}; |
942 | 937 | ||
943 | fn main() { | 938 | fn main() { |
944 | hir<|> | 939 | hir$0 |
945 | } | 940 | } |
946 | "#, | 941 | "#, |
947 | expect![[r#" | 942 | expect![[r#" |
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index 30577dc11..b4439b7d1 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -4,8 +4,7 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! completions if we are allowed to. | 5 | //! completions if we are allowed to. |
6 | 6 | ||
7 | use ide_db::helpers::insert_use::MergeBehavior; | 7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; |
8 | use rustc_hash::FxHashSet; | ||
9 | 8 | ||
10 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
11 | pub struct CompletionConfig { | 10 | pub struct CompletionConfig { |
@@ -15,49 +14,4 @@ pub struct CompletionConfig { | |||
15 | pub add_call_argument_snippets: bool, | 14 | pub add_call_argument_snippets: bool, |
16 | pub snippet_cap: Option<SnippetCap>, | 15 | pub snippet_cap: Option<SnippetCap>, |
17 | pub merge: Option<MergeBehavior>, | 16 | pub merge: Option<MergeBehavior>, |
18 | /// A set of capabilities, enabled on the client and supported on the server. | ||
19 | pub active_resolve_capabilities: FxHashSet<CompletionResolveCapability>, | ||
20 | } | ||
21 | |||
22 | /// A resolve capability, supported on the server. | ||
23 | /// If the client registers any completion resolve capabilities, | ||
24 | /// the server is able to render completion items' corresponding fields later, | ||
25 | /// not during an initial completion item request. | ||
26 | /// See https://github.com/rust-analyzer/rust-analyzer/issues/6366 for more details. | ||
27 | #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] | ||
28 | pub enum CompletionResolveCapability { | ||
29 | Documentation, | ||
30 | Detail, | ||
31 | AdditionalTextEdits, | ||
32 | } | ||
33 | |||
34 | impl CompletionConfig { | ||
35 | pub fn allow_snippets(&mut self, yes: bool) { | ||
36 | self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None } | ||
37 | } | ||
38 | |||
39 | /// Whether the completions' additional edits are calculated when sending an initional completions list | ||
40 | /// or later, in a separate resolve request. | ||
41 | pub fn resolve_additional_edits_lazily(&self) -> bool { | ||
42 | self.active_resolve_capabilities.contains(&CompletionResolveCapability::AdditionalTextEdits) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
47 | pub struct SnippetCap { | ||
48 | _private: (), | ||
49 | } | ||
50 | |||
51 | impl Default for CompletionConfig { | ||
52 | fn default() -> Self { | ||
53 | CompletionConfig { | ||
54 | enable_postfix_completions: true, | ||
55 | enable_autoimport_completions: true, | ||
56 | add_call_parenthesis: true, | ||
57 | add_call_argument_snippets: true, | ||
58 | snippet_cap: Some(SnippetCap { _private: () }), | ||
59 | merge: Some(MergeBehavior::Full), | ||
60 | active_resolve_capabilities: FxHashSet::default(), | ||
61 | } | ||
62 | } | ||
63 | } | 17 | } |
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs index 41de324d8..ebf28e887 100644 --- a/crates/completion/src/context.rs +++ b/crates/completion/src/context.rs | |||
@@ -63,7 +63,7 @@ pub(crate) struct CompletionContext<'a> { | |||
63 | pub(super) is_expr: bool, | 63 | pub(super) is_expr: bool, |
64 | /// Something is typed at the "top" level, in module or impl/trait. | 64 | /// Something is typed at the "top" level, in module or impl/trait. |
65 | pub(super) is_new_item: bool, | 65 | pub(super) is_new_item: bool, |
66 | /// The receiver if this is a field or method access, i.e. writing something.<|> | 66 | /// The receiver if this is a field or method access, i.e. writing something.$0 |
67 | pub(super) dot_receiver: Option<ast::Expr>, | 67 | pub(super) dot_receiver: Option<ast::Expr>, |
68 | pub(super) dot_receiver_is_ambiguous_float_literal: bool, | 68 | pub(super) dot_receiver_is_ambiguous_float_literal: bool, |
69 | /// If this is a call (method or function) in particular, i.e. the () are already there. | 69 | /// If this is a call (method or function) in particular, i.e. the () are already there. |
@@ -228,9 +228,9 @@ impl<'a> CompletionContext<'a> { | |||
228 | 228 | ||
229 | /// Checks whether completions in that particular case don't make much sense. | 229 | /// Checks whether completions in that particular case don't make much sense. |
230 | /// Examples: | 230 | /// Examples: |
231 | /// - `fn <|>` -- we expect function name, it's unlikely that "hint" will be helpful. | 231 | /// - `fn $0` -- we expect function name, it's unlikely that "hint" will be helpful. |
232 | /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. | 232 | /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. |
233 | /// - `for _ i<|>` -- obviously, it'll be "in" keyword. | 233 | /// - `for _ i$0` -- obviously, it'll be "in" keyword. |
234 | pub(crate) fn no_completion_required(&self) -> bool { | 234 | pub(crate) fn no_completion_required(&self) -> bool { |
235 | (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2 | 235 | (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2 |
236 | } | 236 | } |
@@ -279,7 +279,7 @@ impl<'a> CompletionContext<'a> { | |||
279 | offset: TextSize, | 279 | offset: TextSize, |
280 | ) { | 280 | ) { |
281 | // FIXME: this is wrong in at least two cases: | 281 | // FIXME: this is wrong in at least two cases: |
282 | // * when there's no token `foo(<|>)` | 282 | // * when there's no token `foo($0)` |
283 | // * when there is a token, but it happens to have type of it's own | 283 | // * when there is a token, but it happens to have type of it's own |
284 | self.expected_type = self | 284 | self.expected_type = self |
285 | .token | 285 | .token |
@@ -458,7 +458,7 @@ impl<'a> CompletionContext<'a> { | |||
458 | } | 458 | } |
459 | if let Some(block) = ast::BlockExpr::cast(node) { | 459 | if let Some(block) = ast::BlockExpr::cast(node) { |
460 | return Some( | 460 | return Some( |
461 | block.expr().map(|e| e.syntax().text_range()) | 461 | block.tail_expr().map(|e| e.syntax().text_range()) |
462 | == Some(name_ref.syntax().text_range()), | 462 | == Some(name_ref.syntax().text_range()), |
463 | ); | 463 | ); |
464 | } | 464 | } |
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs index 65f8353e7..35af354b0 100644 --- a/crates/completion/src/item.rs +++ b/crates/completion/src/item.rs | |||
@@ -5,13 +5,11 @@ use std::fmt; | |||
5 | use hir::{Documentation, ModPath, Mutability}; | 5 | use hir::{Documentation, ModPath, Mutability}; |
6 | use ide_db::helpers::{ | 6 | use ide_db::helpers::{ |
7 | insert_use::{self, ImportScope, MergeBehavior}, | 7 | insert_use::{self, ImportScope, MergeBehavior}, |
8 | mod_path_to_ast, | 8 | mod_path_to_ast, SnippetCap, |
9 | }; | 9 | }; |
10 | use syntax::{algo, TextRange}; | 10 | use syntax::{algo, TextRange}; |
11 | use text_edit::TextEdit; | 11 | use text_edit::TextEdit; |
12 | 12 | ||
13 | use crate::config::SnippetCap; | ||
14 | |||
15 | /// `CompletionItem` describes a single completion variant in the editor pop-up. | 13 | /// `CompletionItem` describes a single completion variant in the editor pop-up. |
16 | /// It is basically a POD with various properties. To construct a | 14 | /// It is basically a POD with various properties. To construct a |
17 | /// `CompletionItem`, use `new` method and the `Builder` struct. | 15 | /// `CompletionItem`, use `new` method and the `Builder` struct. |
@@ -45,7 +43,7 @@ pub struct CompletionItem { | |||
45 | /// Lookup is used to check if completion item indeed can complete current | 43 | /// Lookup is used to check if completion item indeed can complete current |
46 | /// ident. | 44 | /// ident. |
47 | /// | 45 | /// |
48 | /// That is, in `foo.bar<|>` lookup of `abracadabra` will be accepted (it | 46 | /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it |
49 | /// contains `bar` sub sequence), and `quux` will rejected. | 47 | /// contains `bar` sub sequence), and `quux` will rejected. |
50 | lookup: Option<String>, | 48 | lookup: Option<String>, |
51 | 49 | ||
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index c57d05bbe..6cba88a6b 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -20,7 +20,7 @@ use text_edit::TextEdit; | |||
20 | use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; | 20 | use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; |
21 | 21 | ||
22 | pub use crate::{ | 22 | pub use crate::{ |
23 | config::{CompletionConfig, CompletionResolveCapability}, | 23 | config::CompletionConfig, |
24 | item::{CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, InsertTextFormat}, | 24 | item::{CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, InsertTextFormat}, |
25 | }; | 25 | }; |
26 | 26 | ||
@@ -47,8 +47,8 @@ pub use crate::{ | |||
47 | // - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` | 47 | // - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` |
48 | // - `expr.ref` -> `&expr` | 48 | // - `expr.ref` -> `&expr` |
49 | // - `expr.refm` -> `&mut expr` | 49 | // - `expr.refm` -> `&mut expr` |
50 | // - `expr.let` -> `let <|> = expr;` | 50 | // - `expr.let` -> `let $0 = expr;` |
51 | // - `expr.letm` -> `let mut <|> = expr;` | 51 | // - `expr.letm` -> `let mut $0 = expr;` |
52 | // - `expr.not` -> `!expr` | 52 | // - `expr.not` -> `!expr` |
53 | // - `expr.dbg` -> `dbg!(expr)` | 53 | // - `expr.dbg` -> `dbg!(expr)` |
54 | // - `expr.dbgr` -> `dbg!(&expr)` | 54 | // - `expr.dbgr` -> `dbg!(&expr)` |
@@ -92,7 +92,7 @@ pub use crate::{ | |||
92 | /// ```no_run | 92 | /// ```no_run |
93 | /// fn f() { | 93 | /// fn f() { |
94 | /// let foo = 92; | 94 | /// let foo = 92; |
95 | /// let _ = bar<|> | 95 | /// let _ = bar$0 |
96 | /// } | 96 | /// } |
97 | /// ``` | 97 | /// ``` |
98 | /// | 98 | /// |
@@ -158,8 +158,7 @@ pub fn resolve_completion_edits( | |||
158 | 158 | ||
159 | #[cfg(test)] | 159 | #[cfg(test)] |
160 | mod tests { | 160 | mod tests { |
161 | use crate::config::CompletionConfig; | 161 | use crate::test_utils::{self, TEST_CONFIG}; |
162 | use crate::test_utils; | ||
163 | 162 | ||
164 | struct DetailAndDocumentation<'a> { | 163 | struct DetailAndDocumentation<'a> { |
165 | detail: &'a str, | 164 | detail: &'a str, |
@@ -168,7 +167,7 @@ mod tests { | |||
168 | 167 | ||
169 | fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) { | 168 | fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) { |
170 | let (db, position) = test_utils::position(ra_fixture); | 169 | let (db, position) = test_utils::position(ra_fixture); |
171 | let config = CompletionConfig::default(); | 170 | let config = TEST_CONFIG; |
172 | let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into(); | 171 | let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into(); |
173 | for item in completions { | 172 | for item in completions { |
174 | if item.detail() == Some(expected.detail) { | 173 | if item.detail() == Some(expected.detail) { |
@@ -183,7 +182,7 @@ mod tests { | |||
183 | 182 | ||
184 | fn check_no_completion(ra_fixture: &str) { | 183 | fn check_no_completion(ra_fixture: &str) { |
185 | let (db, position) = test_utils::position(ra_fixture); | 184 | let (db, position) = test_utils::position(ra_fixture); |
186 | let config = CompletionConfig::default(); | 185 | let config = TEST_CONFIG; |
187 | 186 | ||
188 | let completions: Option<Vec<String>> = crate::completions(&db, &config, position) | 187 | let completions: Option<Vec<String>> = crate::completions(&db, &config, position) |
189 | .and_then(|completions| { | 188 | .and_then(|completions| { |
@@ -221,7 +220,7 @@ mod tests { | |||
221 | 220 | ||
222 | fn foo() { | 221 | fn foo() { |
223 | let bar = Bar; | 222 | let bar = Bar; |
224 | bar.fo<|>; | 223 | bar.fo$0; |
225 | } | 224 | } |
226 | "#, | 225 | "#, |
227 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, | 226 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, |
@@ -247,7 +246,7 @@ mod tests { | |||
247 | 246 | ||
248 | fn foo() { | 247 | fn foo() { |
249 | let bar = Bar; | 248 | let bar = Bar; |
250 | bar.fo<|>; | 249 | bar.fo$0; |
251 | } | 250 | } |
252 | "#, | 251 | "#, |
253 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, | 252 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, |
@@ -260,7 +259,7 @@ mod tests { | |||
260 | check_no_completion( | 259 | check_no_completion( |
261 | r#" | 260 | r#" |
262 | fn foo() { | 261 | fn foo() { |
263 | for i i<|> | 262 | for i i$0 |
264 | } | 263 | } |
265 | "#, | 264 | "#, |
266 | ); | 265 | ); |
@@ -271,7 +270,7 @@ mod tests { | |||
271 | fn foo() -> &'static str { "foo" } | 270 | fn foo() -> &'static str { "foo" } |
272 | 271 | ||
273 | fn bar() { | 272 | fn bar() { |
274 | for c in fo<|> | 273 | for c in fo$0 |
275 | } | 274 | } |
276 | "#, | 275 | "#, |
277 | DetailAndDocumentation { | 276 | DetailAndDocumentation { |
diff --git a/crates/completion/src/patterns.rs b/crates/completion/src/patterns.rs index b0f35f9bf..f3ce91dd1 100644 --- a/crates/completion/src/patterns.rs +++ b/crates/completion/src/patterns.rs | |||
@@ -5,7 +5,7 @@ use syntax::{ | |||
5 | ast::{self, LoopBodyOwner}, | 5 | ast::{self, LoopBodyOwner}, |
6 | match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, | 6 | match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, |
7 | SyntaxKind::*, | 7 | SyntaxKind::*, |
8 | SyntaxNode, SyntaxToken, | 8 | SyntaxNode, SyntaxToken, T, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | #[cfg(test)] | 11 | #[cfg(test)] |
@@ -20,7 +20,7 @@ pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool { | |||
20 | } | 20 | } |
21 | #[test] | 21 | #[test] |
22 | fn test_has_trait_parent() { | 22 | fn test_has_trait_parent() { |
23 | check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent); | 23 | check_pattern_is_applicable(r"trait A { f$0 }", has_trait_parent); |
24 | } | 24 | } |
25 | 25 | ||
26 | pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { | 26 | pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { |
@@ -32,7 +32,7 @@ pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { | |||
32 | } | 32 | } |
33 | #[test] | 33 | #[test] |
34 | fn test_has_impl_parent() { | 34 | fn test_has_impl_parent() { |
35 | check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent); | 35 | check_pattern_is_applicable(r"impl A { f$0 }", has_impl_parent); |
36 | } | 36 | } |
37 | 37 | ||
38 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { | 38 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { |
@@ -47,10 +47,10 @@ pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { | |||
47 | } | 47 | } |
48 | #[test] | 48 | #[test] |
49 | fn test_inside_impl_trait_block() { | 49 | fn test_inside_impl_trait_block() { |
50 | check_pattern_is_applicable(r"impl Foo for Bar { f<|> }", inside_impl_trait_block); | 50 | check_pattern_is_applicable(r"impl Foo for Bar { f$0 }", inside_impl_trait_block); |
51 | check_pattern_is_applicable(r"impl Foo for Bar { fn f<|> }", inside_impl_trait_block); | 51 | check_pattern_is_applicable(r"impl Foo for Bar { fn f$0 }", inside_impl_trait_block); |
52 | check_pattern_is_not_applicable(r"impl A { f<|> }", inside_impl_trait_block); | 52 | check_pattern_is_not_applicable(r"impl A { f$0 }", inside_impl_trait_block); |
53 | check_pattern_is_not_applicable(r"impl A { fn f<|> }", inside_impl_trait_block); | 53 | check_pattern_is_not_applicable(r"impl A { fn f$0 }", inside_impl_trait_block); |
54 | } | 54 | } |
55 | 55 | ||
56 | pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { | 56 | pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { |
@@ -58,8 +58,8 @@ pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { | |||
58 | } | 58 | } |
59 | #[test] | 59 | #[test] |
60 | fn test_has_field_list_parent() { | 60 | fn test_has_field_list_parent() { |
61 | check_pattern_is_applicable(r"struct Foo { f<|> }", has_field_list_parent); | 61 | check_pattern_is_applicable(r"struct Foo { f$0 }", has_field_list_parent); |
62 | check_pattern_is_applicable(r"struct Foo { f<|> pub f: i32}", has_field_list_parent); | 62 | check_pattern_is_applicable(r"struct Foo { f$0 pub f: i32}", has_field_list_parent); |
63 | } | 63 | } |
64 | 64 | ||
65 | pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { | 65 | pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { |
@@ -67,7 +67,7 @@ pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { | |||
67 | } | 67 | } |
68 | #[test] | 68 | #[test] |
69 | fn test_has_block_expr_parent() { | 69 | fn test_has_block_expr_parent() { |
70 | check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent); | 70 | check_pattern_is_applicable(r"fn my_fn() { let a = 2; f$0 }", has_block_expr_parent); |
71 | } | 71 | } |
72 | 72 | ||
73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | 73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { |
@@ -75,8 +75,8 @@ pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | |||
75 | } | 75 | } |
76 | #[test] | 76 | #[test] |
77 | fn test_has_bind_pat_parent() { | 77 | fn test_has_bind_pat_parent() { |
78 | check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent); | 78 | check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent); |
79 | check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent); | 79 | check_pattern_is_applicable(r"fn my_fn() { let m$0 }", has_bind_pat_parent); |
80 | } | 80 | } |
81 | 81 | ||
82 | pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool { | 82 | pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool { |
@@ -86,8 +86,8 @@ pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool { | |||
86 | } | 86 | } |
87 | #[test] | 87 | #[test] |
88 | fn test_has_ref_parent() { | 88 | fn test_has_ref_parent() { |
89 | check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent); | 89 | check_pattern_is_applicable(r"fn my_fn(&m$0) {}", has_ref_parent); |
90 | check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent); | 90 | check_pattern_is_applicable(r"fn my() { let &m$0 }", has_ref_parent); |
91 | } | 91 | } |
92 | 92 | ||
93 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { | 93 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { |
@@ -99,8 +99,8 @@ pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> boo | |||
99 | } | 99 | } |
100 | #[test] | 100 | #[test] |
101 | fn test_has_item_list_or_source_file_parent() { | 101 | fn test_has_item_list_or_source_file_parent() { |
102 | check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent); | 102 | check_pattern_is_applicable(r"i$0", has_item_list_or_source_file_parent); |
103 | check_pattern_is_applicable(r"mod foo { f<|> }", has_item_list_or_source_file_parent); | 103 | check_pattern_is_applicable(r"mod foo { f$0 }", has_item_list_or_source_file_parent); |
104 | } | 104 | } |
105 | 105 | ||
106 | pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { | 106 | pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { |
@@ -112,26 +112,26 @@ pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { | |||
112 | } | 112 | } |
113 | #[test] | 113 | #[test] |
114 | fn test_is_match_arm() { | 114 | fn test_is_match_arm() { |
115 | check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm); | 115 | check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); |
116 | } | 116 | } |
117 | 117 | ||
118 | pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { | 118 | pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { |
119 | element | 119 | element |
120 | .into_token() | 120 | .into_token() |
121 | .and_then(|it| previous_non_trivia_token(it)) | 121 | .and_then(|it| previous_non_trivia_token(it)) |
122 | .filter(|it| it.kind() == UNSAFE_KW) | 122 | .filter(|it| it.kind() == T![unsafe]) |
123 | .is_some() | 123 | .is_some() |
124 | } | 124 | } |
125 | #[test] | 125 | #[test] |
126 | fn test_unsafe_is_prev() { | 126 | fn test_unsafe_is_prev() { |
127 | check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev); | 127 | check_pattern_is_applicable(r"unsafe i$0", unsafe_is_prev); |
128 | } | 128 | } |
129 | 129 | ||
130 | pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { | 130 | pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { |
131 | element | 131 | element |
132 | .into_token() | 132 | .into_token() |
133 | .and_then(|it| previous_non_trivia_token(it)) | 133 | .and_then(|it| previous_non_trivia_token(it)) |
134 | .filter(|it| it.kind() == IF_KW) | 134 | .filter(|it| it.kind() == T![if]) |
135 | .is_some() | 135 | .is_some() |
136 | } | 136 | } |
137 | 137 | ||
@@ -139,32 +139,32 @@ pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool { | |||
139 | element | 139 | element |
140 | .into_token() | 140 | .into_token() |
141 | .and_then(|it| previous_non_trivia_token(it)) | 141 | .and_then(|it| previous_non_trivia_token(it)) |
142 | .filter(|it| it.kind() == FN_KW) | 142 | .filter(|it| it.kind() == T![fn]) |
143 | .is_some() | 143 | .is_some() |
144 | } | 144 | } |
145 | #[test] | 145 | #[test] |
146 | fn test_fn_is_prev() { | 146 | fn test_fn_is_prev() { |
147 | check_pattern_is_applicable(r"fn l<|>", fn_is_prev); | 147 | check_pattern_is_applicable(r"fn l$0", fn_is_prev); |
148 | } | 148 | } |
149 | 149 | ||
150 | /// Check if the token previous to the previous one is `for`. | 150 | /// Check if the token previous to the previous one is `for`. |
151 | /// For example, `for _ i<|>` => true. | 151 | /// For example, `for _ i$0` => true. |
152 | pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { | 152 | pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { |
153 | element | 153 | element |
154 | .into_token() | 154 | .into_token() |
155 | .and_then(|it| previous_non_trivia_token(it)) | 155 | .and_then(|it| previous_non_trivia_token(it)) |
156 | .and_then(|it| previous_non_trivia_token(it)) | 156 | .and_then(|it| previous_non_trivia_token(it)) |
157 | .filter(|it| it.kind() == FOR_KW) | 157 | .filter(|it| it.kind() == T![for]) |
158 | .is_some() | 158 | .is_some() |
159 | } | 159 | } |
160 | #[test] | 160 | #[test] |
161 | fn test_for_is_prev2() { | 161 | fn test_for_is_prev2() { |
162 | check_pattern_is_applicable(r"for i i<|>", for_is_prev2); | 162 | check_pattern_is_applicable(r"for i i$0", for_is_prev2); |
163 | } | 163 | } |
164 | 164 | ||
165 | #[test] | 165 | #[test] |
166 | fn test_if_is_prev() { | 166 | fn test_if_is_prev() { |
167 | check_pattern_is_applicable(r"if l<|>", if_is_prev); | 167 | check_pattern_is_applicable(r"if l$0", if_is_prev); |
168 | } | 168 | } |
169 | 169 | ||
170 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { | 170 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { |
@@ -172,7 +172,7 @@ pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { | |||
172 | } | 172 | } |
173 | #[test] | 173 | #[test] |
174 | fn test_has_trait_as_prev_sibling() { | 174 | fn test_has_trait_as_prev_sibling() { |
175 | check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling); | 175 | check_pattern_is_applicable(r"trait A w$0 {}", has_trait_as_prev_sibling); |
176 | } | 176 | } |
177 | 177 | ||
178 | pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { | 178 | pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { |
@@ -180,7 +180,7 @@ pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { | |||
180 | } | 180 | } |
181 | #[test] | 181 | #[test] |
182 | fn test_has_impl_as_prev_sibling() { | 182 | fn test_has_impl_as_prev_sibling() { |
183 | check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling); | 183 | check_pattern_is_applicable(r"impl A w$0 {}", has_impl_as_prev_sibling); |
184 | } | 184 | } |
185 | 185 | ||
186 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | 186 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1ba7201a1..e93c59f71 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -11,13 +11,13 @@ pub(crate) mod type_alias; | |||
11 | mod builder_ext; | 11 | mod builder_ext; |
12 | 12 | ||
13 | use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; | 13 | use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; |
14 | use ide_db::RootDatabase; | 14 | use ide_db::{helpers::SnippetCap, RootDatabase}; |
15 | use syntax::TextRange; | 15 | use syntax::TextRange; |
16 | use test_utils::mark; | 16 | use test_utils::mark; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | config::SnippetCap, item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, | 19 | item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, |
20 | CompletionKind, CompletionScore, | 20 | CompletionScore, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; | 23 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; |
@@ -157,8 +157,7 @@ impl<'a> Render<'a> { | |||
157 | 157 | ||
158 | let kind = match resolution { | 158 | let kind = match resolution { |
159 | ScopeDef::ModuleDef(Function(func)) => { | 159 | ScopeDef::ModuleDef(Function(func)) => { |
160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); | 160 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); |
161 | return Some(item); | ||
162 | } | 161 | } |
163 | ScopeDef::ModuleDef(Variant(_)) | 162 | ScopeDef::ModuleDef(Variant(_)) |
164 | if self.ctx.completion.is_pat_binding_or_const | 163 | if self.ctx.completion.is_pat_binding_or_const |
@@ -321,8 +320,8 @@ mod tests { | |||
321 | use test_utils::mark; | 320 | use test_utils::mark; |
322 | 321 | ||
323 | use crate::{ | 322 | use crate::{ |
324 | test_utils::{check_edit, do_completion, get_all_items}, | 323 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, |
325 | CompletionConfig, CompletionKind, CompletionScore, | 324 | CompletionKind, CompletionScore, |
326 | }; | 325 | }; |
327 | 326 | ||
328 | fn check(ra_fixture: &str, expect: Expect) { | 327 | fn check(ra_fixture: &str, expect: Expect) { |
@@ -339,7 +338,7 @@ mod tests { | |||
339 | } | 338 | } |
340 | } | 339 | } |
341 | 340 | ||
342 | let mut completions = get_all_items(CompletionConfig::default(), ra_fixture); | 341 | let mut completions = get_all_items(TEST_CONFIG, ra_fixture); |
343 | completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); | 342 | completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); |
344 | let actual = completions | 343 | let actual = completions |
345 | .into_iter() | 344 | .into_iter() |
@@ -359,7 +358,7 @@ mod tests { | |||
359 | r#" | 358 | r#" |
360 | enum Foo { Foo { x: i32, y: i32 } } | 359 | enum Foo { Foo { x: i32, y: i32 } } |
361 | 360 | ||
362 | fn main() { Foo::Fo<|> } | 361 | fn main() { Foo::Fo$0 } |
363 | "#, | 362 | "#, |
364 | expect![[r#" | 363 | expect![[r#" |
365 | [ | 364 | [ |
@@ -382,7 +381,7 @@ fn main() { Foo::Fo<|> } | |||
382 | r#" | 381 | r#" |
383 | enum Foo { Foo (i32, i32) } | 382 | enum Foo { Foo (i32, i32) } |
384 | 383 | ||
385 | fn main() { Foo::Fo<|> } | 384 | fn main() { Foo::Fo$0 } |
386 | "#, | 385 | "#, |
387 | expect![[r#" | 386 | expect![[r#" |
388 | [ | 387 | [ |
@@ -407,7 +406,7 @@ fn main() { Foo::Fo<|> } | |||
407 | r#" | 406 | r#" |
408 | enum Foo { Foo } | 407 | enum Foo { Foo } |
409 | 408 | ||
410 | fn main() { Foo::Fo<|> } | 409 | fn main() { Foo::Fo$0 } |
411 | "#, | 410 | "#, |
412 | expect![[r#" | 411 | expect![[r#" |
413 | [ | 412 | [ |
@@ -431,7 +430,7 @@ fn main() { Foo::Fo<|> } | |||
431 | mod m { | 430 | mod m { |
432 | pub enum Spam { Foo, Bar(i32) } | 431 | pub enum Spam { Foo, Bar(i32) } |
433 | } | 432 | } |
434 | fn main() { let _: m::Spam = S<|> } | 433 | fn main() { let _: m::Spam = S$0 } |
435 | "#, | 434 | "#, |
436 | expect![[r#" | 435 | expect![[r#" |
437 | [ | 436 | [ |
@@ -484,7 +483,7 @@ fn something_deprecated() {} | |||
484 | #[deprecated(since = "1.0.0")] | 483 | #[deprecated(since = "1.0.0")] |
485 | fn something_else_deprecated() {} | 484 | fn something_else_deprecated() {} |
486 | 485 | ||
487 | fn main() { som<|> } | 486 | fn main() { som$0 } |
488 | "#, | 487 | "#, |
489 | expect![[r#" | 488 | expect![[r#" |
490 | [ | 489 | [ |
@@ -524,7 +523,7 @@ fn main() { som<|> } | |||
524 | check( | 523 | check( |
525 | r#" | 524 | r#" |
526 | struct A { #[deprecated] the_field: u32 } | 525 | struct A { #[deprecated] the_field: u32 } |
527 | fn foo() { A { the<|> } } | 526 | fn foo() { A { the$0 } } |
528 | "#, | 527 | "#, |
529 | expect![[r#" | 528 | expect![[r#" |
530 | [ | 529 | [ |
@@ -552,7 +551,7 @@ struct S { | |||
552 | } | 551 | } |
553 | impl S { | 552 | impl S { |
554 | /// Method docs | 553 | /// Method docs |
555 | fn bar(self) { self.<|> } | 554 | fn bar(self) { self.$0 } |
556 | }"#, | 555 | }"#, |
557 | expect![[r#" | 556 | expect![[r#" |
558 | [ | 557 | [ |
@@ -585,7 +584,7 @@ impl S { | |||
585 | 584 | ||
586 | check( | 585 | check( |
587 | r#" | 586 | r#" |
588 | use self::my<|>; | 587 | use self::my$0; |
589 | 588 | ||
590 | /// mod docs | 589 | /// mod docs |
591 | mod my { } | 590 | mod my { } |
@@ -644,7 +643,7 @@ impl S { | |||
644 | #[inline] | 643 | #[inline] |
645 | fn the_method(&self) { } | 644 | fn the_method(&self) { } |
646 | } | 645 | } |
647 | fn foo(s: S) { s.<|> } | 646 | fn foo(s: S) { s.$0 } |
648 | "#, | 647 | "#, |
649 | expect![[r#" | 648 | expect![[r#" |
650 | [ | 649 | [ |
@@ -672,7 +671,7 @@ fn foo(foo: u8, bar: u8) {} | |||
672 | struct ManualVtable { f: fn(u8, u8) } | 671 | struct ManualVtable { f: fn(u8, u8) } |
673 | 672 | ||
674 | fn main() -> ManualVtable { | 673 | fn main() -> ManualVtable { |
675 | ManualVtable { f: f<|> } | 674 | ManualVtable { f: f$0 } |
676 | } | 675 | } |
677 | "#, | 676 | "#, |
678 | r#" | 677 | r#" |
@@ -693,7 +692,7 @@ fn main() -> ManualVtable { | |||
693 | "foo", | 692 | "foo", |
694 | r#" | 693 | r#" |
695 | mod m { pub fn foo() {} } | 694 | mod m { pub fn foo() {} } |
696 | use crate::m::f<|>; | 695 | use crate::m::f$0; |
697 | "#, | 696 | "#, |
698 | r#" | 697 | r#" |
699 | mod m { pub fn foo() {} } | 698 | mod m { pub fn foo() {} } |
@@ -708,7 +707,7 @@ use crate::m::foo; | |||
708 | "foo", | 707 | "foo", |
709 | r#" | 708 | r#" |
710 | fn foo(x: i32) {} | 709 | fn foo(x: i32) {} |
711 | fn main() { f<|>(); } | 710 | fn main() { f$0(); } |
712 | "#, | 711 | "#, |
713 | r#" | 712 | r#" |
714 | fn foo(x: i32) {} | 713 | fn foo(x: i32) {} |
@@ -720,7 +719,7 @@ fn main() { foo(); } | |||
720 | r#" | 719 | r#" |
721 | struct Foo; | 720 | struct Foo; |
722 | impl Foo { fn foo(&self){} } | 721 | impl Foo { fn foo(&self){} } |
723 | fn f(foo: &Foo) { foo.f<|>(); } | 722 | fn f(foo: &Foo) { foo.f$0(); } |
724 | "#, | 723 | "#, |
725 | r#" | 724 | r#" |
726 | struct Foo; | 725 | struct Foo; |
@@ -737,7 +736,7 @@ fn f(foo: &Foo) { foo.foo(); } | |||
737 | "Vec", | 736 | "Vec", |
738 | r#" | 737 | r#" |
739 | struct Vec<T> {} | 738 | struct Vec<T> {} |
740 | fn foo(xs: Ve<|>) | 739 | fn foo(xs: Ve$0) |
741 | "#, | 740 | "#, |
742 | r#" | 741 | r#" |
743 | struct Vec<T> {} | 742 | struct Vec<T> {} |
@@ -748,7 +747,7 @@ fn foo(xs: Vec<$0>) | |||
748 | "Vec", | 747 | "Vec", |
749 | r#" | 748 | r#" |
750 | type Vec<T> = (T,); | 749 | type Vec<T> = (T,); |
751 | fn foo(xs: Ve<|>) | 750 | fn foo(xs: Ve$0) |
752 | "#, | 751 | "#, |
753 | r#" | 752 | r#" |
754 | type Vec<T> = (T,); | 753 | type Vec<T> = (T,); |
@@ -759,7 +758,7 @@ fn foo(xs: Vec<$0>) | |||
759 | "Vec", | 758 | "Vec", |
760 | r#" | 759 | r#" |
761 | struct Vec<T = i128> {} | 760 | struct Vec<T = i128> {} |
762 | fn foo(xs: Ve<|>) | 761 | fn foo(xs: Ve$0) |
763 | "#, | 762 | "#, |
764 | r#" | 763 | r#" |
765 | struct Vec<T = i128> {} | 764 | struct Vec<T = i128> {} |
@@ -770,7 +769,7 @@ fn foo(xs: Vec) | |||
770 | "Vec", | 769 | "Vec", |
771 | r#" | 770 | r#" |
772 | struct Vec<T> {} | 771 | struct Vec<T> {} |
773 | fn foo(xs: Ve<|><i128>) | 772 | fn foo(xs: Ve$0<i128>) |
774 | "#, | 773 | "#, |
775 | r#" | 774 | r#" |
776 | struct Vec<T> {} | 775 | struct Vec<T> {} |
@@ -786,7 +785,7 @@ fn foo(xs: Vec<i128>) | |||
786 | r#" | 785 | r#" |
787 | struct S { foo: i64, bar: u32, baz: u32 } | 786 | struct S { foo: i64, bar: u32, baz: u32 } |
788 | fn test(bar: u32) { } | 787 | fn test(bar: u32) { } |
789 | fn foo(s: S) { test(s.<|>) } | 788 | fn foo(s: S) { test(s.$0) } |
790 | "#, | 789 | "#, |
791 | expect![[r#" | 790 | expect![[r#" |
792 | fd bar [type+name] | 791 | fd bar [type+name] |
@@ -803,7 +802,7 @@ fn foo(s: S) { test(s.<|>) } | |||
803 | r#" | 802 | r#" |
804 | struct A { foo: i64, bar: u32, baz: u32 } | 803 | struct A { foo: i64, bar: u32, baz: u32 } |
805 | struct B { x: (), y: f32, bar: u32 } | 804 | struct B { x: (), y: f32, bar: u32 } |
806 | fn foo(a: A) { B { bar: a.<|> }; } | 805 | fn foo(a: A) { B { bar: a.$0 }; } |
807 | "#, | 806 | "#, |
808 | expect![[r#" | 807 | expect![[r#" |
809 | fd bar [type+name] | 808 | fd bar [type+name] |
@@ -820,7 +819,7 @@ fn foo(a: A) { B { bar: a.<|> }; } | |||
820 | struct A { foo: i64, bar: u32, baz: u32 } | 819 | struct A { foo: i64, bar: u32, baz: u32 } |
821 | struct B { x: (), y: f32, bar: u32 } | 820 | struct B { x: (), y: f32, bar: u32 } |
822 | fn f(foo: i64) { } | 821 | fn f(foo: i64) { } |
823 | fn foo(a: A) { B { bar: f(a.<|>) }; } | 822 | fn foo(a: A) { B { bar: f(a.$0) }; } |
824 | "#, | 823 | "#, |
825 | expect![[r#" | 824 | expect![[r#" |
826 | fd foo [type+name] | 825 | fd foo [type+name] |
@@ -833,7 +832,7 @@ fn foo(a: A) { B { bar: f(a.<|>) }; } | |||
833 | struct A { foo: i64, bar: u32, baz: u32 } | 832 | struct A { foo: i64, bar: u32, baz: u32 } |
834 | struct B { x: (), y: f32, bar: u32 } | 833 | struct B { x: (), y: f32, bar: u32 } |
835 | fn f(foo: i64) { } | 834 | fn f(foo: i64) { } |
836 | fn foo(a: A) { f(B { bar: a.<|> }); } | 835 | fn foo(a: A) { f(B { bar: a.$0 }); } |
837 | "#, | 836 | "#, |
838 | expect![[r#" | 837 | expect![[r#" |
839 | fd bar [type+name] | 838 | fd bar [type+name] |
@@ -848,7 +847,7 @@ fn foo(a: A) { f(B { bar: a.<|> }); } | |||
848 | check_scores( | 847 | check_scores( |
849 | r#" | 848 | r#" |
850 | struct WorldSnapshot { _f: () }; | 849 | struct WorldSnapshot { _f: () }; |
851 | fn go(world: &WorldSnapshot) { go(w<|>) } | 850 | fn go(world: &WorldSnapshot) { go(w$0) } |
852 | "#, | 851 | "#, |
853 | expect![[r#" | 852 | expect![[r#" |
854 | bn world [type+name] | 853 | bn world [type+name] |
@@ -863,7 +862,7 @@ fn go(world: &WorldSnapshot) { go(w<|>) } | |||
863 | check_scores( | 862 | check_scores( |
864 | r#" | 863 | r#" |
865 | struct Foo; | 864 | struct Foo; |
866 | fn f(foo: &Foo) { f(foo, w<|>) } | 865 | fn f(foo: &Foo) { f(foo, w$0) } |
867 | "#, | 866 | "#, |
868 | expect![[r#" | 867 | expect![[r#" |
869 | st Foo [] | 868 | st Foo [] |
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs index 039bdabc0..ce924f309 100644 --- a/crates/completion/src/render/const_.rs +++ b/crates/completion/src/render/const_.rs | |||
@@ -15,7 +15,7 @@ pub(crate) fn render_const<'a>( | |||
15 | ctx: RenderContext<'a>, | 15 | ctx: RenderContext<'a>, |
16 | const_: hir::Const, | 16 | const_: hir::Const, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
18 | ConstRender::new(ctx, const_).render() | 18 | ConstRender::new(ctx, const_)?.render() |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -26,9 +26,9 @@ struct ConstRender<'a> { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | impl<'a> ConstRender<'a> { | 28 | impl<'a> ConstRender<'a> { |
29 | fn new(ctx: RenderContext<'a>, const_: hir::Const) -> ConstRender<'a> { | 29 | fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> { |
30 | let ast_node = const_.source(ctx.db()).value; | 30 | let ast_node = const_.source(ctx.db())?.value; |
31 | ConstRender { ctx, const_, ast_node } | 31 | Some(ConstRender { ctx, const_, ast_node }) |
32 | } | 32 | } |
33 | 33 | ||
34 | fn render(self) -> Option<CompletionItem> { | 34 | fn render(self) -> Option<CompletionItem> { |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index 732e139ec..89fb49773 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -115,7 +115,7 @@ mod tests { | |||
115 | enum Option<T> { Some(T), None } | 115 | enum Option<T> { Some(T), None } |
116 | use Option::*; | 116 | use Option::*; |
117 | fn main() -> Option<i32> { | 117 | fn main() -> Option<i32> { |
118 | Som<|> | 118 | Som$0 |
119 | } | 119 | } |
120 | "#, | 120 | "#, |
121 | r#" | 121 | r#" |
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index 316e05b52..f5b0ce3e3 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -14,9 +14,9 @@ pub(crate) fn render_fn<'a>( | |||
14 | import_to_add: Option<ImportEdit>, | 14 | import_to_add: Option<ImportEdit>, |
15 | local_name: Option<String>, | 15 | local_name: Option<String>, |
16 | fn_: hir::Function, | 16 | fn_: hir::Function, |
17 | ) -> CompletionItem { | 17 | ) -> Option<CompletionItem> { |
18 | let _p = profile::span("render_fn"); | 18 | let _p = profile::span("render_fn"); |
19 | FunctionRender::new(ctx, local_name, fn_).render(import_to_add) | 19 | Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add)) |
20 | } | 20 | } |
21 | 21 | ||
22 | #[derive(Debug)] | 22 | #[derive(Debug)] |
@@ -32,11 +32,11 @@ impl<'a> FunctionRender<'a> { | |||
32 | ctx: RenderContext<'a>, | 32 | ctx: RenderContext<'a>, |
33 | local_name: Option<String>, | 33 | local_name: Option<String>, |
34 | fn_: hir::Function, | 34 | fn_: hir::Function, |
35 | ) -> FunctionRender<'a> { | 35 | ) -> Option<FunctionRender<'a>> { |
36 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); | 36 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); |
37 | let ast_node = fn_.source(ctx.db()).value; | 37 | let ast_node = fn_.source(ctx.db())?.value; |
38 | 38 | ||
39 | FunctionRender { ctx, name, func: fn_, ast_node } | 39 | Some(FunctionRender { ctx, name, func: fn_, ast_node }) |
40 | } | 40 | } |
41 | 41 | ||
42 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { | 42 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { |
@@ -113,7 +113,7 @@ mod tests { | |||
113 | use test_utils::mark; | 113 | use test_utils::mark; |
114 | 114 | ||
115 | use crate::{ | 115 | use crate::{ |
116 | test_utils::{check_edit, check_edit_with_config}, | 116 | test_utils::{check_edit, check_edit_with_config, TEST_CONFIG}, |
117 | CompletionConfig, | 117 | CompletionConfig, |
118 | }; | 118 | }; |
119 | 119 | ||
@@ -124,7 +124,7 @@ mod tests { | |||
124 | "no_args", | 124 | "no_args", |
125 | r#" | 125 | r#" |
126 | fn no_args() {} | 126 | fn no_args() {} |
127 | fn main() { no_<|> } | 127 | fn main() { no_$0 } |
128 | "#, | 128 | "#, |
129 | r#" | 129 | r#" |
130 | fn no_args() {} | 130 | fn no_args() {} |
@@ -136,7 +136,7 @@ fn main() { no_args()$0 } | |||
136 | "with_args", | 136 | "with_args", |
137 | r#" | 137 | r#" |
138 | fn with_args(x: i32, y: String) {} | 138 | fn with_args(x: i32, y: String) {} |
139 | fn main() { with_<|> } | 139 | fn main() { with_$0 } |
140 | "#, | 140 | "#, |
141 | r#" | 141 | r#" |
142 | fn with_args(x: i32, y: String) {} | 142 | fn with_args(x: i32, y: String) {} |
@@ -151,7 +151,7 @@ struct S; | |||
151 | impl S { | 151 | impl S { |
152 | fn foo(&self) {} | 152 | fn foo(&self) {} |
153 | } | 153 | } |
154 | fn bar(s: &S) { s.f<|> } | 154 | fn bar(s: &S) { s.f$0 } |
155 | "#, | 155 | "#, |
156 | r#" | 156 | r#" |
157 | struct S; | 157 | struct S; |
@@ -170,7 +170,7 @@ impl S { | |||
170 | fn foo(&self, x: i32) {} | 170 | fn foo(&self, x: i32) {} |
171 | } | 171 | } |
172 | fn bar(s: &S) { | 172 | fn bar(s: &S) { |
173 | s.f<|> | 173 | s.f$0 |
174 | } | 174 | } |
175 | "#, | 175 | "#, |
176 | r#" | 176 | r#" |
@@ -195,7 +195,7 @@ struct S; | |||
195 | impl S { | 195 | impl S { |
196 | fn foo(&self) {} | 196 | fn foo(&self) {} |
197 | } | 197 | } |
198 | fn main() { S::f<|> } | 198 | fn main() { S::f$0 } |
199 | "#, | 199 | "#, |
200 | r#" | 200 | r#" |
201 | struct S; | 201 | struct S; |
@@ -211,11 +211,11 @@ fn main() { S::foo(${1:&self})$0 } | |||
211 | fn suppress_arg_snippets() { | 211 | fn suppress_arg_snippets() { |
212 | mark::check!(suppress_arg_snippets); | 212 | mark::check!(suppress_arg_snippets); |
213 | check_edit_with_config( | 213 | check_edit_with_config( |
214 | CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() }, | 214 | CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG }, |
215 | "with_args", | 215 | "with_args", |
216 | r#" | 216 | r#" |
217 | fn with_args(x: i32, y: String) {} | 217 | fn with_args(x: i32, y: String) {} |
218 | fn main() { with_<|> } | 218 | fn main() { with_$0 } |
219 | "#, | 219 | "#, |
220 | r#" | 220 | r#" |
221 | fn with_args(x: i32, y: String) {} | 221 | fn with_args(x: i32, y: String) {} |
@@ -230,7 +230,7 @@ fn main() { with_args($0) } | |||
230 | "foo", | 230 | "foo", |
231 | r#" | 231 | r#" |
232 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | 232 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} |
233 | fn main() { f<|> } | 233 | fn main() { f$0 } |
234 | "#, | 234 | "#, |
235 | r#" | 235 | r#" |
236 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | 236 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} |
@@ -248,7 +248,7 @@ struct Foo {} | |||
248 | fn ref_arg(x: &Foo) {} | 248 | fn ref_arg(x: &Foo) {} |
249 | fn main() { | 249 | fn main() { |
250 | let x = Foo {}; | 250 | let x = Foo {}; |
251 | ref_ar<|> | 251 | ref_ar$0 |
252 | } | 252 | } |
253 | "#, | 253 | "#, |
254 | r#" | 254 | r#" |
@@ -271,7 +271,7 @@ struct Foo {} | |||
271 | fn ref_arg(x: &mut Foo) {} | 271 | fn ref_arg(x: &mut Foo) {} |
272 | fn main() { | 272 | fn main() { |
273 | let x = Foo {}; | 273 | let x = Foo {}; |
274 | ref_ar<|> | 274 | ref_ar$0 |
275 | } | 275 | } |
276 | "#, | 276 | "#, |
277 | r#" | 277 | r#" |
@@ -299,7 +299,7 @@ impl Bar { | |||
299 | fn main() { | 299 | fn main() { |
300 | let x = Foo {}; | 300 | let x = Foo {}; |
301 | let y = Bar {}; | 301 | let y = Bar {}; |
302 | y.<|> | 302 | y.$0 |
303 | } | 303 | } |
304 | "#, | 304 | "#, |
305 | r#" | 305 | r#" |
@@ -326,7 +326,7 @@ fn main() { | |||
326 | fn take_mutably(mut x: &i32) {} | 326 | fn take_mutably(mut x: &i32) {} |
327 | 327 | ||
328 | fn main() { | 328 | fn main() { |
329 | take_m<|> | 329 | take_m$0 |
330 | } | 330 | } |
331 | "#, | 331 | "#, |
332 | r#" | 332 | r#" |
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs index dac79592f..f893e420a 100644 --- a/crates/completion/src/render/macro_.rs +++ b/crates/completion/src/render/macro_.rs | |||
@@ -39,20 +39,13 @@ impl<'a> MacroRender<'a> { | |||
39 | } | 39 | } |
40 | 40 | ||
41 | fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { | 41 | fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { |
42 | // FIXME: Currently proc-macro do not have ast-node, | ||
43 | // such that it does not have source | ||
44 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
45 | if self.macro_.is_proc_macro() { | ||
46 | return None; | ||
47 | } | ||
48 | |||
49 | let mut builder = | 42 | let mut builder = |
50 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) | 43 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) |
51 | .kind(CompletionItemKind::Macro) | 44 | .kind(CompletionItemKind::Macro) |
52 | .set_documentation(self.docs.clone()) | 45 | .set_documentation(self.docs.clone()) |
53 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) | 46 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) |
54 | .add_import(import_to_add) | 47 | .add_import(import_to_add) |
55 | .detail(self.detail()); | 48 | .set_detail(self.detail()); |
56 | 49 | ||
57 | let needs_bang = self.needs_bang(); | 50 | let needs_bang = self.needs_bang(); |
58 | builder = match self.ctx.snippet_cap() { | 51 | builder = match self.ctx.snippet_cap() { |
@@ -95,9 +88,9 @@ impl<'a> MacroRender<'a> { | |||
95 | format!("{}!", self.name) | 88 | format!("{}!", self.name) |
96 | } | 89 | } |
97 | 90 | ||
98 | fn detail(&self) -> String { | 91 | fn detail(&self) -> Option<String> { |
99 | let ast_node = self.macro_.source(self.ctx.db()).value; | 92 | let ast_node = self.macro_.source(self.ctx.db())?.value; |
100 | macro_label(&ast_node) | 93 | Some(macro_label(&ast_node)) |
101 | } | 94 | } |
102 | } | 95 | } |
103 | 96 | ||
@@ -142,7 +135,7 @@ mod tests { | |||
142 | "frobnicate!", | 135 | "frobnicate!", |
143 | r#" | 136 | r#" |
144 | //- /main.rs crate:main deps:foo | 137 | //- /main.rs crate:main deps:foo |
145 | use foo::<|>; | 138 | use foo::$0; |
146 | //- /foo/lib.rs crate:foo | 139 | //- /foo/lib.rs crate:foo |
147 | #[macro_export] | 140 | #[macro_export] |
148 | macro_rules! frobnicate { () => () } | 141 | macro_rules! frobnicate { () => () } |
@@ -156,7 +149,7 @@ use foo::frobnicate; | |||
156 | "frobnicate!", | 149 | "frobnicate!", |
157 | r#" | 150 | r#" |
158 | macro_rules! frobnicate { () => () } | 151 | macro_rules! frobnicate { () => () } |
159 | fn main() { frob<|>!(); } | 152 | fn main() { frob$0!(); } |
160 | "#, | 153 | "#, |
161 | r#" | 154 | r#" |
162 | macro_rules! frobnicate { () => () } | 155 | macro_rules! frobnicate { () => () } |
@@ -180,7 +173,7 @@ fn main() { frobnicate!(); } | |||
180 | /// ``` | 173 | /// ``` |
181 | macro_rules! vec { () => {} } | 174 | macro_rules! vec { () => {} } |
182 | 175 | ||
183 | fn fn main() { v<|> } | 176 | fn fn main() { v$0 } |
184 | "#, | 177 | "#, |
185 | r#" | 178 | r#" |
186 | /// Creates a [`Vec`] containing the arguments. | 179 | /// Creates a [`Vec`] containing the arguments. |
@@ -205,7 +198,7 @@ fn fn main() { vec![$0] } | |||
205 | /// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, | 198 | /// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, |
206 | /// call as `let _=foo! { hello world };` | 199 | /// call as `let _=foo! { hello world };` |
207 | macro_rules! foo { () => {} } | 200 | macro_rules! foo { () => {} } |
208 | fn main() { <|> } | 201 | fn main() { $0 } |
209 | "#, | 202 | "#, |
210 | r#" | 203 | r#" |
211 | /// Foo | 204 | /// Foo |
diff --git a/crates/completion/src/render/pattern.rs b/crates/completion/src/render/pattern.rs index a3b6a3cac..61d8a17e5 100644 --- a/crates/completion/src/render/pattern.rs +++ b/crates/completion/src/render/pattern.rs | |||
@@ -1,12 +1,10 @@ | |||
1 | //! Renderer for patterns. | 1 | //! Renderer for patterns. |
2 | 2 | ||
3 | use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; | 3 | use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; |
4 | use ide_db::helpers::SnippetCap; | ||
4 | use itertools::Itertools; | 5 | use itertools::Itertools; |
5 | 6 | ||
6 | use crate::{ | 7 | use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind}; |
7 | config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem, | ||
8 | CompletionItemKind, | ||
9 | }; | ||
10 | 8 | ||
11 | fn visible_fields( | 9 | fn visible_fields( |
12 | ctx: &RenderContext<'_>, | 10 | ctx: &RenderContext<'_>, |
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs index 9605c7fa9..69b445b9c 100644 --- a/crates/completion/src/render/type_alias.rs +++ b/crates/completion/src/render/type_alias.rs | |||
@@ -15,7 +15,7 @@ pub(crate) fn render_type_alias<'a>( | |||
15 | ctx: RenderContext<'a>, | 15 | ctx: RenderContext<'a>, |
16 | type_alias: hir::TypeAlias, | 16 | type_alias: hir::TypeAlias, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
18 | TypeAliasRender::new(ctx, type_alias).render() | 18 | TypeAliasRender::new(ctx, type_alias)?.render() |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -26,9 +26,9 @@ struct TypeAliasRender<'a> { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | impl<'a> TypeAliasRender<'a> { | 28 | impl<'a> TypeAliasRender<'a> { |
29 | fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> TypeAliasRender<'a> { | 29 | fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> { |
30 | let ast_node = type_alias.source(ctx.db()).value; | 30 | let ast_node = type_alias.source(ctx.db())?.value; |
31 | TypeAliasRender { ctx, type_alias, ast_node } | 31 | Some(TypeAliasRender { ctx, type_alias, ast_node }) |
32 | } | 32 | } |
33 | 33 | ||
34 | fn render(self) -> Option<CompletionItem> { | 34 | fn render(self) -> Option<CompletionItem> { |
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs index eb0c16f52..3f4b9d4ac 100644 --- a/crates/completion/src/test_utils.rs +++ b/crates/completion/src/test_utils.rs | |||
@@ -1,8 +1,11 @@ | |||
1 | //! Runs completion for testing purposes. | 1 | //! Runs completion for testing purposes. |
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::base_db::{fixture::ChangeFixture, FileLoader, FilePosition}; | 4 | use ide_db::{ |
5 | use ide_db::RootDatabase; | 5 | base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, |
6 | helpers::{insert_use::MergeBehavior, SnippetCap}, | ||
7 | RootDatabase, | ||
8 | }; | ||
6 | use itertools::Itertools; | 9 | use itertools::Itertools; |
7 | use stdx::{format_to, trim_indent}; | 10 | use stdx::{format_to, trim_indent}; |
8 | use syntax::{AstNode, NodeOrToken, SyntaxElement}; | 11 | use syntax::{AstNode, NodeOrToken, SyntaxElement}; |
@@ -10,12 +13,21 @@ use test_utils::{assert_eq_text, RangeOrOffset}; | |||
10 | 13 | ||
11 | use crate::{item::CompletionKind, CompletionConfig, CompletionItem}; | 14 | use crate::{item::CompletionKind, CompletionConfig, CompletionItem}; |
12 | 15 | ||
13 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 16 | pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { |
17 | enable_postfix_completions: true, | ||
18 | enable_autoimport_completions: true, | ||
19 | add_call_parenthesis: true, | ||
20 | add_call_argument_snippets: true, | ||
21 | snippet_cap: SnippetCap::new(true), | ||
22 | merge: Some(MergeBehavior::Full), | ||
23 | }; | ||
24 | |||
25 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | ||
14 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 26 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { |
15 | let change_fixture = ChangeFixture::parse(ra_fixture); | 27 | let change_fixture = ChangeFixture::parse(ra_fixture); |
16 | let mut database = RootDatabase::default(); | 28 | let mut database = RootDatabase::default(); |
17 | database.apply_change(change_fixture.change); | 29 | database.apply_change(change_fixture.change); |
18 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 30 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
19 | let offset = match range_or_offset { | 31 | let offset = match range_or_offset { |
20 | RangeOrOffset::Range(_) => panic!(), | 32 | RangeOrOffset::Range(_) => panic!(), |
21 | RangeOrOffset::Offset(it) => it, | 33 | RangeOrOffset::Offset(it) => it, |
@@ -24,7 +36,7 @@ pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | |||
24 | } | 36 | } |
25 | 37 | ||
26 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | 38 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { |
27 | do_completion_with_config(CompletionConfig::default(), code, kind) | 39 | do_completion_with_config(TEST_CONFIG, code, kind) |
28 | } | 40 | } |
29 | 41 | ||
30 | pub(crate) fn do_completion_with_config( | 42 | pub(crate) fn do_completion_with_config( |
@@ -39,7 +51,7 @@ pub(crate) fn do_completion_with_config( | |||
39 | } | 51 | } |
40 | 52 | ||
41 | pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { | 53 | pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { |
42 | completion_list_with_config(CompletionConfig::default(), code, kind) | 54 | completion_list_with_config(TEST_CONFIG, code, kind) |
43 | } | 55 | } |
44 | 56 | ||
45 | pub(crate) fn completion_list_with_config( | 57 | pub(crate) fn completion_list_with_config( |
@@ -76,7 +88,7 @@ fn monospace_width(s: &str) -> usize { | |||
76 | } | 88 | } |
77 | 89 | ||
78 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 90 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
79 | check_edit_with_config(CompletionConfig::default(), what, ra_fixture_before, ra_fixture_after) | 91 | check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) |
80 | } | 92 | } |
81 | 93 | ||
82 | pub(crate) fn check_edit_with_config( | 94 | pub(crate) fn check_edit_with_config( |
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 3d9436d69..1d19c7886 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml | |||
@@ -12,8 +12,9 @@ doctest = false | |||
12 | [dependencies] | 12 | [dependencies] |
13 | crossbeam-channel = "0.5.0" | 13 | crossbeam-channel = "0.5.0" |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | cargo_metadata = "=0.12.0" | 15 | cargo_metadata = "0.12.2" |
16 | serde_json = "1.0.48" | 16 | serde_json = "1.0.48" |
17 | jod-thread = "0.1.1" | 17 | jod-thread = "0.1.1" |
18 | 18 | ||
19 | toolchain = { path = "../toolchain", version = "0.0.0" } | 19 | toolchain = { path = "../toolchain", version = "0.0.0" } |
20 | stdx = { path = "../stdx", version = "0.0.0" } | ||
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index d982c5f29..4388e8c67 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs | |||
@@ -5,13 +5,13 @@ | |||
5 | use std::{ | 5 | use std::{ |
6 | fmt, | 6 | fmt, |
7 | io::{self, BufReader}, | 7 | io::{self, BufReader}, |
8 | ops, | ||
9 | path::PathBuf, | 8 | path::PathBuf, |
10 | process::{self, Command, Stdio}, | 9 | process::{self, Command, Stdio}, |
11 | time::Duration, | 10 | time::Duration, |
12 | }; | 11 | }; |
13 | 12 | ||
14 | use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; | 13 | use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; |
14 | use stdx::JodChild; | ||
15 | 15 | ||
16 | pub use cargo_metadata::diagnostic::{ | 16 | pub use cargo_metadata::diagnostic::{ |
17 | Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, | 17 | Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, |
@@ -323,24 +323,3 @@ impl CargoActor { | |||
323 | Ok(read_at_least_one_message) | 323 | Ok(read_at_least_one_message) |
324 | } | 324 | } |
325 | } | 325 | } |
326 | |||
327 | struct JodChild(process::Child); | ||
328 | |||
329 | impl ops::Deref for JodChild { | ||
330 | type Target = process::Child; | ||
331 | fn deref(&self) -> &process::Child { | ||
332 | &self.0 | ||
333 | } | ||
334 | } | ||
335 | |||
336 | impl ops::DerefMut for JodChild { | ||
337 | fn deref_mut(&mut self) -> &mut process::Child { | ||
338 | &mut self.0 | ||
339 | } | ||
340 | } | ||
341 | |||
342 | impl Drop for JodChild { | ||
343 | fn drop(&mut self) { | ||
344 | let _ = self.0.kill(); | ||
345 | } | ||
346 | } | ||
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 6dc5ad63b..d4ea7327e 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml | |||
@@ -14,7 +14,7 @@ log = "0.4.8" | |||
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | either = "1.5.3" | 15 | either = "1.5.3" |
16 | arrayvec = "0.5.1" | 16 | arrayvec = "0.5.1" |
17 | itertools = "0.9.0" | 17 | itertools = "0.10.0" |
18 | 18 | ||
19 | stdx = { path = "../stdx", version = "0.0.0" } | 19 | stdx = { path = "../stdx", version = "0.0.0" } |
20 | syntax = { path = "../syntax", version = "0.0.0" } | 20 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index d32ce37ed..99fb65bac 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -3,15 +3,15 @@ use hir_def::{ | |||
3 | attr::{Attrs, Documentation}, | 3 | attr::{Attrs, Documentation}, |
4 | path::ModPath, | 4 | path::ModPath, |
5 | resolver::HasResolver, | 5 | resolver::HasResolver, |
6 | AttrDefId, ModuleDefId, | 6 | AttrDefId, GenericParamId, ModuleDefId, |
7 | }; | 7 | }; |
8 | use hir_expand::hygiene::Hygiene; | 8 | use hir_expand::hygiene::Hygiene; |
9 | use hir_ty::db::HirDatabase; | 9 | use hir_ty::db::HirDatabase; |
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Adt, Const, Enum, Field, Function, MacroDef, Module, ModuleDef, Static, Struct, Trait, | 13 | Adt, Const, ConstParam, Enum, Field, Function, GenericParam, LifetimeParam, MacroDef, Module, |
14 | TypeAlias, Union, Variant, | 14 | ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub trait HasAttrs { | 17 | pub trait HasAttrs { |
@@ -62,25 +62,27 @@ impl_has_attrs![ | |||
62 | (Function, FunctionId), | 62 | (Function, FunctionId), |
63 | (Adt, AdtId), | 63 | (Adt, AdtId), |
64 | (Module, ModuleId), | 64 | (Module, ModuleId), |
65 | (GenericParam, GenericParamId), | ||
65 | ]; | 66 | ]; |
66 | 67 | ||
67 | macro_rules! impl_has_attrs_adt { | 68 | macro_rules! impl_has_attrs_enum { |
68 | ($($adt:ident),*) => {$( | 69 | ($($variant:ident),* for $enum:ident) => {$( |
69 | impl HasAttrs for $adt { | 70 | impl HasAttrs for $variant { |
70 | fn attrs(self, db: &dyn HirDatabase) -> Attrs { | 71 | fn attrs(self, db: &dyn HirDatabase) -> Attrs { |
71 | Adt::$adt(self).attrs(db) | 72 | $enum::$variant(self).attrs(db) |
72 | } | 73 | } |
73 | fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { | 74 | fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { |
74 | Adt::$adt(self).docs(db) | 75 | $enum::$variant(self).docs(db) |
75 | } | 76 | } |
76 | fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> { | 77 | fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> { |
77 | Adt::$adt(self).resolve_doc_path(db, link, ns) | 78 | $enum::$variant(self).resolve_doc_path(db, link, ns) |
78 | } | 79 | } |
79 | } | 80 | } |
80 | )*}; | 81 | )*}; |
81 | } | 82 | } |
82 | 83 | ||
83 | impl_has_attrs_adt![Struct, Union, Enum]; | 84 | impl_has_attrs_enum![Struct, Union, Enum for Adt]; |
85 | impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam]; | ||
84 | 86 | ||
85 | fn resolve_doc_path( | 87 | fn resolve_doc_path( |
86 | db: &dyn HirDatabase, | 88 | db: &dyn HirDatabase, |
@@ -99,6 +101,12 @@ fn resolve_doc_path( | |||
99 | AttrDefId::TraitId(it) => it.resolver(db.upcast()), | 101 | AttrDefId::TraitId(it) => it.resolver(db.upcast()), |
100 | AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), | 102 | AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), |
101 | AttrDefId::ImplId(it) => it.resolver(db.upcast()), | 103 | AttrDefId::ImplId(it) => it.resolver(db.upcast()), |
104 | AttrDefId::GenericParamId(it) => match it { | ||
105 | GenericParamId::TypeParamId(it) => it.parent, | ||
106 | GenericParamId::LifetimeParamId(it) => it.parent, | ||
107 | GenericParamId::ConstParamId(it) => it.parent, | ||
108 | } | ||
109 | .resolver(db.upcast()), | ||
102 | AttrDefId::MacroDefId(_) => return None, | 110 | AttrDefId::MacroDefId(_) => return None, |
103 | }; | 111 | }; |
104 | let path = ast::Path::parse(link).ok()?; | 112 | let path = ast::Path::parse(link).ok()?; |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index b7ded3478..6cbf5cecf 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -5,9 +5,7 @@ use arrayvec::ArrayVec; | |||
5 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 5 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | adt::ReprKind, | 8 | adt::{ReprKind, StructKind, VariantData}, |
9 | adt::StructKind, | ||
10 | adt::VariantData, | ||
11 | builtin_type::BuiltinType, | 9 | builtin_type::BuiltinType, |
12 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 10 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
13 | import_map, | 11 | import_map, |
@@ -18,10 +16,10 @@ use hir_def::{ | |||
18 | resolver::{HasResolver, Resolver}, | 16 | resolver::{HasResolver, Resolver}, |
19 | src::HasSource as _, | 17 | src::HasSource as _, |
20 | type_ref::{Mutability, TypeRef}, | 18 | type_ref::{Mutability, TypeRef}, |
21 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, DefWithBodyId, EnumId, | 19 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, |
22 | FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, | 20 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, |
23 | LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 21 | LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, |
24 | UnionId, | 22 | TypeAliasId, TypeParamId, UnionId, |
25 | }; | 23 | }; |
26 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; | 24 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; |
27 | use hir_expand::{ | 25 | use hir_expand::{ |
@@ -31,7 +29,7 @@ use hir_expand::{ | |||
31 | }; | 29 | }; |
32 | use hir_ty::{ | 30 | use hir_ty::{ |
33 | autoderef, | 31 | autoderef, |
34 | display::{HirDisplayError, HirFormatter}, | 32 | display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter}, |
35 | method_resolution, | 33 | method_resolution, |
36 | traits::{FnTrait, Solution, SolutionVariables}, | 34 | traits::{FnTrait, Solution, SolutionVariables}, |
37 | ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, | 35 | ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, |
@@ -39,7 +37,7 @@ use hir_ty::{ | |||
39 | TyDefId, TyKind, TypeCtor, | 37 | TyDefId, TyKind, TypeCtor, |
40 | }; | 38 | }; |
41 | use rustc_hash::FxHashSet; | 39 | use rustc_hash::FxHashSet; |
42 | use stdx::impl_from; | 40 | use stdx::{format_to, impl_from}; |
43 | use syntax::{ | 41 | use syntax::{ |
44 | ast::{self, AttrsOwner, NameOwner}, | 42 | ast::{self, AttrsOwner, NameOwner}, |
45 | AstNode, SmolStr, | 43 | AstNode, SmolStr, |
@@ -745,6 +743,18 @@ impl Function { | |||
745 | db.function_data(self.id).name.clone() | 743 | db.function_data(self.id).name.clone() |
746 | } | 744 | } |
747 | 745 | ||
746 | /// Get this function's return type | ||
747 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { | ||
748 | let resolver = self.id.resolver(db.upcast()); | ||
749 | let ret_type = &db.function_data(self.id).ret_type; | ||
750 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
751 | let environment = TraitEnvironment::lower(db, &resolver); | ||
752 | Type { | ||
753 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate, | ||
754 | ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment }, | ||
755 | } | ||
756 | } | ||
757 | |||
748 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { | 758 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { |
749 | if !db.function_data(self.id).has_self_param { | 759 | if !db.function_data(self.id).has_self_param { |
750 | return None; | 760 | return None; |
@@ -797,6 +807,19 @@ impl Function { | |||
797 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { | 807 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { |
798 | db.function_data(self.id).has_body | 808 | db.function_data(self.id).has_body |
799 | } | 809 | } |
810 | |||
811 | /// A textual representation of the HIR of this function for debugging purposes. | ||
812 | pub fn debug_hir(self, db: &dyn HirDatabase) -> String { | ||
813 | let body = db.body(self.id.into()); | ||
814 | |||
815 | let mut result = String::new(); | ||
816 | format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); | ||
817 | for (id, expr) in body.exprs.iter() { | ||
818 | format_to!(result, "{:?}: {:?}\n", id, expr); | ||
819 | } | ||
820 | |||
821 | result | ||
822 | } | ||
800 | } | 823 | } |
801 | 824 | ||
802 | // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. | 825 | // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. |
@@ -983,13 +1006,7 @@ impl MacroDef { | |||
983 | 1006 | ||
984 | /// XXX: this parses the file | 1007 | /// XXX: this parses the file |
985 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 1008 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
986 | // FIXME: Currently proc-macro do not have ast-node, | 1009 | self.source(db)?.value.name().map(|it| it.as_name()) |
987 | // such that it does not have source | ||
988 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
989 | if self.is_proc_macro() { | ||
990 | return None; | ||
991 | } | ||
992 | self.source(db).value.name().map(|it| it.as_name()) | ||
993 | } | 1010 | } |
994 | 1011 | ||
995 | /// Indicate it is a proc-macro | 1012 | /// Indicate it is a proc-macro |
@@ -1125,7 +1142,12 @@ impl GenericDef { | |||
1125 | id: LifetimeParamId { parent: self.into(), local_id }, | 1142 | id: LifetimeParamId { parent: self.into(), local_id }, |
1126 | }) | 1143 | }) |
1127 | .map(GenericParam::LifetimeParam); | 1144 | .map(GenericParam::LifetimeParam); |
1128 | ty_params.chain(lt_params).collect() | 1145 | let const_params = generics |
1146 | .consts | ||
1147 | .iter() | ||
1148 | .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } }) | ||
1149 | .map(GenericParam::ConstParam); | ||
1150 | ty_params.chain(lt_params).chain(const_params).collect() | ||
1129 | } | 1151 | } |
1130 | 1152 | ||
1131 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { | 1153 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { |
@@ -1237,8 +1259,27 @@ impl Label { | |||
1237 | pub enum GenericParam { | 1259 | pub enum GenericParam { |
1238 | TypeParam(TypeParam), | 1260 | TypeParam(TypeParam), |
1239 | LifetimeParam(LifetimeParam), | 1261 | LifetimeParam(LifetimeParam), |
1262 | ConstParam(ConstParam), | ||
1263 | } | ||
1264 | impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); | ||
1265 | |||
1266 | impl GenericParam { | ||
1267 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1268 | match self { | ||
1269 | GenericParam::TypeParam(it) => it.module(db), | ||
1270 | GenericParam::LifetimeParam(it) => it.module(db), | ||
1271 | GenericParam::ConstParam(it) => it.module(db), | ||
1272 | } | ||
1273 | } | ||
1274 | |||
1275 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1276 | match self { | ||
1277 | GenericParam::TypeParam(it) => it.name(db), | ||
1278 | GenericParam::LifetimeParam(it) => it.name(db), | ||
1279 | GenericParam::ConstParam(it) => it.name(db), | ||
1280 | } | ||
1281 | } | ||
1240 | } | 1282 | } |
1241 | impl_from!(TypeParam, LifetimeParam for GenericParam); | ||
1242 | 1283 | ||
1243 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1284 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1244 | pub struct TypeParam { | 1285 | pub struct TypeParam { |
@@ -1265,6 +1306,18 @@ impl TypeParam { | |||
1265 | } | 1306 | } |
1266 | } | 1307 | } |
1267 | 1308 | ||
1309 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | ||
1310 | db.generic_predicates_for_param(self.id) | ||
1311 | .into_iter() | ||
1312 | .filter_map(|pred| match &pred.value { | ||
1313 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1314 | Some(Trait::from(trait_ref.trait_)) | ||
1315 | } | ||
1316 | _ => None, | ||
1317 | }) | ||
1318 | .collect() | ||
1319 | } | ||
1320 | |||
1268 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { | 1321 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { |
1269 | let params = db.generic_defaults(self.id.parent); | 1322 | let params = db.generic_defaults(self.id.parent); |
1270 | let local_idx = hir_ty::param_idx(db, self.id)?; | 1323 | let local_idx = hir_ty::param_idx(db, self.id)?; |
@@ -1280,6 +1333,20 @@ impl TypeParam { | |||
1280 | } | 1333 | } |
1281 | } | 1334 | } |
1282 | 1335 | ||
1336 | impl HirDisplay for TypeParam { | ||
1337 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1338 | write!(f, "{}", self.name(f.db))?; | ||
1339 | let bounds = f.db.generic_predicates_for_param(self.id); | ||
1340 | let substs = Substs::type_params(f.db, self.id.parent); | ||
1341 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | ||
1342 | if !(predicates.is_empty() || f.omit_verbose_types()) { | ||
1343 | write!(f, ": ")?; | ||
1344 | write_bounds_like_dyn_trait(&predicates, f)?; | ||
1345 | } | ||
1346 | Ok(()) | ||
1347 | } | ||
1348 | } | ||
1349 | |||
1283 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1350 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1284 | pub struct LifetimeParam { | 1351 | pub struct LifetimeParam { |
1285 | pub(crate) id: LifetimeParamId, | 1352 | pub(crate) id: LifetimeParamId, |
@@ -1300,6 +1367,32 @@ impl LifetimeParam { | |||
1300 | } | 1367 | } |
1301 | } | 1368 | } |
1302 | 1369 | ||
1370 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1371 | pub struct ConstParam { | ||
1372 | pub(crate) id: ConstParamId, | ||
1373 | } | ||
1374 | |||
1375 | impl ConstParam { | ||
1376 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1377 | let params = db.generic_params(self.id.parent); | ||
1378 | params.consts[self.id.local_id].name.clone() | ||
1379 | } | ||
1380 | |||
1381 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1382 | self.id.parent.module(db.upcast()).into() | ||
1383 | } | ||
1384 | |||
1385 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1386 | self.id.parent.into() | ||
1387 | } | ||
1388 | |||
1389 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1390 | let def = self.id.parent; | ||
1391 | let krate = def.module(db.upcast()).krate; | ||
1392 | Type::new(db, krate, def, db.const_param_ty(self.id)) | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1303 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1396 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1304 | pub struct Impl { | 1397 | pub struct Impl { |
1305 | pub(crate) id: ImplId, | 1398 | pub(crate) id: ImplId, |
@@ -1352,7 +1445,7 @@ impl Impl { | |||
1352 | } | 1445 | } |
1353 | 1446 | ||
1354 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | 1447 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { |
1355 | let src = self.source(db); | 1448 | let src = self.source(db)?; |
1356 | let item = src.file_id.is_builtin_derive(db.upcast())?; | 1449 | let item = src.file_id.is_builtin_derive(db.upcast())?; |
1357 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); | 1450 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); |
1358 | 1451 | ||
@@ -1567,9 +1660,10 @@ impl Type { | |||
1567 | } | 1660 | } |
1568 | 1661 | ||
1569 | pub fn is_fn(&self) -> bool { | 1662 | pub fn is_fn(&self) -> bool { |
1570 | matches!(&self.ty.value, | 1663 | matches!( |
1571 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(..), .. }) | | 1664 | &self.ty.value, |
1572 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnPtr { .. }, .. }) | 1665 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(..), .. }) |
1666 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnPtr { .. }, .. }) | ||
1573 | ) | 1667 | ) |
1574 | } | 1668 | } |
1575 | 1669 | ||
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index d01e1b33d..d5d4cf5b6 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs | |||
@@ -10,8 +10,8 @@ pub use hir_def::db::{ | |||
10 | TypeAliasDataQuery, UnionDataQuery, | 10 | TypeAliasDataQuery, UnionDataQuery, |
11 | }; | 11 | }; |
12 | pub use hir_expand::db::{ | 12 | pub use hir_expand::db::{ |
13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, | 13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery, |
14 | MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery, | 14 | InternMacroQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery, |
15 | }; | 15 | }; |
16 | pub use hir_ty::db::*; | 16 | pub use hir_ty::db::*; |
17 | 17 | ||
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index b1c924167..447faa04f 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -4,6 +4,6 @@ pub use hir_expand::diagnostics::{ | |||
4 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, | 4 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, |
5 | }; | 5 | }; |
6 | pub use hir_ty::diagnostics::{ | 6 | pub use hir_ty::diagnostics::{ |
7 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, | 7 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, |
8 | NoSuchField, RemoveThisSemicolon, | 8 | NoSuchField, RemoveThisSemicolon, |
9 | }; | 9 | }; |
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index a0792b9a6..c8c5fecd7 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs | |||
@@ -1,18 +1,18 @@ | |||
1 | //! Utility module for converting between hir_def ids and code_model wrappers. | 1 | //! Utility module for converting between hir_def ids and code_model wrappers. |
2 | //! | 2 | //! |
3 | //! It's unclear if we need this long-term, but it's definitelly useful while we | 3 | //! It's unclear if we need this long-term, but it's definitely useful while we |
4 | //! are splitting the hir. | 4 | //! are splitting the hir. |
5 | 5 | ||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | expr::{LabelId, PatId}, | 7 | expr::{LabelId, PatId}, |
8 | item_scope::ItemInNs, | 8 | item_scope::ItemInNs, |
9 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, ModuleDefId, | 9 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, |
10 | VariantId, | 10 | ModuleDefId, VariantId, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant, | 14 | code_model::GenericParam, Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, |
15 | VariantDef, | 15 | MacroDef, ModuleDef, Variant, VariantDef, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | macro_rules! from_id { | 18 | macro_rules! from_id { |
@@ -44,6 +44,7 @@ from_id![ | |||
44 | (hir_def::ImplId, crate::Impl), | 44 | (hir_def::ImplId, crate::Impl), |
45 | (hir_def::TypeParamId, crate::TypeParam), | 45 | (hir_def::TypeParamId, crate::TypeParam), |
46 | (hir_def::LifetimeParamId, crate::LifetimeParam), | 46 | (hir_def::LifetimeParamId, crate::LifetimeParam), |
47 | (hir_def::ConstParamId, crate::ConstParam), | ||
47 | (hir_expand::MacroDefId, crate::MacroDef) | 48 | (hir_expand::MacroDefId, crate::MacroDef) |
48 | ]; | 49 | ]; |
49 | 50 | ||
@@ -67,6 +68,26 @@ impl From<Adt> for AdtId { | |||
67 | } | 68 | } |
68 | } | 69 | } |
69 | 70 | ||
71 | impl From<GenericParamId> for GenericParam { | ||
72 | fn from(id: GenericParamId) -> Self { | ||
73 | match id { | ||
74 | GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()), | ||
75 | GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()), | ||
76 | GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()), | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | impl From<GenericParam> for GenericParamId { | ||
82 | fn from(id: GenericParam) -> Self { | ||
83 | match id { | ||
84 | GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id), | ||
85 | GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id), | ||
86 | GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id), | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
70 | impl From<EnumVariantId> for Variant { | 91 | impl From<EnumVariantId> for Variant { |
71 | fn from(id: EnumVariantId) -> Self { | 92 | fn from(id: EnumVariantId) -> Self { |
72 | Variant { parent: id.parent.into(), id: id.local_id } | 93 | Variant { parent: id.parent.into(), id: id.local_id } |
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 0dc07c33e..7c57d8378 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs | |||
@@ -10,13 +10,13 @@ use hir_expand::InFile; | |||
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | db::HirDatabase, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, MacroDef, | 13 | db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam, |
14 | Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, | 14 | MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub trait HasSource { | 17 | pub trait HasSource { |
18 | type Ast; | 18 | type Ast; |
19 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>; | 19 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>; |
20 | } | 20 | } |
21 | 21 | ||
22 | /// NB: Module is !HasSource, because it has two source nodes at the same time: | 22 | /// NB: Module is !HasSource, because it has two source nodes at the same time: |
@@ -46,97 +46,104 @@ impl Module { | |||
46 | 46 | ||
47 | impl HasSource for Field { | 47 | impl HasSource for Field { |
48 | type Ast = FieldSource; | 48 | type Ast = FieldSource; |
49 | fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> { | 49 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
50 | let var = VariantId::from(self.parent); | 50 | let var = VariantId::from(self.parent); |
51 | let src = var.child_source(db.upcast()); | 51 | let src = var.child_source(db.upcast()); |
52 | src.map(|it| match it[self.id].clone() { | 52 | let field_source = src.map(|it| match it[self.id].clone() { |
53 | Either::Left(it) => FieldSource::Pos(it), | 53 | Either::Left(it) => FieldSource::Pos(it), |
54 | Either::Right(it) => FieldSource::Named(it), | 54 | Either::Right(it) => FieldSource::Named(it), |
55 | }) | 55 | }); |
56 | Some(field_source) | ||
56 | } | 57 | } |
57 | } | 58 | } |
58 | impl HasSource for Struct { | 59 | impl HasSource for Struct { |
59 | type Ast = ast::Struct; | 60 | type Ast = ast::Struct; |
60 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> { | 61 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
61 | self.id.lookup(db.upcast()).source(db.upcast()) | 62 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
62 | } | 63 | } |
63 | } | 64 | } |
64 | impl HasSource for Union { | 65 | impl HasSource for Union { |
65 | type Ast = ast::Union; | 66 | type Ast = ast::Union; |
66 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> { | 67 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
67 | self.id.lookup(db.upcast()).source(db.upcast()) | 68 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
68 | } | 69 | } |
69 | } | 70 | } |
70 | impl HasSource for Enum { | 71 | impl HasSource for Enum { |
71 | type Ast = ast::Enum; | 72 | type Ast = ast::Enum; |
72 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> { | 73 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
73 | self.id.lookup(db.upcast()).source(db.upcast()) | 74 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
74 | } | 75 | } |
75 | } | 76 | } |
76 | impl HasSource for Variant { | 77 | impl HasSource for Variant { |
77 | type Ast = ast::Variant; | 78 | type Ast = ast::Variant; |
78 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> { | 79 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> { |
79 | self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()) | 80 | Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())) |
80 | } | 81 | } |
81 | } | 82 | } |
82 | impl HasSource for Function { | 83 | impl HasSource for Function { |
83 | type Ast = ast::Fn; | 84 | type Ast = ast::Fn; |
84 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> { | 85 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
85 | self.id.lookup(db.upcast()).source(db.upcast()) | 86 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
86 | } | 87 | } |
87 | } | 88 | } |
88 | impl HasSource for Const { | 89 | impl HasSource for Const { |
89 | type Ast = ast::Const; | 90 | type Ast = ast::Const; |
90 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> { | 91 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
91 | self.id.lookup(db.upcast()).source(db.upcast()) | 92 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
92 | } | 93 | } |
93 | } | 94 | } |
94 | impl HasSource for Static { | 95 | impl HasSource for Static { |
95 | type Ast = ast::Static; | 96 | type Ast = ast::Static; |
96 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> { | 97 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
97 | self.id.lookup(db.upcast()).source(db.upcast()) | 98 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
98 | } | 99 | } |
99 | } | 100 | } |
100 | impl HasSource for Trait { | 101 | impl HasSource for Trait { |
101 | type Ast = ast::Trait; | 102 | type Ast = ast::Trait; |
102 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> { | 103 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
103 | self.id.lookup(db.upcast()).source(db.upcast()) | 104 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
104 | } | 105 | } |
105 | } | 106 | } |
106 | impl HasSource for TypeAlias { | 107 | impl HasSource for TypeAlias { |
107 | type Ast = ast::TypeAlias; | 108 | type Ast = ast::TypeAlias; |
108 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> { | 109 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
109 | self.id.lookup(db.upcast()).source(db.upcast()) | 110 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
110 | } | 111 | } |
111 | } | 112 | } |
112 | impl HasSource for MacroDef { | 113 | impl HasSource for MacroDef { |
113 | type Ast = ast::Macro; | 114 | type Ast = ast::Macro; |
114 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> { | 115 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
115 | InFile { | 116 | let ast_id = self.id.ast_id?; |
116 | file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id, | 117 | Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) }) |
117 | value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()), | ||
118 | } | ||
119 | } | 118 | } |
120 | } | 119 | } |
121 | impl HasSource for Impl { | 120 | impl HasSource for Impl { |
122 | type Ast = ast::Impl; | 121 | type Ast = ast::Impl; |
123 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> { | 122 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
124 | self.id.lookup(db.upcast()).source(db.upcast()) | 123 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
125 | } | 124 | } |
126 | } | 125 | } |
127 | 126 | ||
128 | impl HasSource for TypeParam { | 127 | impl HasSource for TypeParam { |
129 | type Ast = Either<ast::Trait, ast::TypeParam>; | 128 | type Ast = Either<ast::Trait, ast::TypeParam>; |
130 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { | 129 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
131 | let child_source = self.id.parent.child_source(db.upcast()); | 130 | let child_source = self.id.parent.child_source(db.upcast()); |
132 | child_source.map(|it| it[self.id.local_id].clone()) | 131 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
133 | } | 132 | } |
134 | } | 133 | } |
135 | 134 | ||
136 | impl HasSource for LifetimeParam { | 135 | impl HasSource for LifetimeParam { |
137 | type Ast = ast::LifetimeParam; | 136 | type Ast = ast::LifetimeParam; |
138 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { | 137 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
138 | let child_source = self.id.parent.child_source(db.upcast()); | ||
139 | Some(child_source.map(|it| it[self.id.local_id].clone())) | ||
140 | } | ||
141 | } | ||
142 | |||
143 | impl HasSource for ConstParam { | ||
144 | type Ast = ast::ConstParam; | ||
145 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { | ||
139 | let child_source = self.id.parent.child_source(db.upcast()); | 146 | let child_source = self.id.parent.child_source(db.upcast()); |
140 | child_source.map(|it| it[self.id.local_id].clone()) | 147 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
141 | } | 148 | } |
142 | } | 149 | } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7ac9fd507..769945c47 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -34,9 +34,10 @@ pub use crate::{ | |||
34 | attrs::{HasAttrs, Namespace}, | 34 | attrs::{HasAttrs, Namespace}, |
35 | code_model::{ | 35 | code_model::{ |
36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, | 36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, |
37 | Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef, | 37 | ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, |
38 | HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, | 38 | GenericDef, GenericParam, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, |
39 | Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, | 39 | Module, ModuleDef, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, |
40 | Variant, VariantDef, | ||
40 | }, | 41 | }, |
41 | has_source::HasSource, | 42 | has_source::HasSource, |
42 | semantics::{PathResolution, Semantics, SemanticsScope}, | 43 | semantics::{PathResolution, Semantics, SemanticsScope}, |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 67cd16e31..cd689c869 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -25,9 +25,9 @@ use crate::{ | |||
25 | diagnostics::Diagnostic, | 25 | diagnostics::Diagnostic, |
26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
28 | AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam, | 28 | AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label, |
29 | Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, | 29 | LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, |
30 | VariantDef, | 30 | TypeAlias, TypeParam, VariantDef, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #[derive(Debug, Clone, PartialEq, Eq)] | 33 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -38,6 +38,7 @@ pub enum PathResolution { | |||
38 | Local(Local), | 38 | Local(Local), |
39 | /// A generic parameter | 39 | /// A generic parameter |
40 | TypeParam(TypeParam), | 40 | TypeParam(TypeParam), |
41 | ConstParam(ConstParam), | ||
41 | SelfType(Impl), | 42 | SelfType(Impl), |
42 | Macro(MacroDef), | 43 | Macro(MacroDef), |
43 | AssocItem(AssocItem), | 44 | AssocItem(AssocItem), |
@@ -59,7 +60,9 @@ impl PathResolution { | |||
59 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { | 60 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { |
60 | Some(TypeNs::TypeAliasId((*alias).into())) | 61 | Some(TypeNs::TypeAliasId((*alias).into())) |
61 | } | 62 | } |
62 | PathResolution::Local(_) | PathResolution::Macro(_) => None, | 63 | PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => { |
64 | None | ||
65 | } | ||
63 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), | 66 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), |
64 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), | 67 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), |
65 | PathResolution::AssocItem(AssocItem::Const(_)) | 68 | PathResolution::AssocItem(AssocItem::Const(_)) |
@@ -744,6 +747,7 @@ to_def_impls![ | |||
744 | (crate::Variant, ast::Variant, enum_variant_to_def), | 747 | (crate::Variant, ast::Variant, enum_variant_to_def), |
745 | (crate::TypeParam, ast::TypeParam, type_param_to_def), | 748 | (crate::TypeParam, ast::TypeParam, type_param_to_def), |
746 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), | 749 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), |
750 | (crate::ConstParam, ast::ConstParam, const_param_to_def), | ||
747 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), | 751 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), |
748 | (crate::Local, ast::IdentPat, bind_pat_to_def), | 752 | (crate::Local, ast::IdentPat, bind_pat_to_def), |
749 | (crate::Label, ast::Label, label_to_def), | 753 | (crate::Label, ast::Label, label_to_def), |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 424e6e8a9..4b9ebff72 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -6,9 +6,9 @@ use hir_def::{ | |||
6 | dyn_map::DynMap, | 6 | dyn_map::DynMap, |
7 | expr::{LabelId, PatId}, | 7 | expr::{LabelId, PatId}, |
8 | keys::{self, Key}, | 8 | keys::{self, Key}, |
9 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId, | 9 | ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, |
10 | LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 10 | ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
11 | VariantId, | 11 | UnionId, VariantId, |
12 | }; | 12 | }; |
13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; | 13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
@@ -157,6 +157,18 @@ impl SourceToDefCtx<'_, '_> { | |||
157 | dyn_map[keys::LIFETIME_PARAM].get(&src).copied() | 157 | dyn_map[keys::LIFETIME_PARAM].get(&src).copied() |
158 | } | 158 | } |
159 | 159 | ||
160 | pub(super) fn const_param_to_def( | ||
161 | &mut self, | ||
162 | src: InFile<ast::ConstParam>, | ||
163 | ) -> Option<ConstParamId> { | ||
164 | let container: ChildContainer = | ||
165 | self.find_generic_param_container(src.as_ref().map(|it| it.syntax()))?.into(); | ||
166 | let db = self.db; | ||
167 | let dyn_map = | ||
168 | &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); | ||
169 | dyn_map[keys::CONST_PARAM].get(&src).copied() | ||
170 | } | ||
171 | |||
160 | // FIXME: use DynMap as well? | 172 | // FIXME: use DynMap as well? |
161 | pub(super) fn macro_rules_to_def( | 173 | pub(super) fn macro_rules_to_def( |
162 | &mut self, | 174 | &mut self, |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index bddc49c05..30a8e513d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -479,6 +479,7 @@ pub(crate) fn resolve_hir_path( | |||
479 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), | 479 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), |
480 | ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), | 480 | ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), |
481 | ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), | 481 | ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), |
482 | ValueNs::GenericParam(it) => PathResolution::ConstParam(it.into()), | ||
482 | }; | 483 | }; |
483 | Some(res) | 484 | Some(res) |
484 | }); | 485 | }); |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index a88b5f57e..7ef966cd2 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -17,7 +17,7 @@ either = "1.5.3" | |||
17 | anymap = "0.12.1" | 17 | anymap = "0.12.1" |
18 | drop_bomb = "0.1.4" | 18 | drop_bomb = "0.1.4" |
19 | fst = { version = "0.4", default-features = false } | 19 | fst = { version = "0.4", default-features = false } |
20 | itertools = "0.9.0" | 20 | itertools = "0.10.0" |
21 | indexmap = "1.4.0" | 21 | indexmap = "1.4.0" |
22 | smallvec = "1.4.0" | 22 | smallvec = "1.4.0" |
23 | 23 | ||
@@ -33,4 +33,4 @@ cfg = { path = "../cfg", version = "0.0.0" } | |||
33 | tt = { path = "../tt", version = "0.0.0" } | 33 | tt = { path = "../tt", version = "0.0.0" } |
34 | 34 | ||
35 | [dev-dependencies] | 35 | [dev-dependencies] |
36 | expect-test = "1.0" | 36 | expect-test = "1.1" |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 042e119b1..9e6426b31 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::{ops, sync::Arc}; | 3 | use std::{ops, sync::Arc}; |
4 | 4 | ||
5 | use arena::map::ArenaMap; | ||
5 | use base_db::CrateId; | 6 | use base_db::CrateId; |
6 | use cfg::{CfgExpr, CfgOptions}; | 7 | use cfg::{CfgExpr, CfgOptions}; |
7 | use either::Either; | 8 | use either::Either; |
@@ -21,7 +22,8 @@ use crate::{ | |||
21 | nameres::ModuleSource, | 22 | nameres::ModuleSource, |
22 | path::{ModPath, PathKind}, | 23 | path::{ModPath, PathKind}, |
23 | src::HasChildSource, | 24 | src::HasChildSource, |
24 | AdtId, AttrDefId, Lookup, | 25 | AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, |
26 | VariantId, | ||
25 | }; | 27 | }; |
26 | 28 | ||
27 | /// Holds documentation | 29 | /// Holds documentation |
@@ -210,16 +212,10 @@ impl Attrs { | |||
210 | } | 212 | } |
211 | } | 213 | } |
212 | AttrDefId::FieldId(it) => { | 214 | AttrDefId::FieldId(it) => { |
213 | let src = it.parent.child_source(db); | 215 | return db.fields_attrs(it.parent)[it.local_id].clone(); |
214 | match &src.value[it.local_id] { | ||
215 | Either::Left(_tuple) => RawAttrs::default(), | ||
216 | Either::Right(record) => RawAttrs::from_attrs_owner(db, src.with_value(record)), | ||
217 | } | ||
218 | } | 216 | } |
219 | AttrDefId::EnumVariantId(var_id) => { | 217 | AttrDefId::EnumVariantId(it) => { |
220 | let src = var_id.parent.child_source(db); | 218 | return db.variants_attrs(it.parent)[it.local_id].clone(); |
221 | let src = src.as_ref().map(|it| &it[var_id.local_id]); | ||
222 | RawAttrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) | ||
223 | } | 219 | } |
224 | AttrDefId::AdtId(it) => match it { | 220 | AttrDefId::AdtId(it) => match it { |
225 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 221 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
@@ -235,11 +231,70 @@ impl Attrs { | |||
235 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 231 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
236 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 232 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
237 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 233 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
234 | AttrDefId::GenericParamId(it) => match it { | ||
235 | GenericParamId::TypeParamId(it) => { | ||
236 | let src = it.parent.child_source(db); | ||
237 | RawAttrs::from_attrs_owner( | ||
238 | db, | ||
239 | src.with_value( | ||
240 | src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _), | ||
241 | ), | ||
242 | ) | ||
243 | } | ||
244 | GenericParamId::LifetimeParamId(it) => { | ||
245 | let src = it.parent.child_source(db); | ||
246 | RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) | ||
247 | } | ||
248 | GenericParamId::ConstParamId(it) => { | ||
249 | let src = it.parent.child_source(db); | ||
250 | RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) | ||
251 | } | ||
252 | }, | ||
238 | }; | 253 | }; |
239 | 254 | ||
240 | raw_attrs.filter(db, def.krate(db)) | 255 | raw_attrs.filter(db, def.krate(db)) |
241 | } | 256 | } |
242 | 257 | ||
258 | pub(crate) fn variants_attrs_query( | ||
259 | db: &dyn DefDatabase, | ||
260 | e: EnumId, | ||
261 | ) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> { | ||
262 | let krate = e.lookup(db).container.module(db).krate; | ||
263 | let src = e.child_source(db); | ||
264 | let mut res = ArenaMap::default(); | ||
265 | |||
266 | for (id, var) in src.value.iter() { | ||
267 | let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn AttrsOwner)) | ||
268 | .filter(db, krate); | ||
269 | |||
270 | res.insert(id, attrs) | ||
271 | } | ||
272 | |||
273 | Arc::new(res) | ||
274 | } | ||
275 | |||
276 | pub(crate) fn fields_attrs_query( | ||
277 | db: &dyn DefDatabase, | ||
278 | v: VariantId, | ||
279 | ) -> Arc<ArenaMap<LocalFieldId, Attrs>> { | ||
280 | let krate = v.module(db).krate; | ||
281 | let src = v.child_source(db); | ||
282 | let mut res = ArenaMap::default(); | ||
283 | |||
284 | for (id, fld) in src.value.iter() { | ||
285 | let attrs = match fld { | ||
286 | Either::Left(_tuple) => Attrs::default(), | ||
287 | Either::Right(record) => { | ||
288 | RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate) | ||
289 | } | ||
290 | }; | ||
291 | |||
292 | res.insert(id, attrs); | ||
293 | } | ||
294 | |||
295 | Arc::new(res) | ||
296 | } | ||
297 | |||
243 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | 298 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { |
244 | AttrQuery { attrs: self, key } | 299 | AttrQuery { attrs: self, key } |
245 | } | 300 | } |
@@ -260,14 +315,13 @@ impl Attrs { | |||
260 | } | 315 | } |
261 | 316 | ||
262 | pub fn docs(&self) -> Option<Documentation> { | 317 | pub fn docs(&self) -> Option<Documentation> { |
263 | let docs = self | 318 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { |
264 | .by_key("doc") | 319 | AttrInput::Literal(s) => Some(s), |
265 | .attrs() | 320 | AttrInput::TokenTree(_) => None, |
266 | .flat_map(|attr| match attr.input.as_ref()? { | 321 | }); |
267 | AttrInput::Literal(s) => Some(s), | 322 | // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the |
268 | AttrInput::TokenTree(_) => None, | 323 | // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524). |
269 | }) | 324 | let docs = Itertools::intersperse(docs, &SmolStr::new_inline("\n")) |
270 | .intersperse(&SmolStr::new_inline("\n")) | ||
271 | .map(|it| it.as_str()) | 325 | .map(|it| it.as_str()) |
272 | .collect::<String>(); | 326 | .collect::<String>(); |
273 | if docs.is_empty() { | 327 | if docs.is_empty() { |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 17c72779b..3dc33f248 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -581,7 +581,7 @@ impl ExprCollector<'_> { | |||
581 | match res.value { | 581 | match res.value { |
582 | Some((mark, expansion)) => { | 582 | Some((mark, expansion)) => { |
583 | // FIXME: Statements are too complicated to recover from error for now. | 583 | // FIXME: Statements are too complicated to recover from error for now. |
584 | // It is because we don't have any hygenine for local variable expansion right now. | 584 | // It is because we don't have any hygiene for local variable expansion right now. |
585 | if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() { | 585 | if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() { |
586 | self.expander.exit(self.db, mark); | 586 | self.expander.exit(self.db, mark); |
587 | collector(self, None); | 587 | collector(self, None); |
@@ -695,7 +695,7 @@ impl ExprCollector<'_> { | |||
695 | self.collect_stmts_items(block.statements()); | 695 | self.collect_stmts_items(block.statements()); |
696 | let statements = | 696 | let statements = |
697 | block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); | 697 | block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); |
698 | let tail = block.expr().map(|e| self.collect_expr(e)); | 698 | let tail = block.tail_expr().map(|e| self.collect_expr(e)); |
699 | self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) | 699 | self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) |
700 | } | 700 | } |
701 | 701 | ||
@@ -959,7 +959,7 @@ impl ExprCollector<'_> { | |||
959 | 959 | ||
960 | fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) { | 960 | fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) { |
961 | // Find the location of the `..`, if there is one. Note that we do not | 961 | // Find the location of the `..`, if there is one. Note that we do not |
962 | // consider the possiblity of there being multiple `..` here. | 962 | // consider the possibility of there being multiple `..` here. |
963 | let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_))); | 963 | let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_))); |
964 | // We want to skip the `..` pattern here, since we account for it above. | 964 | // We want to skip the `..` pattern here, since we account for it above. |
965 | let args = args | 965 | let args = args |
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs index 9142bc05b..065785da7 100644 --- a/crates/hir_def/src/body/scope.rs +++ b/crates/hir_def/src/body/scope.rs | |||
@@ -194,7 +194,7 @@ mod tests { | |||
194 | let mut buf = String::new(); | 194 | let mut buf = String::new(); |
195 | let off: usize = offset.into(); | 195 | let off: usize = offset.into(); |
196 | buf.push_str(&code[..off]); | 196 | buf.push_str(&code[..off]); |
197 | buf.push_str("<|>marker"); | 197 | buf.push_str("$0marker"); |
198 | buf.push_str(&code[off..]); | 198 | buf.push_str(&code[off..]); |
199 | buf | 199 | buf |
200 | }; | 200 | }; |
@@ -231,7 +231,7 @@ mod tests { | |||
231 | r" | 231 | r" |
232 | fn quux(foo: i32) { | 232 | fn quux(foo: i32) { |
233 | let f = |bar, baz: i32| { | 233 | let f = |bar, baz: i32| { |
234 | <|> | 234 | $0 |
235 | }; | 235 | }; |
236 | }", | 236 | }", |
237 | &["bar", "baz", "foo"], | 237 | &["bar", "baz", "foo"], |
@@ -243,7 +243,7 @@ mod tests { | |||
243 | do_check( | 243 | do_check( |
244 | r" | 244 | r" |
245 | fn quux() { | 245 | fn quux() { |
246 | f(|x| <|> ); | 246 | f(|x| $0 ); |
247 | }", | 247 | }", |
248 | &["x"], | 248 | &["x"], |
249 | ); | 249 | ); |
@@ -254,7 +254,7 @@ mod tests { | |||
254 | do_check( | 254 | do_check( |
255 | r" | 255 | r" |
256 | fn quux() { | 256 | fn quux() { |
257 | z.f(|x| <|> ); | 257 | z.f(|x| $0 ); |
258 | }", | 258 | }", |
259 | &["x"], | 259 | &["x"], |
260 | ); | 260 | ); |
@@ -267,7 +267,7 @@ mod tests { | |||
267 | fn quux() { | 267 | fn quux() { |
268 | loop { | 268 | loop { |
269 | let x = (); | 269 | let x = (); |
270 | <|> | 270 | $0 |
271 | }; | 271 | }; |
272 | }", | 272 | }", |
273 | &["x"], | 273 | &["x"], |
@@ -281,7 +281,7 @@ mod tests { | |||
281 | fn quux() { | 281 | fn quux() { |
282 | match () { | 282 | match () { |
283 | Some(x) => { | 283 | Some(x) => { |
284 | <|> | 284 | $0 |
285 | } | 285 | } |
286 | }; | 286 | }; |
287 | }", | 287 | }", |
@@ -294,7 +294,7 @@ mod tests { | |||
294 | do_check( | 294 | do_check( |
295 | r" | 295 | r" |
296 | fn foo(x: String) { | 296 | fn foo(x: String) { |
297 | let x : &str = &x<|>; | 297 | let x : &str = &x$0; |
298 | }", | 298 | }", |
299 | &["x"], | 299 | &["x"], |
300 | ); | 300 | ); |
@@ -307,7 +307,7 @@ mod tests { | |||
307 | fn foo() { | 307 | fn foo() { |
308 | match Some(()) { | 308 | match Some(()) { |
309 | opt @ Some(unit) => { | 309 | opt @ Some(unit) => { |
310 | <|> | 310 | $0 |
311 | } | 311 | } |
312 | _ => {} | 312 | _ => {} |
313 | } | 313 | } |
@@ -330,7 +330,7 @@ fn foo() { | |||
330 | 330 | ||
331 | fn foo() { | 331 | fn foo() { |
332 | mac!(); | 332 | mac!(); |
333 | <|> | 333 | $0 |
334 | } | 334 | } |
335 | ", | 335 | ", |
336 | &[], | 336 | &[], |
@@ -343,7 +343,7 @@ fn foo() { | |||
343 | r" | 343 | r" |
344 | fn foo() { | 344 | fn foo() { |
345 | trait {} | 345 | trait {} |
346 | <|> | 346 | $0 |
347 | } | 347 | } |
348 | ", | 348 | ", |
349 | &[], | 349 | &[], |
@@ -391,7 +391,7 @@ fn foo(x: i32, y: u32) { | |||
391 | let z = x * 2; | 391 | let z = x * 2; |
392 | } | 392 | } |
393 | { | 393 | { |
394 | let t = x<|> * 3; | 394 | let t = x$0 * 3; |
395 | } | 395 | } |
396 | } | 396 | } |
397 | "#, | 397 | "#, |
@@ -404,7 +404,7 @@ fn foo(x: i32, y: u32) { | |||
404 | do_check_local_name( | 404 | do_check_local_name( |
405 | r#" | 405 | r#" |
406 | fn foo(x: String) { | 406 | fn foo(x: String) { |
407 | let x : &str = &x<|>; | 407 | let x : &str = &x$0; |
408 | } | 408 | } |
409 | "#, | 409 | "#, |
410 | 7, | 410 | 7, |
@@ -417,7 +417,7 @@ fn foo(x: String) { | |||
417 | r" | 417 | r" |
418 | fn foo(x: String) { | 418 | fn foo(x: String) { |
419 | let x : &str = &x; | 419 | let x : &str = &x; |
420 | x<|> | 420 | x$0 |
421 | } | 421 | } |
422 | ", | 422 | ", |
423 | 28, | 423 | 28, |
@@ -430,7 +430,7 @@ fn foo(x: String) { | |||
430 | r" | 430 | r" |
431 | fn foo() { | 431 | fn foo() { |
432 | if let Some(&from) = bar() { | 432 | if let Some(&from) = bar() { |
433 | from<|>; | 433 | from$0; |
434 | } | 434 | } |
435 | } | 435 | } |
436 | ", | 436 | ", |
@@ -446,7 +446,7 @@ fn foo() { | |||
446 | fn test() { | 446 | fn test() { |
447 | let foo: Option<f32> = None; | 447 | let foo: Option<f32> = None; |
448 | while let Option::Some(spam) = foo { | 448 | while let Option::Some(spam) = foo { |
449 | spam<|> | 449 | spam$0 |
450 | } | 450 | } |
451 | } | 451 | } |
452 | "#, | 452 | "#, |
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index d1a459066..d3bf5b34c 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! Defines database & queries for name resolution. | 1 | //! Defines database & queries for name resolution. |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use arena::map::ArenaMap; | ||
4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; | 5 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; |
5 | use hir_expand::{db::AstDatabase, HirFileId}; | 6 | use hir_expand::{db::AstDatabase, HirFileId}; |
6 | use syntax::SmolStr; | 7 | use syntax::SmolStr; |
@@ -16,8 +17,8 @@ use crate::{ | |||
16 | lang_item::{LangItemTarget, LangItems}, | 17 | lang_item::{LangItemTarget, LangItems}, |
17 | nameres::CrateDefMap, | 18 | nameres::CrateDefMap, |
18 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 19 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
19 | GenericDefId, ImplId, ImplLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, | 20 | GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId, |
20 | TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | 21 | StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, |
21 | }; | 22 | }; |
22 | 23 | ||
23 | #[salsa::query_group(InternDatabaseStorage)] | 24 | #[salsa::query_group(InternDatabaseStorage)] |
@@ -92,6 +93,12 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
92 | #[salsa::invoke(GenericParams::generic_params_query)] | 93 | #[salsa::invoke(GenericParams::generic_params_query)] |
93 | fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; | 94 | fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; |
94 | 95 | ||
96 | #[salsa::invoke(Attrs::variants_attrs_query)] | ||
97 | fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>; | ||
98 | |||
99 | #[salsa::invoke(Attrs::fields_attrs_query)] | ||
100 | fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; | ||
101 | |||
95 | #[salsa::invoke(Attrs::attrs_query)] | 102 | #[salsa::invoke(Attrs::attrs_query)] |
96 | fn attrs(&self, def: AttrDefId) -> Attrs; | 103 | fn attrs(&self, def: AttrDefId) -> Attrs; |
97 | 104 | ||
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index c71266dc0..ab3f059ce 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -133,6 +133,10 @@ impl Diagnostic for InactiveCode { | |||
133 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | 133 | // This diagnostic is shown when a procedural macro can not be found. This usually means that |
134 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | 134 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), |
135 | // but can also indicate project setup problems. | 135 | // but can also indicate project setup problems. |
136 | // | ||
137 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | ||
138 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | ||
139 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | ||
136 | #[derive(Debug, Clone, Eq, PartialEq)] | 140 | #[derive(Debug, Clone, Eq, PartialEq)] |
137 | pub struct UnresolvedProcMacro { | 141 | pub struct UnresolvedProcMacro { |
138 | pub file: HirFileId, | 142 | pub file: HirFileId, |
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index 6a481769d..76f5721e5 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! This module describes hir-level representation of expressions. | 1 | //! This module describes hir-level representation of expressions. |
2 | //! | 2 | //! |
3 | //! This representaion is: | 3 | //! This representation is: |
4 | //! | 4 | //! |
5 | //! 1. Identity-based. Each expression has an `id`, so we can distinguish | 5 | //! 1. Identity-based. Each expression has an `id`, so we can distinguish |
6 | //! between different `1` in `1 + 1`. | 6 | //! between different `1` in `1 + 1`. |
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index 02613c4c4..4a212d291 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -410,7 +410,7 @@ mod tests { | |||
410 | let code = r#" | 410 | let code = r#" |
411 | //- /main.rs | 411 | //- /main.rs |
412 | struct S; | 412 | struct S; |
413 | <|> | 413 | $0 |
414 | "#; | 414 | "#; |
415 | check_found_path(code, "S", "S", "crate::S", "self::S"); | 415 | check_found_path(code, "S", "S", "crate::S", "self::S"); |
416 | } | 416 | } |
@@ -420,7 +420,7 @@ mod tests { | |||
420 | let code = r#" | 420 | let code = r#" |
421 | //- /main.rs | 421 | //- /main.rs |
422 | enum E { A } | 422 | enum E { A } |
423 | <|> | 423 | $0 |
424 | "#; | 424 | "#; |
425 | check_found_path(code, "E::A", "E::A", "E::A", "E::A"); | 425 | check_found_path(code, "E::A", "E::A", "E::A", "E::A"); |
426 | } | 426 | } |
@@ -432,7 +432,7 @@ mod tests { | |||
432 | mod foo { | 432 | mod foo { |
433 | pub struct S; | 433 | pub struct S; |
434 | } | 434 | } |
435 | <|> | 435 | $0 |
436 | "#; | 436 | "#; |
437 | check_found_path(code, "foo::S", "foo::S", "crate::foo::S", "self::foo::S"); | 437 | check_found_path(code, "foo::S", "foo::S", "crate::foo::S", "self::foo::S"); |
438 | } | 438 | } |
@@ -446,7 +446,7 @@ mod tests { | |||
446 | mod bar; | 446 | mod bar; |
447 | struct S; | 447 | struct S; |
448 | //- /foo/bar.rs | 448 | //- /foo/bar.rs |
449 | <|> | 449 | $0 |
450 | "#; | 450 | "#; |
451 | check_found_path(code, "super::S", "super::S", "crate::foo::S", "super::S"); | 451 | check_found_path(code, "super::S", "super::S", "crate::foo::S", "super::S"); |
452 | } | 452 | } |
@@ -457,7 +457,7 @@ mod tests { | |||
457 | //- /main.rs | 457 | //- /main.rs |
458 | mod foo; | 458 | mod foo; |
459 | //- /foo.rs | 459 | //- /foo.rs |
460 | <|> | 460 | $0 |
461 | "#; | 461 | "#; |
462 | check_found_path(code, "self", "self", "crate::foo", "self"); | 462 | check_found_path(code, "self", "self", "crate::foo", "self"); |
463 | } | 463 | } |
@@ -468,7 +468,7 @@ mod tests { | |||
468 | //- /main.rs | 468 | //- /main.rs |
469 | mod foo; | 469 | mod foo; |
470 | //- /foo.rs | 470 | //- /foo.rs |
471 | <|> | 471 | $0 |
472 | "#; | 472 | "#; |
473 | check_found_path(code, "crate", "crate", "crate", "crate"); | 473 | check_found_path(code, "crate", "crate", "crate", "crate"); |
474 | } | 474 | } |
@@ -480,7 +480,7 @@ mod tests { | |||
480 | mod foo; | 480 | mod foo; |
481 | struct S; | 481 | struct S; |
482 | //- /foo.rs | 482 | //- /foo.rs |
483 | <|> | 483 | $0 |
484 | "#; | 484 | "#; |
485 | check_found_path(code, "crate::S", "crate::S", "crate::S", "crate::S"); | 485 | check_found_path(code, "crate::S", "crate::S", "crate::S", "crate::S"); |
486 | } | 486 | } |
@@ -489,7 +489,7 @@ mod tests { | |||
489 | fn different_crate() { | 489 | fn different_crate() { |
490 | let code = r#" | 490 | let code = r#" |
491 | //- /main.rs crate:main deps:std | 491 | //- /main.rs crate:main deps:std |
492 | <|> | 492 | $0 |
493 | //- /std.rs crate:std | 493 | //- /std.rs crate:std |
494 | pub struct S; | 494 | pub struct S; |
495 | "#; | 495 | "#; |
@@ -501,7 +501,7 @@ mod tests { | |||
501 | let code = r#" | 501 | let code = r#" |
502 | //- /main.rs crate:main deps:std | 502 | //- /main.rs crate:main deps:std |
503 | extern crate std as std_renamed; | 503 | extern crate std as std_renamed; |
504 | <|> | 504 | $0 |
505 | //- /std.rs crate:std | 505 | //- /std.rs crate:std |
506 | pub struct S; | 506 | pub struct S; |
507 | "#; | 507 | "#; |
@@ -523,7 +523,7 @@ mod tests { | |||
523 | //- /main.rs crate:main deps:syntax | 523 | //- /main.rs crate:main deps:syntax |
524 | 524 | ||
525 | use syntax::ast; | 525 | use syntax::ast; |
526 | <|> | 526 | $0 |
527 | 527 | ||
528 | //- /lib.rs crate:syntax | 528 | //- /lib.rs crate:syntax |
529 | pub mod ast { | 529 | pub mod ast { |
@@ -543,7 +543,7 @@ mod tests { | |||
543 | let code = r#" | 543 | let code = r#" |
544 | //- /main.rs crate:main deps:syntax | 544 | //- /main.rs crate:main deps:syntax |
545 | 545 | ||
546 | <|> | 546 | $0 |
547 | 547 | ||
548 | //- /lib.rs crate:syntax | 548 | //- /lib.rs crate:syntax |
549 | pub mod ast { | 549 | pub mod ast { |
@@ -569,7 +569,7 @@ mod tests { | |||
569 | mod foo { pub(super) struct S; } | 569 | mod foo { pub(super) struct S; } |
570 | pub(crate) use foo::*; | 570 | pub(crate) use foo::*; |
571 | } | 571 | } |
572 | <|> | 572 | $0 |
573 | "#; | 573 | "#; |
574 | check_found_path(code, "bar::S", "bar::S", "crate::bar::S", "self::bar::S"); | 574 | check_found_path(code, "bar::S", "bar::S", "crate::bar::S", "self::bar::S"); |
575 | } | 575 | } |
@@ -582,7 +582,7 @@ mod tests { | |||
582 | mod foo { pub(super) struct S; } | 582 | mod foo { pub(super) struct S; } |
583 | pub(crate) use foo::S as U; | 583 | pub(crate) use foo::S as U; |
584 | } | 584 | } |
585 | <|> | 585 | $0 |
586 | "#; | 586 | "#; |
587 | check_found_path(code, "bar::U", "bar::U", "crate::bar::U", "self::bar::U"); | 587 | check_found_path(code, "bar::U", "bar::U", "crate::bar::U", "self::bar::U"); |
588 | } | 588 | } |
@@ -591,7 +591,7 @@ mod tests { | |||
591 | fn different_crate_reexport() { | 591 | fn different_crate_reexport() { |
592 | let code = r#" | 592 | let code = r#" |
593 | //- /main.rs crate:main deps:std | 593 | //- /main.rs crate:main deps:std |
594 | <|> | 594 | $0 |
595 | //- /std.rs crate:std deps:core | 595 | //- /std.rs crate:std deps:core |
596 | pub use core::S; | 596 | pub use core::S; |
597 | //- /core.rs crate:core | 597 | //- /core.rs crate:core |
@@ -604,7 +604,7 @@ mod tests { | |||
604 | fn prelude() { | 604 | fn prelude() { |
605 | let code = r#" | 605 | let code = r#" |
606 | //- /main.rs crate:main deps:std | 606 | //- /main.rs crate:main deps:std |
607 | <|> | 607 | $0 |
608 | //- /std.rs crate:std | 608 | //- /std.rs crate:std |
609 | pub mod prelude { pub struct S; } | 609 | pub mod prelude { pub struct S; } |
610 | #[prelude_import] | 610 | #[prelude_import] |
@@ -617,7 +617,7 @@ mod tests { | |||
617 | fn enum_variant_from_prelude() { | 617 | fn enum_variant_from_prelude() { |
618 | let code = r#" | 618 | let code = r#" |
619 | //- /main.rs crate:main deps:std | 619 | //- /main.rs crate:main deps:std |
620 | <|> | 620 | $0 |
621 | //- /std.rs crate:std | 621 | //- /std.rs crate:std |
622 | pub mod prelude { | 622 | pub mod prelude { |
623 | pub enum Option<T> { Some(T), None } | 623 | pub enum Option<T> { Some(T), None } |
@@ -637,7 +637,7 @@ mod tests { | |||
637 | pub mod foo; | 637 | pub mod foo; |
638 | pub mod baz; | 638 | pub mod baz; |
639 | struct S; | 639 | struct S; |
640 | <|> | 640 | $0 |
641 | //- /foo.rs | 641 | //- /foo.rs |
642 | pub mod bar { pub struct S; } | 642 | pub mod bar { pub struct S; } |
643 | //- /baz.rs | 643 | //- /baz.rs |
@@ -654,7 +654,7 @@ mod tests { | |||
654 | pub mod bar { pub struct S; } | 654 | pub mod bar { pub struct S; } |
655 | use bar::S; | 655 | use bar::S; |
656 | //- /foo.rs | 656 | //- /foo.rs |
657 | <|> | 657 | $0 |
658 | "#; | 658 | "#; |
659 | // crate::S would be shorter, but using private imports seems wrong | 659 | // crate::S would be shorter, but using private imports seems wrong |
660 | check_found_path(code, "crate::bar::S", "crate::bar::S", "crate::bar::S", "crate::bar::S"); | 660 | check_found_path(code, "crate::bar::S", "crate::bar::S", "crate::bar::S", "crate::bar::S"); |
@@ -668,7 +668,7 @@ mod tests { | |||
668 | pub mod bar; | 668 | pub mod bar; |
669 | pub mod baz; | 669 | pub mod baz; |
670 | //- /bar.rs | 670 | //- /bar.rs |
671 | <|> | 671 | $0 |
672 | //- /foo.rs | 672 | //- /foo.rs |
673 | pub use super::baz; | 673 | pub use super::baz; |
674 | pub struct S; | 674 | pub struct S; |
@@ -683,7 +683,7 @@ mod tests { | |||
683 | mark::check!(prefer_std_paths); | 683 | mark::check!(prefer_std_paths); |
684 | let code = r#" | 684 | let code = r#" |
685 | //- /main.rs crate:main deps:alloc,std | 685 | //- /main.rs crate:main deps:alloc,std |
686 | <|> | 686 | $0 |
687 | 687 | ||
688 | //- /std.rs crate:std deps:alloc | 688 | //- /std.rs crate:std deps:alloc |
689 | pub mod sync { | 689 | pub mod sync { |
@@ -711,7 +711,7 @@ mod tests { | |||
711 | //- /main.rs crate:main deps:core,std | 711 | //- /main.rs crate:main deps:core,std |
712 | #![no_std] | 712 | #![no_std] |
713 | 713 | ||
714 | <|> | 714 | $0 |
715 | 715 | ||
716 | //- /std.rs crate:std deps:core | 716 | //- /std.rs crate:std deps:core |
717 | 717 | ||
@@ -740,7 +740,7 @@ mod tests { | |||
740 | //- /main.rs crate:main deps:alloc,std | 740 | //- /main.rs crate:main deps:alloc,std |
741 | #![no_std] | 741 | #![no_std] |
742 | 742 | ||
743 | <|> | 743 | $0 |
744 | 744 | ||
745 | //- /std.rs crate:std deps:alloc | 745 | //- /std.rs crate:std deps:alloc |
746 | 746 | ||
@@ -767,7 +767,7 @@ mod tests { | |||
767 | fn prefer_shorter_paths_if_not_alloc() { | 767 | fn prefer_shorter_paths_if_not_alloc() { |
768 | let code = r#" | 768 | let code = r#" |
769 | //- /main.rs crate:main deps:megaalloc,std | 769 | //- /main.rs crate:main deps:megaalloc,std |
770 | <|> | 770 | $0 |
771 | 771 | ||
772 | //- /std.rs crate:std deps:megaalloc | 772 | //- /std.rs crate:std deps:megaalloc |
773 | pub mod sync { | 773 | pub mod sync { |
@@ -790,7 +790,7 @@ mod tests { | |||
790 | fn builtins_are_in_scope() { | 790 | fn builtins_are_in_scope() { |
791 | let code = r#" | 791 | let code = r#" |
792 | //- /main.rs | 792 | //- /main.rs |
793 | <|> | 793 | $0 |
794 | 794 | ||
795 | pub mod primitive { | 795 | pub mod primitive { |
796 | pub use u8; | 796 | pub use u8; |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index bb8fca009..9b5b886c2 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -21,11 +21,11 @@ use crate::{ | |||
21 | keys, | 21 | keys, |
22 | src::{HasChildSource, HasSource}, | 22 | src::{HasChildSource, HasSource}, |
23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, | 23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, |
24 | AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup, | 24 | AdtId, ConstParamId, GenericDefId, LifetimeParamId, LocalConstParamId, LocalLifetimeParamId, |
25 | TypeParamId, | 25 | LocalTypeParamId, Lookup, TypeParamId, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | /// Data about a generic parameter (to a function, struct, impl, ...). | 28 | /// Data about a generic type parameter (to a function, struct, impl, ...). |
29 | #[derive(Clone, PartialEq, Eq, Debug)] | 29 | #[derive(Clone, PartialEq, Eq, Debug)] |
30 | pub struct TypeParamData { | 30 | pub struct TypeParamData { |
31 | pub name: Option<Name>, | 31 | pub name: Option<Name>, |
@@ -33,12 +33,19 @@ pub struct TypeParamData { | |||
33 | pub provenance: TypeParamProvenance, | 33 | pub provenance: TypeParamProvenance, |
34 | } | 34 | } |
35 | 35 | ||
36 | /// Data about a generic parameter (to a function, struct, impl, ...). | 36 | /// Data about a generic lifetime parameter (to a function, struct, impl, ...). |
37 | #[derive(Clone, PartialEq, Eq, Debug)] | 37 | #[derive(Clone, PartialEq, Eq, Debug)] |
38 | pub struct LifetimeParamData { | 38 | pub struct LifetimeParamData { |
39 | pub name: Name, | 39 | pub name: Name, |
40 | } | 40 | } |
41 | 41 | ||
42 | /// Data about a generic const parameter (to a function, struct, impl, ...). | ||
43 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
44 | pub struct ConstParamData { | ||
45 | pub name: Name, | ||
46 | pub ty: TypeRef, | ||
47 | } | ||
48 | |||
42 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | 49 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
43 | pub enum TypeParamProvenance { | 50 | pub enum TypeParamProvenance { |
44 | TypeParamList, | 51 | TypeParamList, |
@@ -51,6 +58,7 @@ pub enum TypeParamProvenance { | |||
51 | pub struct GenericParams { | 58 | pub struct GenericParams { |
52 | pub types: Arena<TypeParamData>, | 59 | pub types: Arena<TypeParamData>, |
53 | pub lifetimes: Arena<LifetimeParamData>, | 60 | pub lifetimes: Arena<LifetimeParamData>, |
61 | pub consts: Arena<ConstParamData>, | ||
54 | pub where_predicates: Vec<WherePredicate>, | 62 | pub where_predicates: Vec<WherePredicate>, |
55 | } | 63 | } |
56 | 64 | ||
@@ -76,6 +84,7 @@ pub enum WherePredicateTypeTarget { | |||
76 | pub(crate) struct SourceMap { | 84 | pub(crate) struct SourceMap { |
77 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, | 85 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, |
78 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, | 86 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, |
87 | const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, | ||
79 | } | 88 | } |
80 | 89 | ||
81 | impl GenericParams { | 90 | impl GenericParams { |
@@ -268,6 +277,13 @@ impl GenericParams { | |||
268 | let lifetime_ref = LifetimeRef::new_name(name); | 277 | let lifetime_ref = LifetimeRef::new_name(name); |
269 | self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); | 278 | self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); |
270 | } | 279 | } |
280 | for const_param in params.const_params() { | ||
281 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); | ||
282 | let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); | ||
283 | let param = ConstParamData { name, ty }; | ||
284 | let param_id = self.consts.alloc(param); | ||
285 | sm.const_params.insert(param_id, const_param.clone()); | ||
286 | } | ||
271 | } | 287 | } |
272 | 288 | ||
273 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { | 289 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { |
@@ -353,12 +369,16 @@ impl GenericParams { | |||
353 | }); | 369 | }); |
354 | } | 370 | } |
355 | 371 | ||
356 | pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { | 372 | pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { |
357 | self.types | 373 | self.types |
358 | .iter() | 374 | .iter() |
359 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) | 375 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) |
360 | } | 376 | } |
361 | 377 | ||
378 | pub fn find_const_by_name(&self, name: &Name) -> Option<LocalConstParamId> { | ||
379 | self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None }) | ||
380 | } | ||
381 | |||
362 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { | 382 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { |
363 | self.types.iter().find_map(|(id, p)| { | 383 | self.types.iter().find_map(|(id, p)| { |
364 | if p.provenance == TypeParamProvenance::TraitSelf { | 384 | if p.provenance == TypeParamProvenance::TraitSelf { |
@@ -390,6 +410,16 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId { | |||
390 | } | 410 | } |
391 | } | 411 | } |
392 | 412 | ||
413 | impl HasChildSource<LocalConstParamId> for GenericDefId { | ||
414 | type Value = ast::ConstParam; | ||
415 | fn child_source( | ||
416 | &self, | ||
417 | db: &dyn DefDatabase, | ||
418 | ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> { | ||
419 | GenericParams::new(db, *self).1.map(|source_maps| source_maps.const_params) | ||
420 | } | ||
421 | } | ||
422 | |||
393 | impl ChildBySource for GenericDefId { | 423 | impl ChildBySource for GenericDefId { |
394 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | 424 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { |
395 | let mut res = DynMap::default(); | 425 | let mut res = DynMap::default(); |
@@ -406,6 +436,10 @@ impl ChildBySource for GenericDefId { | |||
406 | let id = LifetimeParamId { parent: *self, local_id }; | 436 | let id = LifetimeParamId { parent: *self, local_id }; |
407 | res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); | 437 | res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); |
408 | } | 438 | } |
439 | for (local_id, src) in sm.value.const_params.iter() { | ||
440 | let id = ConstParamId { parent: *self, local_id }; | ||
441 | res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id); | ||
442 | } | ||
409 | res | 443 | res |
410 | } | 444 | } |
411 | } | 445 | } |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index c4dc894df..e5368b293 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -7,9 +7,8 @@ use fst::{self, Streamer}; | |||
7 | use hir_expand::name::Name; | 7 | use hir_expand::name::Name; |
8 | use indexmap::{map::Entry, IndexMap}; | 8 | use indexmap::{map::Entry, IndexMap}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; | 10 | use rustc_hash::{FxHashSet, FxHasher}; |
11 | use smallvec::SmallVec; | 11 | use test_utils::mark; |
12 | use syntax::SmolStr; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, | 14 | db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, |
@@ -25,6 +24,8 @@ pub struct ImportInfo { | |||
25 | pub path: ImportPath, | 24 | pub path: ImportPath, |
26 | /// The module containing this item. | 25 | /// The module containing this item. |
27 | pub container: ModuleId, | 26 | pub container: ModuleId, |
27 | /// Whether the import is a trait associated item or not. | ||
28 | pub is_trait_assoc_item: bool, | ||
28 | } | 29 | } |
29 | 30 | ||
30 | #[derive(Debug, Clone, Eq, PartialEq)] | 31 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -64,10 +65,6 @@ pub struct ImportMap { | |||
64 | /// the index of the first one. | 65 | /// the index of the first one. |
65 | importables: Vec<ItemInNs>, | 66 | importables: Vec<ItemInNs>, |
66 | fst: fst::Map<Vec<u8>>, | 67 | fst: fst::Map<Vec<u8>>, |
67 | |||
68 | /// Maps names of associated items to the item's ID. Only includes items whose defining trait is | ||
69 | /// exported. | ||
70 | assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>, | ||
71 | } | 68 | } |
72 | 69 | ||
73 | impl ImportMap { | 70 | impl ImportMap { |
@@ -108,14 +105,27 @@ impl ImportMap { | |||
108 | 105 | ||
109 | for item in per_ns.iter_items() { | 106 | for item in per_ns.iter_items() { |
110 | let path = mk_path(); | 107 | let path = mk_path(); |
108 | let path_len = path.len(); | ||
109 | let import_info = | ||
110 | ImportInfo { path, container: module, is_trait_assoc_item: false }; | ||
111 | |||
112 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
113 | import_map.collect_trait_assoc_items( | ||
114 | db, | ||
115 | tr, | ||
116 | matches!(item, ItemInNs::Types(_)), | ||
117 | &import_info, | ||
118 | ); | ||
119 | } | ||
120 | |||
111 | match import_map.map.entry(item) { | 121 | match import_map.map.entry(item) { |
112 | Entry::Vacant(entry) => { | 122 | Entry::Vacant(entry) => { |
113 | entry.insert(ImportInfo { path, container: module }); | 123 | entry.insert(import_info); |
114 | } | 124 | } |
115 | Entry::Occupied(mut entry) => { | 125 | Entry::Occupied(mut entry) => { |
116 | // If the new path is shorter, prefer that one. | 126 | // If the new path is shorter, prefer that one. |
117 | if path.len() < entry.get().path.len() { | 127 | if path_len < entry.get().path.len() { |
118 | *entry.get_mut() = ImportInfo { path, container: module }; | 128 | *entry.get_mut() = import_info; |
119 | } else { | 129 | } else { |
120 | continue; | 130 | continue; |
121 | } | 131 | } |
@@ -128,11 +138,6 @@ impl ImportMap { | |||
128 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | 138 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { |
129 | worklist.push((mod_id, mk_path())); | 139 | worklist.push((mod_id, mk_path())); |
130 | } | 140 | } |
131 | |||
132 | // If we've added a path to a trait, add the trait's methods to the method map. | ||
133 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
134 | import_map.collect_trait_methods(db, tr); | ||
135 | } | ||
136 | } | 141 | } |
137 | } | 142 | } |
138 | } | 143 | } |
@@ -153,12 +158,10 @@ impl ImportMap { | |||
153 | } | 158 | } |
154 | } | 159 | } |
155 | 160 | ||
156 | let start = last_batch_start; | 161 | let key = fst_path(&importables[last_batch_start].1.path); |
157 | last_batch_start = idx + 1; | 162 | builder.insert(key, last_batch_start as u64).unwrap(); |
158 | |||
159 | let key = fst_path(&importables[start].1.path); | ||
160 | 163 | ||
161 | builder.insert(key, start as u64).unwrap(); | 164 | last_batch_start = idx + 1; |
162 | } | 165 | } |
163 | 166 | ||
164 | import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); | 167 | import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); |
@@ -176,10 +179,34 @@ impl ImportMap { | |||
176 | self.map.get(&item) | 179 | self.map.get(&item) |
177 | } | 180 | } |
178 | 181 | ||
179 | fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) { | 182 | fn collect_trait_assoc_items( |
180 | let data = db.trait_data(tr); | 183 | &mut self, |
181 | for (name, item) in data.items.iter() { | 184 | db: &dyn DefDatabase, |
182 | self.assoc_map.entry(name.to_string().into()).or_default().push(*item); | 185 | tr: TraitId, |
186 | is_type_in_ns: bool, | ||
187 | original_import_info: &ImportInfo, | ||
188 | ) { | ||
189 | for (assoc_item_name, item) in &db.trait_data(tr).items { | ||
190 | let module_def_id = match item { | ||
191 | AssocItemId::FunctionId(f) => ModuleDefId::from(*f), | ||
192 | AssocItemId::ConstId(c) => ModuleDefId::from(*c), | ||
193 | // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias` | ||
194 | // qualifier, ergo no need to store it for imports in import_map | ||
195 | AssocItemId::TypeAliasId(_) => { | ||
196 | mark::hit!(type_aliases_ignored); | ||
197 | continue; | ||
198 | } | ||
199 | }; | ||
200 | let assoc_item = if is_type_in_ns { | ||
201 | ItemInNs::Types(module_def_id) | ||
202 | } else { | ||
203 | ItemInNs::Values(module_def_id) | ||
204 | }; | ||
205 | |||
206 | let mut assoc_item_info = original_import_info.clone(); | ||
207 | assoc_item_info.path.segments.push(assoc_item_name.to_owned()); | ||
208 | assoc_item_info.is_trait_assoc_item = true; | ||
209 | self.map.insert(assoc_item, assoc_item_info); | ||
183 | } | 210 | } |
184 | } | 211 | } |
185 | } | 212 | } |
@@ -302,38 +329,38 @@ impl Query { | |||
302 | self.exclude_import_kinds.insert(import_kind); | 329 | self.exclude_import_kinds.insert(import_kind); |
303 | self | 330 | self |
304 | } | 331 | } |
305 | } | ||
306 | 332 | ||
307 | fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool { | 333 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { |
308 | let mut input = if query.name_only { | 334 | let mut input = if import.is_trait_assoc_item || self.name_only { |
309 | input_path.segments.last().unwrap().to_string() | 335 | import.path.segments.last().unwrap().to_string() |
310 | } else { | 336 | } else { |
311 | input_path.to_string() | 337 | import.path.to_string() |
312 | }; | 338 | }; |
313 | if enforce_lowercase || !query.case_sensitive { | 339 | if enforce_lowercase || !self.case_sensitive { |
314 | input.make_ascii_lowercase(); | 340 | input.make_ascii_lowercase(); |
315 | } | 341 | } |
316 | 342 | ||
317 | let query_string = | 343 | let query_string = |
318 | if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased }; | 344 | if !enforce_lowercase && self.case_sensitive { &self.query } else { &self.lowercased }; |
319 | 345 | ||
320 | match query.search_mode { | 346 | match self.search_mode { |
321 | SearchMode::Equals => &input == query_string, | 347 | SearchMode::Equals => &input == query_string, |
322 | SearchMode::Contains => input.contains(query_string), | 348 | SearchMode::Contains => input.contains(query_string), |
323 | SearchMode::Fuzzy => { | 349 | SearchMode::Fuzzy => { |
324 | let mut unchecked_query_chars = query_string.chars(); | 350 | let mut unchecked_query_chars = query_string.chars(); |
325 | let mut mismatching_query_char = unchecked_query_chars.next(); | 351 | let mut mismatching_query_char = unchecked_query_chars.next(); |
326 | 352 | ||
327 | for input_char in input.chars() { | 353 | for input_char in input.chars() { |
328 | match mismatching_query_char { | 354 | match mismatching_query_char { |
329 | None => return true, | 355 | None => return true, |
330 | Some(matching_query_char) if matching_query_char == input_char => { | 356 | Some(matching_query_char) if matching_query_char == input_char => { |
331 | mismatching_query_char = unchecked_query_chars.next(); | 357 | mismatching_query_char = unchecked_query_chars.next(); |
358 | } | ||
359 | _ => (), | ||
332 | } | 360 | } |
333 | _ => (), | ||
334 | } | 361 | } |
362 | mismatching_query_char.is_none() | ||
335 | } | 363 | } |
336 | mismatching_query_char.is_none() | ||
337 | } | 364 | } |
338 | } | 365 | } |
339 | } | 366 | } |
@@ -366,13 +393,13 @@ pub fn search_dependencies<'a>( | |||
366 | let import_map = &import_maps[indexed_value.index]; | 393 | let import_map = &import_maps[indexed_value.index]; |
367 | let importables = &import_map.importables[indexed_value.value as usize..]; | 394 | let importables = &import_map.importables[indexed_value.value as usize..]; |
368 | 395 | ||
369 | // Path shared by the importable items in this group. | 396 | let common_importable_data = &import_map.map[&importables[0]]; |
370 | let common_importables_path = &import_map.map[&importables[0]].path; | 397 | if !query.import_matches(common_importable_data, true) { |
371 | if !contains_query(&query, common_importables_path, true) { | ||
372 | continue; | 398 | continue; |
373 | } | 399 | } |
374 | 400 | ||
375 | let common_importables_path_fst = fst_path(common_importables_path); | 401 | // Path shared by the importable items in this group. |
402 | let common_importables_path_fst = fst_path(&common_importable_data.path); | ||
376 | // Add the items from this `ModPath` group. Those are all subsequent items in | 403 | // Add the items from this `ModPath` group. Those are all subsequent items in |
377 | // `importables` whose paths match `path`. | 404 | // `importables` whose paths match `path`. |
378 | let iter = importables | 405 | let iter = importables |
@@ -387,7 +414,7 @@ pub fn search_dependencies<'a>( | |||
387 | }) | 414 | }) |
388 | .filter(|item| { | 415 | .filter(|item| { |
389 | !query.case_sensitive // we've already checked the common importables path case-insensitively | 416 | !query.case_sensitive // we've already checked the common importables path case-insensitively |
390 | || contains_query(&query, &import_map.map[item].path, false) | 417 | || query.import_matches(&import_map.map[item], false) |
391 | }); | 418 | }); |
392 | res.extend(iter); | 419 | res.extend(iter); |
393 | 420 | ||
@@ -398,19 +425,6 @@ pub fn search_dependencies<'a>( | |||
398 | } | 425 | } |
399 | } | 426 | } |
400 | 427 | ||
401 | // Add all exported associated items whose names match the query (exactly). | ||
402 | for map in &import_maps { | ||
403 | if let Some(v) = map.assoc_map.get(&*query.query) { | ||
404 | res.extend(v.iter().map(|&assoc| { | ||
405 | ItemInNs::Types(match assoc { | ||
406 | AssocItemId::FunctionId(it) => it.into(), | ||
407 | AssocItemId::ConstId(it) => it.into(), | ||
408 | AssocItemId::TypeAliasId(it) => it.into(), | ||
409 | }) | ||
410 | })); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | res | 428 | res |
415 | } | 429 | } |
416 | 430 | ||
@@ -432,8 +446,9 @@ fn item_import_kind(item: ItemInNs) -> Option<ImportKind> { | |||
432 | mod tests { | 446 | mod tests { |
433 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; | 447 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; |
434 | use expect_test::{expect, Expect}; | 448 | use expect_test::{expect, Expect}; |
449 | use test_utils::mark; | ||
435 | 450 | ||
436 | use crate::{data::FunctionData, test_db::TestDB, AssocContainerId, Lookup}; | 451 | use crate::{test_db::TestDB, AssocContainerId, Lookup}; |
437 | 452 | ||
438 | use super::*; | 453 | use super::*; |
439 | 454 | ||
@@ -450,45 +465,66 @@ mod tests { | |||
450 | 465 | ||
451 | let actual = search_dependencies(db.upcast(), krate, query) | 466 | let actual = search_dependencies(db.upcast(), krate, query) |
452 | .into_iter() | 467 | .into_iter() |
453 | .filter_map(|item| { | 468 | .filter_map(|dependency| { |
454 | let mark = match item { | 469 | let dependency_krate = dependency.krate(db.upcast())?; |
455 | ItemInNs::Types(ModuleDefId::FunctionId(_)) | 470 | let dependency_imports = db.import_map(dependency_krate); |
456 | | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", | 471 | |
457 | ItemInNs::Types(_) => "t", | 472 | let (path, mark) = match assoc_item_path(&db, &dependency_imports, dependency) { |
458 | ItemInNs::Values(_) => "v", | 473 | Some(assoc_item_path) => (assoc_item_path, "a"), |
459 | ItemInNs::Macros(_) => "m", | 474 | None => ( |
475 | dependency_imports.path_of(dependency)?.to_string(), | ||
476 | match dependency { | ||
477 | ItemInNs::Types(ModuleDefId::FunctionId(_)) | ||
478 | | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", | ||
479 | ItemInNs::Types(_) => "t", | ||
480 | ItemInNs::Values(_) => "v", | ||
481 | ItemInNs::Macros(_) => "m", | ||
482 | }, | ||
483 | ), | ||
460 | }; | 484 | }; |
461 | item.krate(db.upcast()).map(|krate| { | 485 | |
462 | let map = db.import_map(krate); | 486 | Some(format!( |
463 | 487 | "{}::{} ({})\n", | |
464 | let path = match assoc_to_trait(&db, item) { | 488 | crate_graph[dependency_krate].display_name.as_ref()?, |
465 | Some(trait_) => { | 489 | path, |
466 | let mut full_path = map.path_of(trait_).unwrap().to_string(); | 490 | mark |
467 | if let ItemInNs::Types(ModuleDefId::FunctionId(function_id)) | 491 | )) |
468 | | ItemInNs::Values(ModuleDefId::FunctionId(function_id)) = item | ||
469 | { | ||
470 | full_path += &format!( | ||
471 | "::{}", | ||
472 | FunctionData::fn_data_query(&db, function_id).name | ||
473 | ); | ||
474 | } | ||
475 | full_path | ||
476 | } | ||
477 | None => map.path_of(item).unwrap().to_string(), | ||
478 | }; | ||
479 | |||
480 | format!( | ||
481 | "{}::{} ({})\n", | ||
482 | crate_graph[krate].display_name.as_ref().unwrap(), | ||
483 | path, | ||
484 | mark | ||
485 | ) | ||
486 | }) | ||
487 | }) | 492 | }) |
488 | .collect::<String>(); | 493 | .collect::<String>(); |
489 | expect.assert_eq(&actual) | 494 | expect.assert_eq(&actual) |
490 | } | 495 | } |
491 | 496 | ||
497 | fn assoc_item_path( | ||
498 | db: &dyn DefDatabase, | ||
499 | dependency_imports: &ImportMap, | ||
500 | dependency: ItemInNs, | ||
501 | ) -> Option<String> { | ||
502 | let dependency_assoc_item_id = match dependency { | ||
503 | ItemInNs::Types(ModuleDefId::FunctionId(id)) | ||
504 | | ItemInNs::Values(ModuleDefId::FunctionId(id)) => AssocItemId::from(id), | ||
505 | ItemInNs::Types(ModuleDefId::ConstId(id)) | ||
506 | | ItemInNs::Values(ModuleDefId::ConstId(id)) => AssocItemId::from(id), | ||
507 | ItemInNs::Types(ModuleDefId::TypeAliasId(id)) | ||
508 | | ItemInNs::Values(ModuleDefId::TypeAliasId(id)) => AssocItemId::from(id), | ||
509 | _ => return None, | ||
510 | }; | ||
511 | |||
512 | let trait_ = assoc_to_trait(db, dependency)?; | ||
513 | if let ModuleDefId::TraitId(tr) = trait_.as_module_def_id()? { | ||
514 | let trait_data = db.trait_data(tr); | ||
515 | let assoc_item_name = | ||
516 | trait_data.items.iter().find_map(|(assoc_item_name, assoc_item_id)| { | ||
517 | if &dependency_assoc_item_id == assoc_item_id { | ||
518 | Some(assoc_item_name) | ||
519 | } else { | ||
520 | None | ||
521 | } | ||
522 | })?; | ||
523 | return Some(format!("{}::{}", dependency_imports.path_of(trait_)?, assoc_item_name)); | ||
524 | } | ||
525 | None | ||
526 | } | ||
527 | |||
492 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> { | 528 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> { |
493 | let assoc: AssocItemId = match item { | 529 | let assoc: AssocItemId = match item { |
494 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { | 530 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { |
@@ -747,6 +783,37 @@ mod tests { | |||
747 | } | 783 | } |
748 | 784 | ||
749 | #[test] | 785 | #[test] |
786 | fn fuzzy_import_trait_and_assoc_items() { | ||
787 | mark::check!(type_aliases_ignored); | ||
788 | let ra_fixture = r#" | ||
789 | //- /main.rs crate:main deps:dep | ||
790 | //- /dep.rs crate:dep | ||
791 | pub mod fmt { | ||
792 | pub trait Display { | ||
793 | type FmtTypeAlias; | ||
794 | const FMT_CONST: bool; | ||
795 | |||
796 | fn format_function(); | ||
797 | fn format_method(&self); | ||
798 | } | ||
799 | } | ||
800 | "#; | ||
801 | |||
802 | check_search( | ||
803 | ra_fixture, | ||
804 | "main", | ||
805 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), | ||
806 | expect![[r#" | ||
807 | dep::fmt (t) | ||
808 | dep::fmt::Display (t) | ||
809 | dep::fmt::Display::FMT_CONST (a) | ||
810 | dep::fmt::Display::format_function (a) | ||
811 | dep::fmt::Display::format_method (a) | ||
812 | "#]], | ||
813 | ); | ||
814 | } | ||
815 | |||
816 | #[test] | ||
750 | fn search_mode() { | 817 | fn search_mode() { |
751 | let ra_fixture = r#" | 818 | let ra_fixture = r#" |
752 | //- /main.rs crate:main deps:dep | 819 | //- /main.rs crate:main deps:dep |
@@ -782,8 +849,8 @@ mod tests { | |||
782 | dep::Fmt (v) | 849 | dep::Fmt (v) |
783 | dep::Fmt (m) | 850 | dep::Fmt (m) |
784 | dep::fmt::Display (t) | 851 | dep::fmt::Display (t) |
852 | dep::fmt::Display::fmt (a) | ||
785 | dep::format (f) | 853 | dep::format (f) |
786 | dep::fmt::Display::fmt (f) | ||
787 | "#]], | 854 | "#]], |
788 | ); | 855 | ); |
789 | 856 | ||
@@ -796,7 +863,7 @@ mod tests { | |||
796 | dep::Fmt (t) | 863 | dep::Fmt (t) |
797 | dep::Fmt (v) | 864 | dep::Fmt (v) |
798 | dep::Fmt (m) | 865 | dep::Fmt (m) |
799 | dep::fmt::Display::fmt (f) | 866 | dep::fmt::Display::fmt (a) |
800 | "#]], | 867 | "#]], |
801 | ); | 868 | ); |
802 | 869 | ||
@@ -810,7 +877,7 @@ mod tests { | |||
810 | dep::Fmt (v) | 877 | dep::Fmt (v) |
811 | dep::Fmt (m) | 878 | dep::Fmt (m) |
812 | dep::fmt::Display (t) | 879 | dep::fmt::Display (t) |
813 | dep::fmt::Display::fmt (f) | 880 | dep::fmt::Display::fmt (a) |
814 | "#]], | 881 | "#]], |
815 | ); | 882 | ); |
816 | } | 883 | } |
@@ -851,7 +918,7 @@ mod tests { | |||
851 | dep::Fmt (v) | 918 | dep::Fmt (v) |
852 | dep::Fmt (m) | 919 | dep::Fmt (m) |
853 | dep::fmt::Display (t) | 920 | dep::fmt::Display (t) |
854 | dep::fmt::Display::fmt (f) | 921 | dep::fmt::Display::fmt (a) |
855 | "#]], | 922 | "#]], |
856 | ); | 923 | ); |
857 | 924 | ||
@@ -864,7 +931,7 @@ mod tests { | |||
864 | dep::Fmt (t) | 931 | dep::Fmt (t) |
865 | dep::Fmt (v) | 932 | dep::Fmt (v) |
866 | dep::Fmt (m) | 933 | dep::Fmt (m) |
867 | dep::fmt::Display::fmt (f) | 934 | dep::fmt::Display::fmt (a) |
868 | "#]], | 935 | "#]], |
869 | ); | 936 | ); |
870 | } | 937 | } |
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index 62ab3b2bd..2750e1c91 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -10,10 +10,9 @@ use once_cell::sync::Lazy; | |||
10 | use rustc_hash::{FxHashMap, FxHashSet}; | 10 | use rustc_hash::{FxHashMap, FxHashSet}; |
11 | use test_utils::mark; | 11 | use test_utils::mark; |
12 | 12 | ||
13 | use crate::ModuleId; | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | 14 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, |
16 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId, | 15 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, ModuleId, TraitId, |
17 | }; | 16 | }; |
18 | 17 | ||
19 | #[derive(Copy, Clone)] | 18 | #[derive(Copy, Clone)] |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 100dbf5d6..b6f510731 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -260,6 +260,7 @@ impl GenericParamsStorage { | |||
260 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { | 260 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { |
261 | if params.types.is_empty() | 261 | if params.types.is_empty() |
262 | && params.lifetimes.is_empty() | 262 | && params.lifetimes.is_empty() |
263 | && params.consts.is_empty() | ||
263 | && params.where_predicates.is_empty() | 264 | && params.where_predicates.is_empty() |
264 | { | 265 | { |
265 | return GenericParamsId::EMPTY; | 266 | return GenericParamsId::EMPTY; |
@@ -269,8 +270,12 @@ impl GenericParamsStorage { | |||
269 | } | 270 | } |
270 | } | 271 | } |
271 | 272 | ||
272 | static EMPTY_GENERICS: GenericParams = | 273 | static EMPTY_GENERICS: GenericParams = GenericParams { |
273 | GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() }; | 274 | types: Arena::new(), |
275 | lifetimes: Arena::new(), | ||
276 | consts: Arena::new(), | ||
277 | where_predicates: Vec::new(), | ||
278 | }; | ||
274 | 279 | ||
275 | #[derive(Default, Debug, Eq, PartialEq)] | 280 | #[derive(Default, Debug, Eq, PartialEq)] |
276 | struct ItemTreeData { | 281 | struct ItemTreeData { |
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs index 9c585de2c..89b3ed868 100644 --- a/crates/hir_def/src/keys.rs +++ b/crates/hir_def/src/keys.rs | |||
@@ -8,8 +8,8 @@ use syntax::{ast, AstNode, AstPtr}; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | dyn_map::{DynMap, Policy}, | 10 | dyn_map::{DynMap, Policy}, |
11 | ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId, | 11 | ConstId, ConstParamId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, |
12 | StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 12 | StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; | 15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; |
@@ -29,6 +29,7 @@ pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new(); | |||
29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); | 29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); |
30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); | 30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); |
31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); | 31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); |
32 | pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new(); | ||
32 | 33 | ||
33 | pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); | 34 | pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); |
34 | 35 | ||
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index ba09a9126..211cb2faf 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -232,6 +232,13 @@ pub struct LifetimeParamId { | |||
232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; | 232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; |
233 | 233 | ||
234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
235 | pub struct ConstParamId { | ||
236 | pub parent: GenericDefId, | ||
237 | pub local_id: LocalConstParamId, | ||
238 | } | ||
239 | pub type LocalConstParamId = Idx<generics::ConstParamData>; | ||
240 | |||
241 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
235 | pub enum ContainerId { | 242 | pub enum ContainerId { |
236 | ModuleId(ModuleId), | 243 | ModuleId(ModuleId), |
237 | DefWithBodyId(DefWithBodyId), | 244 | DefWithBodyId(DefWithBodyId), |
@@ -254,6 +261,15 @@ pub enum AdtId { | |||
254 | } | 261 | } |
255 | impl_from!(StructId, UnionId, EnumId for AdtId); | 262 | impl_from!(StructId, UnionId, EnumId for AdtId); |
256 | 263 | ||
264 | /// A generic param | ||
265 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
266 | pub enum GenericParamId { | ||
267 | TypeParamId(TypeParamId), | ||
268 | LifetimeParamId(LifetimeParamId), | ||
269 | ConstParamId(ConstParamId), | ||
270 | } | ||
271 | impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId); | ||
272 | |||
257 | /// The defs which can be visible in the module. | 273 | /// The defs which can be visible in the module. |
258 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 274 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
259 | pub enum ModuleDefId { | 275 | pub enum ModuleDefId { |
@@ -350,6 +366,7 @@ pub enum AttrDefId { | |||
350 | TypeAliasId(TypeAliasId), | 366 | TypeAliasId(TypeAliasId), |
351 | MacroDefId(MacroDefId), | 367 | MacroDefId(MacroDefId), |
352 | ImplId(ImplId), | 368 | ImplId(ImplId), |
369 | GenericParamId(GenericParamId), | ||
353 | } | 370 | } |
354 | 371 | ||
355 | impl_from!( | 372 | impl_from!( |
@@ -363,7 +380,8 @@ impl_from!( | |||
363 | TraitId, | 380 | TraitId, |
364 | TypeAliasId, | 381 | TypeAliasId, |
365 | MacroDefId, | 382 | MacroDefId, |
366 | ImplId | 383 | ImplId, |
384 | GenericParamId | ||
367 | for AttrDefId | 385 | for AttrDefId |
368 | ); | 386 | ); |
369 | 387 | ||
@@ -488,6 +506,15 @@ impl AttrDefId { | |||
488 | AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, | 506 | AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, |
489 | AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, | 507 | AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, |
490 | AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, | 508 | AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, |
509 | AttrDefId::GenericParamId(it) => { | ||
510 | match it { | ||
511 | GenericParamId::TypeParamId(it) => it.parent, | ||
512 | GenericParamId::LifetimeParamId(it) => it.parent, | ||
513 | GenericParamId::ConstParamId(it) => it.parent, | ||
514 | } | ||
515 | .module(db) | ||
516 | .krate | ||
517 | } | ||
491 | // FIXME: `MacroDefId` should store the defining module, then this can implement | 518 | // FIXME: `MacroDefId` should store the defining module, then this can implement |
492 | // `HasModule` | 519 | // `HasModule` |
493 | AttrDefId::MacroDefId(it) => it.krate, | 520 | AttrDefId::MacroDefId(it) => it.krate, |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 9bf358775..5682e122d 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -454,7 +454,7 @@ mod diagnostics { | |||
454 | }); | 454 | }); |
455 | for token in tokens { | 455 | for token in tokens { |
456 | if token.kind() == SyntaxKind::IDENT | 456 | if token.kind() == SyntaxKind::IDENT |
457 | && token.to_string() == *name | 457 | && token.text() == name.as_str() |
458 | { | 458 | { |
459 | precise_location = Some(token.text_range()); | 459 | precise_location = Some(token.text_range()); |
460 | break 'outer; | 460 | break 'outer; |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index a636ec77d..f027fd48d 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -13,7 +13,7 @@ use hir_expand::{ | |||
13 | builtin_macro::find_builtin_macro, | 13 | builtin_macro::find_builtin_macro, |
14 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
15 | proc_macro::ProcMacroExpander, | 15 | proc_macro::ProcMacroExpander, |
16 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | 16 | HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
17 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -267,7 +267,7 @@ impl DefCollector<'_> { | |||
267 | 267 | ||
268 | // Resolve all indeterminate resolved imports again | 268 | // Resolve all indeterminate resolved imports again |
269 | // As some of the macros will expand newly import shadowing partial resolved imports | 269 | // As some of the macros will expand newly import shadowing partial resolved imports |
270 | // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports` | 270 | // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports` |
271 | // correctly | 271 | // correctly |
272 | let partial_resolved = self.resolved_imports.iter().filter_map(|directive| { | 272 | let partial_resolved = self.resolved_imports.iter().filter_map(|directive| { |
273 | if let PartialResolvedImport::Indeterminate(_) = directive.status { | 273 | if let PartialResolvedImport::Indeterminate(_) = directive.status { |
@@ -402,7 +402,7 @@ impl DefCollector<'_> { | |||
402 | 402 | ||
403 | /// Define a proc macro | 403 | /// Define a proc macro |
404 | /// | 404 | /// |
405 | /// A proc macro is similar to normal macro scope, but it would not visiable in legacy textual scoped. | 405 | /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. |
406 | /// And unconditionally exported. | 406 | /// And unconditionally exported. |
407 | fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { | 407 | fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { |
408 | self.update( | 408 | self.update( |
@@ -592,7 +592,7 @@ impl DefCollector<'_> { | |||
592 | // XXX: urgh, so this works by accident! Here, we look at | 592 | // XXX: urgh, so this works by accident! Here, we look at |
593 | // the enum data, and, in theory, this might require us to | 593 | // the enum data, and, in theory, this might require us to |
594 | // look back at the crate_def_map, creating a cycle. For | 594 | // look back at the crate_def_map, creating a cycle. For |
595 | // example, `enum E { crate::some_macro!(); }`. Luckely, the | 595 | // example, `enum E { crate::some_macro!(); }`. Luckily, the |
596 | // only kind of macro that is allowed inside enum is a | 596 | // only kind of macro that is allowed inside enum is a |
597 | // `cfg_macro`, and we don't need to run name resolution for | 597 | // `cfg_macro`, and we don't need to run name resolution for |
598 | // it, but this is sheer luck! | 598 | // it, but this is sheer luck! |
@@ -655,7 +655,7 @@ impl DefCollector<'_> { | |||
655 | &mut self, | 655 | &mut self, |
656 | module_id: LocalModuleId, | 656 | module_id: LocalModuleId, |
657 | resolutions: &[(Option<Name>, PerNs)], | 657 | resolutions: &[(Option<Name>, PerNs)], |
658 | // All resolutions are imported with this visibility; the visibilies in | 658 | // All resolutions are imported with this visibility; the visibilities in |
659 | // the `PerNs` values are ignored and overwritten | 659 | // the `PerNs` values are ignored and overwritten |
660 | vis: Visibility, | 660 | vis: Visibility, |
661 | import_type: ImportType, | 661 | import_type: ImportType, |
@@ -860,6 +860,37 @@ impl DefCollector<'_> { | |||
860 | } | 860 | } |
861 | 861 | ||
862 | fn finish(mut self) -> CrateDefMap { | 862 | fn finish(mut self) -> CrateDefMap { |
863 | // Emit diagnostics for all remaining unexpanded macros. | ||
864 | |||
865 | for directive in &self.unexpanded_macros { | ||
866 | let mut error = None; | ||
867 | directive.ast_id.as_call_id_with_errors( | ||
868 | self.db, | ||
869 | self.def_map.krate, | ||
870 | |path| { | ||
871 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | ||
872 | self.db, | ||
873 | ResolveMode::Other, | ||
874 | directive.module_id, | ||
875 | &path, | ||
876 | BuiltinShadowMode::Module, | ||
877 | ); | ||
878 | resolved_res.resolved_def.take_macros() | ||
879 | }, | ||
880 | &mut |e| { | ||
881 | error.get_or_insert(e); | ||
882 | }, | ||
883 | ); | ||
884 | |||
885 | if let Some(err) = error { | ||
886 | self.def_map.diagnostics.push(DefDiagnostic::macro_error( | ||
887 | directive.module_id, | ||
888 | MacroCallKind::FnLike(directive.ast_id.ast_id), | ||
889 | err.to_string(), | ||
890 | )); | ||
891 | } | ||
892 | } | ||
893 | |||
863 | // Emit diagnostics for all remaining unresolved imports. | 894 | // Emit diagnostics for all remaining unresolved imports. |
864 | 895 | ||
865 | // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't | 896 | // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't |
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs index 8981fa7c9..509e1bbbc 100644 --- a/crates/hir_def/src/nameres/tests/incremental.rs +++ b/crates/hir_def/src/nameres/tests/incremental.rs | |||
@@ -28,7 +28,7 @@ fn typing_inside_a_function_should_not_invalidate_def_map() { | |||
28 | check_def_map_is_not_recomputed( | 28 | check_def_map_is_not_recomputed( |
29 | r" | 29 | r" |
30 | //- /lib.rs | 30 | //- /lib.rs |
31 | mod foo;<|> | 31 | mod foo;$0 |
32 | 32 | ||
33 | use crate::foo::bar::Baz; | 33 | use crate::foo::bar::Baz; |
34 | 34 | ||
@@ -81,7 +81,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
81 | pub mod bar; | 81 | pub mod bar; |
82 | 82 | ||
83 | //- /foo/bar.rs | 83 | //- /foo/bar.rs |
84 | <|> | 84 | $0 |
85 | m!(X); | 85 | m!(X); |
86 | ", | 86 | ", |
87 | ); | 87 | ); |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index e2bf85bbc..3dd7c3cbb 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -305,6 +305,7 @@ pub use hir_expand::name as __name; | |||
305 | macro_rules! __known_path { | 305 | macro_rules! __known_path { |
306 | (core::iter::IntoIterator) => {}; | 306 | (core::iter::IntoIterator) => {}; |
307 | (core::result::Result) => {}; | 307 | (core::result::Result) => {}; |
308 | (core::option::Option) => {}; | ||
308 | (core::ops::Range) => {}; | 309 | (core::ops::Range) => {}; |
309 | (core::ops::RangeFrom) => {}; | 310 | (core::ops::RangeFrom) => {}; |
310 | (core::ops::RangeFull) => {}; | 311 | (core::ops::RangeFull) => {}; |
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 8a01e6eea..9518ac109 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -123,7 +123,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
123 | // We follow what it did anyway :) | 123 | // We follow what it did anyway :) |
124 | if segments.len() == 1 && kind == PathKind::Plain { | 124 | if segments.len() == 1 && kind == PathKind::Plain { |
125 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | 125 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { |
126 | if let Some(crate_id) = hygiene.local_inner_macros() { | 126 | if let Some(crate_id) = hygiene.local_inner_macros(path) { |
127 | kind = PathKind::DollarCrate(crate_id); | 127 | kind = PathKind::DollarCrate(crate_id); |
128 | } | 128 | } |
129 | } | 129 | } |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 779754ada..61059c349 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -20,14 +20,14 @@ use crate::{ | |||
20 | path::{ModPath, PathKind}, | 20 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 21 | per_ns::PerNs, |
22 | visibility::{RawVisibility, Visibility}, | 22 | visibility::{RawVisibility, Visibility}, |
23 | AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, | 23 | AdtId, AssocContainerId, ConstId, ConstParamId, ContainerId, DefWithBodyId, EnumId, |
24 | FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, | 24 | EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, |
25 | StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, | 25 | ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | #[derive(Debug, Clone, Default)] | 28 | #[derive(Debug, Clone, Default)] |
29 | pub struct Resolver { | 29 | pub struct Resolver { |
30 | // FIXME: all usages generally call `.rev`, so maybe reverse once in consturciton? | 30 | // FIXME: all usages generally call `.rev`, so maybe reverse once in construction? |
31 | scopes: Vec<Scope>, | 31 | scopes: Vec<Scope>, |
32 | } | 32 | } |
33 | 33 | ||
@@ -93,6 +93,7 @@ pub enum ValueNs { | |||
93 | StaticId(StaticId), | 93 | StaticId(StaticId), |
94 | StructId(StructId), | 94 | StructId(StructId), |
95 | EnumVariantId(EnumVariantId), | 95 | EnumVariantId(EnumVariantId), |
96 | GenericParam(ConstParamId), | ||
96 | } | 97 | } |
97 | 98 | ||
98 | impl Resolver { | 99 | impl Resolver { |
@@ -163,7 +164,7 @@ impl Resolver { | |||
163 | } | 164 | } |
164 | 165 | ||
165 | Scope::GenericParams { params, def } => { | 166 | Scope::GenericParams { params, def } => { |
166 | if let Some(local_id) = params.find_by_name(first_name) { | 167 | if let Some(local_id) = params.find_type_by_name(first_name) { |
167 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | 168 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; |
168 | return Some(( | 169 | return Some(( |
169 | TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), | 170 | TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), |
@@ -285,11 +286,17 @@ impl Resolver { | |||
285 | Scope::ExprScope(_) => continue, | 286 | Scope::ExprScope(_) => continue, |
286 | 287 | ||
287 | Scope::GenericParams { params, def } if n_segments > 1 => { | 288 | Scope::GenericParams { params, def } if n_segments > 1 => { |
288 | if let Some(local_id) = params.find_by_name(first_name) { | 289 | if let Some(local_id) = params.find_type_by_name(first_name) { |
289 | let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); | 290 | let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); |
290 | return Some(ResolveValueResult::Partial(ty, 1)); | 291 | return Some(ResolveValueResult::Partial(ty, 1)); |
291 | } | 292 | } |
292 | } | 293 | } |
294 | Scope::GenericParams { params, def } if n_segments == 1 => { | ||
295 | if let Some(local_id) = params.find_const_by_name(first_name) { | ||
296 | let val = ValueNs::GenericParam(ConstParamId { local_id, parent: *def }); | ||
297 | return Some(ResolveValueResult::ValueNs(val)); | ||
298 | } | ||
299 | } | ||
293 | Scope::GenericParams { .. } => continue, | 300 | Scope::GenericParams { .. } => continue, |
294 | 301 | ||
295 | Scope::ImplDefScope(impl_) => { | 302 | Scope::ImplDefScope(impl_) => { |
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs index ad378762a..eb257579f 100644 --- a/crates/hir_expand/src/builtin_derive.rs +++ b/crates/hir_expand/src/builtin_derive.rs | |||
@@ -277,7 +277,7 @@ mod tests { | |||
277 | let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); | 277 | let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); |
278 | let fixture = format!( | 278 | let fixture = format!( |
279 | r#"//- /main.rs crate:main deps:core | 279 | r#"//- /main.rs crate:main deps:core |
280 | <|> | 280 | $0 |
281 | {} | 281 | {} |
282 | //- /lib.rs crate:core | 282 | //- /lib.rs crate:core |
283 | // empty | 283 | // empty |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 6382521fb..80b60d59f 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -259,7 +259,8 @@ fn format_args_expand( | |||
259 | } | 259 | } |
260 | for arg in &mut args { | 260 | for arg in &mut args { |
261 | // Remove `key =`. | 261 | // Remove `key =`. |
262 | if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=') { | 262 | if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) |
263 | { | ||
263 | arg.drain(..2); | 264 | arg.drain(..2); |
264 | } | 265 | } |
265 | } | 266 | } |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 06f0a3ed9..c62086390 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -8,9 +8,9 @@ use parser::FragmentKind; | |||
8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, | 11 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, |
12 | HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, | 12 | EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, |
13 | MacroFile, ProcMacroExpander, | 13 | MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | /// Total limit on the number of tokens produced by any macro invocation. | 16 | /// Total limit on the number of tokens produced by any macro invocation. |
@@ -40,7 +40,7 @@ impl TokenExpander { | |||
40 | // FIXME switch these to ExpandResult as well | 40 | // FIXME switch these to ExpandResult as well |
41 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), | 41 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), |
42 | TokenExpander::ProcMacro(_) => { | 42 | TokenExpander::ProcMacro(_) => { |
43 | // We store the result in salsa db to prevent non-determinisc behavior in | 43 | // We store the result in salsa db to prevent non-deterministic behavior in |
44 | // some proc-macro implementation | 44 | // some proc-macro implementation |
45 | // See #4315 for details | 45 | // See #4315 for details |
46 | db.expand_proc_macro(id.into()).into() | 46 | db.expand_proc_macro(id.into()).into() |
@@ -94,6 +94,8 @@ pub trait AstDatabase: SourceDatabase { | |||
94 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; | 94 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; |
95 | 95 | ||
96 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; | 96 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; |
97 | |||
98 | fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>; | ||
97 | } | 99 | } |
98 | 100 | ||
99 | /// This expands the given macro call, but with different arguments. This is | 101 | /// This expands the given macro call, but with different arguments. This is |
@@ -369,6 +371,10 @@ fn parse_macro_with_arg( | |||
369 | } | 371 | } |
370 | } | 372 | } |
371 | 373 | ||
374 | fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { | ||
375 | Arc::new(HygieneFrame::new(db, file_id)) | ||
376 | } | ||
377 | |||
372 | /// Given a `MacroCallId`, return what `FragmentKind` it belongs to. | 378 | /// Given a `MacroCallId`, return what `FragmentKind` it belongs to. |
373 | /// FIXME: Not completed | 379 | /// FIXME: Not completed |
374 | fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | 380 | fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { |
@@ -404,7 +410,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | |||
404 | TRY_EXPR => FragmentKind::Expr, | 410 | TRY_EXPR => FragmentKind::Expr, |
405 | TUPLE_EXPR => FragmentKind::Expr, | 411 | TUPLE_EXPR => FragmentKind::Expr, |
406 | PAREN_EXPR => FragmentKind::Expr, | 412 | PAREN_EXPR => FragmentKind::Expr, |
407 | 413 | ARRAY_EXPR => FragmentKind::Expr, | |
408 | FOR_EXPR => FragmentKind::Expr, | 414 | FOR_EXPR => FragmentKind::Expr, |
409 | PATH_EXPR => FragmentKind::Expr, | 415 | PATH_EXPR => FragmentKind::Expr, |
410 | CLOSURE_EXPR => FragmentKind::Expr, | 416 | CLOSURE_EXPR => FragmentKind::Expr, |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 6354b090d..ae7b51a08 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -218,6 +218,12 @@ fn eager_macro_recur( | |||
218 | } | 218 | } |
219 | }; | 219 | }; |
220 | 220 | ||
221 | // check if the whole original sytnax is replaced | ||
222 | // Note that SyntaxRewriter cannot replace the root node itself | ||
223 | if child.syntax() == &original { | ||
224 | return Ok(insert); | ||
225 | } | ||
226 | |||
221 | rewriter.replace(child.syntax(), &insert); | 227 | rewriter.replace(child.syntax(), &insert); |
222 | } | 228 | } |
223 | 229 | ||
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 7ab0a5e52..8db581b77 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -2,65 +2,209 @@ | |||
2 | //! | 2 | //! |
3 | //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at | 3 | //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at |
4 | //! this moment, this is horribly incomplete and handles only `$crate`. | 4 | //! this moment, this is horribly incomplete and handles only `$crate`. |
5 | use std::sync::Arc; | ||
6 | |||
5 | use base_db::CrateId; | 7 | use base_db::CrateId; |
6 | use either::Either; | 8 | use either::Either; |
7 | use syntax::ast; | 9 | use mbe::Origin; |
10 | use parser::SyntaxKind; | ||
11 | use syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize}; | ||
8 | 12 | ||
9 | use crate::{ | 13 | use crate::{ |
10 | db::AstDatabase, | 14 | db::{self, AstDatabase}, |
11 | name::{AsName, Name}, | 15 | name::{AsName, Name}, |
12 | HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, | 16 | HirFileId, HirFileIdRepr, InFile, MacroCallId, MacroCallLoc, MacroDefKind, MacroFile, |
13 | }; | 17 | }; |
14 | 18 | ||
15 | #[derive(Clone, Debug)] | 19 | #[derive(Clone, Debug)] |
16 | pub struct Hygiene { | 20 | pub struct Hygiene { |
17 | // This is what `$crate` expands to | 21 | frames: Option<HygieneFrames>, |
18 | def_crate: Option<CrateId>, | ||
19 | |||
20 | // Indicate this is a local inner macro | ||
21 | local_inner: bool, | ||
22 | } | 22 | } |
23 | 23 | ||
24 | impl Hygiene { | 24 | impl Hygiene { |
25 | pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { | 25 | pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { |
26 | let (def_crate, local_inner) = match file_id.0 { | 26 | Hygiene { frames: Some(HygieneFrames::new(db, file_id.clone())) } |
27 | HirFileIdRepr::FileId(_) => (None, false), | ||
28 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { | ||
29 | MacroCallId::LazyMacro(id) => { | ||
30 | let loc = db.lookup_intern_macro(id); | ||
31 | match loc.def.kind { | ||
32 | MacroDefKind::Declarative => (Some(loc.def.krate), loc.def.local_inner), | ||
33 | MacroDefKind::BuiltIn(_) => (Some(loc.def.krate), false), | ||
34 | MacroDefKind::BuiltInDerive(_) => (None, false), | ||
35 | MacroDefKind::BuiltInEager(_) => (None, false), | ||
36 | MacroDefKind::ProcMacro(_) => (None, false), | ||
37 | } | ||
38 | } | ||
39 | MacroCallId::EagerMacro(_id) => (None, false), | ||
40 | }, | ||
41 | }; | ||
42 | Hygiene { def_crate, local_inner } | ||
43 | } | 27 | } |
44 | 28 | ||
45 | pub fn new_unhygienic() -> Hygiene { | 29 | pub fn new_unhygienic() -> Hygiene { |
46 | Hygiene { def_crate: None, local_inner: false } | 30 | Hygiene { frames: None } |
47 | } | 31 | } |
48 | 32 | ||
49 | // FIXME: this should just return name | 33 | // FIXME: this should just return name |
50 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { | 34 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { |
51 | if let Some(def_crate) = self.def_crate { | 35 | if let Some(frames) = &self.frames { |
52 | if name_ref.text() == "$crate" { | 36 | if name_ref.text() == "$crate" { |
53 | return Either::Right(def_crate); | 37 | if let Some(krate) = frames.root_crate(name_ref.syntax()) { |
38 | return Either::Right(krate); | ||
39 | } | ||
54 | } | 40 | } |
55 | } | 41 | } |
42 | |||
56 | Either::Left(name_ref.as_name()) | 43 | Either::Left(name_ref.as_name()) |
57 | } | 44 | } |
58 | 45 | ||
59 | pub fn local_inner_macros(&self) -> Option<CrateId> { | 46 | pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> { |
60 | if self.local_inner { | 47 | let mut token = path.syntax().first_token()?.text_range(); |
61 | self.def_crate | 48 | let frames = self.frames.as_ref()?; |
62 | } else { | 49 | let mut current = frames.0.clone(); |
63 | None | 50 | |
51 | loop { | ||
52 | let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(token)?; | ||
53 | if origin == Origin::Def { | ||
54 | return if current.local_inner { frames.root_crate(path.syntax()) } else { None }; | ||
55 | } | ||
56 | current = current.call_site.as_ref()?.clone(); | ||
57 | token = mapped.value; | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | #[derive(Clone, Debug)] | ||
63 | struct HygieneFrames(Arc<HygieneFrame>); | ||
64 | |||
65 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
66 | pub struct HygieneFrame { | ||
67 | expansion: Option<HygieneInfo>, | ||
68 | |||
69 | // Indicate this is a local inner macro | ||
70 | local_inner: bool, | ||
71 | krate: Option<CrateId>, | ||
72 | |||
73 | call_site: Option<Arc<HygieneFrame>>, | ||
74 | def_site: Option<Arc<HygieneFrame>>, | ||
75 | } | ||
76 | |||
77 | impl HygieneFrames { | ||
78 | fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { | ||
79 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) | ||
80 | } | ||
81 | |||
82 | fn root_crate(&self, node: &SyntaxNode) -> Option<CrateId> { | ||
83 | let mut token = node.first_token()?.text_range(); | ||
84 | let mut result = self.0.krate; | ||
85 | let mut current = self.0.clone(); | ||
86 | |||
87 | while let Some((mapped, origin)) = | ||
88 | current.expansion.as_ref().and_then(|it| it.map_ident_up(token)) | ||
89 | { | ||
90 | result = current.krate; | ||
91 | |||
92 | let site = match origin { | ||
93 | Origin::Def => ¤t.def_site, | ||
94 | Origin::Call => ¤t.call_site, | ||
95 | }; | ||
96 | |||
97 | let site = match site { | ||
98 | None => break, | ||
99 | Some(it) => it, | ||
100 | }; | ||
101 | |||
102 | current = site.clone(); | ||
103 | token = mapped.value; | ||
64 | } | 104 | } |
105 | |||
106 | result | ||
107 | } | ||
108 | } | ||
109 | |||
110 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
111 | struct HygieneInfo { | ||
112 | arg_start: InFile<TextSize>, | ||
113 | /// The `macro_rules!` arguments. | ||
114 | def_start: Option<InFile<TextSize>>, | ||
115 | |||
116 | macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, | ||
117 | macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, | ||
118 | exp_map: Arc<mbe::TokenMap>, | ||
119 | } | ||
120 | |||
121 | impl HygieneInfo { | ||
122 | fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> { | ||
123 | let token_id = self.exp_map.token_by_range(token)?; | ||
124 | |||
125 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); | ||
126 | let (token_map, tt) = match origin { | ||
127 | mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), | ||
128 | mbe::Origin::Def => ( | ||
129 | &self.macro_def.1, | ||
130 | self.def_start | ||
131 | .as_ref() | ||
132 | .expect("`Origin::Def` used with non-`macro_rules!` macro") | ||
133 | .clone(), | ||
134 | ), | ||
135 | }; | ||
136 | |||
137 | let range = token_map.range_by_token(token_id)?.by_kind(SyntaxKind::IDENT)?; | ||
138 | Some((tt.with_value(range + tt.value), origin)) | ||
139 | } | ||
140 | } | ||
141 | |||
142 | fn make_hygiene_info( | ||
143 | db: &dyn AstDatabase, | ||
144 | macro_file: MacroFile, | ||
145 | loc: &MacroCallLoc, | ||
146 | ) -> Option<HygieneInfo> { | ||
147 | let arg_tt = loc.kind.arg(db)?; | ||
148 | |||
149 | let def_offset = loc.def.ast_id.and_then(|id| { | ||
150 | let def_tt = match id.to_node(db) { | ||
151 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), | ||
152 | ast::Macro::MacroDef(_) => return None, | ||
153 | }; | ||
154 | Some(InFile::new(id.file_id, def_tt)) | ||
155 | }); | ||
156 | |||
157 | let macro_def = db.macro_def(loc.def)?; | ||
158 | let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; | ||
159 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; | ||
160 | |||
161 | Some(HygieneInfo { | ||
162 | arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()), | ||
163 | def_start: def_offset, | ||
164 | macro_arg, | ||
165 | macro_def, | ||
166 | exp_map, | ||
167 | }) | ||
168 | } | ||
169 | |||
170 | impl HygieneFrame { | ||
171 | pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame { | ||
172 | let (info, krate, local_inner) = match file_id.0 { | ||
173 | HirFileIdRepr::FileId(_) => (None, None, false), | ||
174 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { | ||
175 | MacroCallId::EagerMacro(_id) => (None, None, false), | ||
176 | MacroCallId::LazyMacro(id) => { | ||
177 | let loc = db.lookup_intern_macro(id); | ||
178 | let info = make_hygiene_info(db, macro_file, &loc); | ||
179 | match loc.def.kind { | ||
180 | MacroDefKind::Declarative => { | ||
181 | (info, Some(loc.def.krate), loc.def.local_inner) | ||
182 | } | ||
183 | MacroDefKind::BuiltIn(_) => (info, Some(loc.def.krate), false), | ||
184 | MacroDefKind::BuiltInDerive(_) => (info, None, false), | ||
185 | MacroDefKind::BuiltInEager(_) => (info, None, false), | ||
186 | MacroDefKind::ProcMacro(_) => (info, None, false), | ||
187 | } | ||
188 | } | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | let info = match info { | ||
193 | None => { | ||
194 | return HygieneFrame { | ||
195 | expansion: None, | ||
196 | local_inner, | ||
197 | krate, | ||
198 | call_site: None, | ||
199 | def_site: None, | ||
200 | }; | ||
201 | } | ||
202 | Some(it) => it, | ||
203 | }; | ||
204 | |||
205 | let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); | ||
206 | let call_site = Some(db.hygiene_frame(info.arg_start.file_id)); | ||
207 | |||
208 | HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } | ||
65 | } | 209 | } |
66 | } | 210 | } |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 2f44876a8..95d853b6d 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -164,6 +164,7 @@ pub mod known { | |||
164 | future, | 164 | future, |
165 | result, | 165 | result, |
166 | boxed, | 166 | boxed, |
167 | option, | ||
167 | // Components of known path (type name) | 168 | // Components of known path (type name) |
168 | Iterator, | 169 | Iterator, |
169 | IntoIterator, | 170 | IntoIterator, |
@@ -172,6 +173,7 @@ pub mod known { | |||
172 | Ok, | 173 | Ok, |
173 | Future, | 174 | Future, |
174 | Result, | 175 | Result, |
176 | Option, | ||
175 | Output, | 177 | Output, |
176 | Target, | 178 | Target, |
177 | Box, | 179 | Box, |
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index 7c77f6ce0..1923daca5 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -58,7 +58,7 @@ impl ProcMacroExpander { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { | 60 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { |
61 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = cursor.token_tree() { | 61 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = cursor.token_tree() { |
62 | if punct.char == c { | 62 | if punct.char == c { |
63 | *cursor = cursor.bump(); | 63 | *cursor = cursor.bump(); |
64 | return true; | 64 | return true; |
@@ -68,7 +68,7 @@ fn eat_punct(cursor: &mut Cursor, c: char) -> bool { | |||
68 | } | 68 | } |
69 | 69 | ||
70 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | 70 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { |
71 | if let Some(tt::TokenTree::Subtree(subtree)) = cursor.token_tree() { | 71 | if let Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) = cursor.token_tree() { |
72 | if Some(kind) == subtree.delimiter_kind() { | 72 | if Some(kind) == subtree.delimiter_kind() { |
73 | *cursor = cursor.bump_subtree(); | 73 | *cursor = cursor.bump_subtree(); |
74 | return true; | 74 | return true; |
@@ -78,7 +78,7 @@ fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | 80 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { |
81 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = cursor.token_tree() { | 81 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = cursor.token_tree() { |
82 | if t == ident.text.as_str() { | 82 | if t == ident.text.as_str() { |
83 | *cursor = cursor.bump(); | 83 | *cursor = cursor.bump(); |
84 | return true; | 84 | return true; |
@@ -88,7 +88,7 @@ fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | |||
88 | } | 88 | } |
89 | 89 | ||
90 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | 90 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { |
91 | let buffer = TokenBuffer::new(&tt.token_trees); | 91 | let buffer = TokenBuffer::from_tokens(&tt.token_trees); |
92 | let mut p = buffer.begin(); | 92 | let mut p = buffer.begin(); |
93 | let mut result = tt::Subtree::default(); | 93 | let mut result = tt::Subtree::default(); |
94 | 94 | ||
@@ -106,7 +106,7 @@ fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | result.token_trees.push(curr.token_tree()?.clone()); | 109 | result.token_trees.push(curr.token_tree()?.cloned()); |
110 | p = curr.bump(); | 110 | p = curr.bump(); |
111 | } | 111 | } |
112 | 112 | ||
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 965c1780a..b0a453961 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -10,16 +10,16 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | itertools = "0.9.0" | 13 | itertools = "0.10.0" |
14 | arrayvec = "0.5.1" | 14 | arrayvec = "0.5.1" |
15 | smallvec = "1.2.0" | 15 | smallvec = "1.2.0" |
16 | ena = "0.14.0" | 16 | ena = "0.14.0" |
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.45", default-features = false } | 20 | chalk-solve = { version = "0.47", default-features = false } |
21 | chalk-ir = "0.45" | 21 | chalk-ir = "0.47" |
22 | chalk-recursive = "0.45" | 22 | chalk-recursive = "0.47" |
23 | 23 | ||
24 | stdx = { path = "../stdx", version = "0.0.0" } | 24 | stdx = { path = "../stdx", version = "0.0.0" } |
25 | hir_def = { path = "../hir_def", version = "0.0.0" } | 25 | hir_def = { path = "../hir_def", version = "0.0.0" } |
@@ -31,7 +31,7 @@ syntax = { path = "../syntax", version = "0.0.0" } | |||
31 | test_utils = { path = "../test_utils", version = "0.0.0" } | 31 | test_utils = { path = "../test_utils", version = "0.0.0" } |
32 | 32 | ||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | expect-test = "1.0" | 34 | expect-test = "1.1" |
35 | tracing = "0.1" | 35 | tracing = "0.1" |
36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } | 36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } |
37 | tracing-tree = { version = "0.1.4" } | 37 | tracing-tree = { version = "0.1.4" } |
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index 66bdb8e88..f3567c49e 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs | |||
@@ -5,8 +5,8 @@ use std::sync::Arc; | |||
5 | use arena::map::ArenaMap; | 5 | use arena::map::ArenaMap; |
6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; | 6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; |
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, | 8 | db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, |
9 | TypeParamId, VariantId, | 9 | LocalFieldId, TypeParamId, VariantId, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
@@ -37,6 +37,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
37 | #[salsa::cycle(crate::lower::impl_self_ty_recover)] | 37 | #[salsa::cycle(crate::lower::impl_self_ty_recover)] |
38 | fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; | 38 | fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; |
39 | 39 | ||
40 | #[salsa::invoke(crate::lower::const_param_ty_query)] | ||
41 | fn const_param_ty(&self, def: ConstParamId) -> Ty; | ||
42 | |||
40 | #[salsa::invoke(crate::lower::impl_trait_query)] | 43 | #[salsa::invoke(crate::lower::impl_trait_query)] |
41 | fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; | 44 | fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; |
42 | 45 | ||
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 14e18f5a1..c67a289f2 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -186,9 +186,10 @@ impl Diagnostic for MissingMatchArms { | |||
186 | } | 186 | } |
187 | } | 187 | } |
188 | 188 | ||
189 | // Diagnostic: missing-ok-in-tail-expr | 189 | // Diagnostic: missing-ok-or-some-in-tail-expr |
190 | // | 190 | // |
191 | // This diagnostic is triggered if block that should return `Result` returns a value not wrapped in `Ok`. | 191 | // This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`, |
192 | // or if a block that should return `Option` returns a value not wrapped in `Some`. | ||
192 | // | 193 | // |
193 | // Example: | 194 | // Example: |
194 | // | 195 | // |
@@ -198,17 +199,19 @@ impl Diagnostic for MissingMatchArms { | |||
198 | // } | 199 | // } |
199 | // ``` | 200 | // ``` |
200 | #[derive(Debug)] | 201 | #[derive(Debug)] |
201 | pub struct MissingOkInTailExpr { | 202 | pub struct MissingOkOrSomeInTailExpr { |
202 | pub file: HirFileId, | 203 | pub file: HirFileId, |
203 | pub expr: AstPtr<ast::Expr>, | 204 | pub expr: AstPtr<ast::Expr>, |
205 | // `Some` or `Ok` depending on whether the return type is Result or Option | ||
206 | pub required: String, | ||
204 | } | 207 | } |
205 | 208 | ||
206 | impl Diagnostic for MissingOkInTailExpr { | 209 | impl Diagnostic for MissingOkOrSomeInTailExpr { |
207 | fn code(&self) -> DiagnosticCode { | 210 | fn code(&self) -> DiagnosticCode { |
208 | DiagnosticCode("missing-ok-in-tail-expr") | 211 | DiagnosticCode("missing-ok-or-some-in-tail-expr") |
209 | } | 212 | } |
210 | fn message(&self) -> String { | 213 | fn message(&self) -> String { |
211 | "wrap return expression in Ok".to_string() | 214 | format!("wrap return expression in {}", self.required) |
212 | } | 215 | } |
213 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | 216 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
214 | InFile { file_id: self.file, value: self.expr.clone().into() } | 217 | InFile { file_id: self.file, value: self.expr.clone().into() } |
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 849415706..107417c27 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -11,8 +11,8 @@ use crate::{ | |||
11 | db::HirDatabase, | 11 | db::HirDatabase, |
12 | diagnostics::{ | 12 | diagnostics::{ |
13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | 13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, |
14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, | 14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, |
15 | RemoveThisSemicolon, | 15 | MissingPatFields, RemoveThisSemicolon, |
16 | }, | 16 | }, |
17 | utils::variant_data, | 17 | utils::variant_data, |
18 | ApplicationTy, InferenceResult, Ty, TypeCtor, | 18 | ApplicationTy, InferenceResult, Ty, TypeCtor, |
@@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this | 156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this |
157 | // diagnostic if there are no type mismatches in the containing function. | 157 | // diagnostic if there are no type mismatches in the containing function. |
158 | if self.infer.type_mismatches.iter().next().is_some() { | 158 | if self.infer.type_mismatches.iter().next().is_some() { |
159 | return Some(()); | 159 | return None; |
160 | } | 160 | } |
161 | 161 | ||
162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); | 162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); |
@@ -170,6 +170,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
170 | let mut args = args.clone(); | 170 | let mut args = args.clone(); |
171 | args.insert(0, *receiver); | 171 | args.insert(0, *receiver); |
172 | 172 | ||
173 | let receiver = &self.infer.type_of_expr[*receiver]; | ||
174 | if receiver.strip_references().is_unknown() { | ||
175 | // if the receiver is of unknown type, it's very likely we | ||
176 | // don't know enough to correctly resolve the method call. | ||
177 | // This is kind of a band-aid for #6975. | ||
178 | return None; | ||
179 | } | ||
180 | |||
173 | // FIXME: note that we erase information about substs here. This | 181 | // FIXME: note that we erase information about substs here. This |
174 | // is not right, but, luckily, doesn't matter as we care only | 182 | // is not right, but, luckily, doesn't matter as we care only |
175 | // about the number of params | 183 | // about the number of params |
@@ -298,27 +306,40 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
298 | }; | 306 | }; |
299 | 307 | ||
300 | let core_result_path = path![core::result::Result]; | 308 | let core_result_path = path![core::result::Result]; |
309 | let core_option_path = path![core::option::Option]; | ||
301 | 310 | ||
302 | let resolver = self.owner.resolver(db.upcast()); | 311 | let resolver = self.owner.resolver(db.upcast()); |
303 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { | 312 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { |
304 | Some(it) => it, | 313 | Some(it) => it, |
305 | _ => return, | 314 | _ => return, |
306 | }; | 315 | }; |
316 | let core_option_enum = match resolver.resolve_known_enum(db.upcast(), &core_option_path) { | ||
317 | Some(it) => it, | ||
318 | _ => return, | ||
319 | }; | ||
307 | 320 | ||
308 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); | 321 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); |
309 | let params = match &mismatch.expected { | 322 | let core_option_ctor = TypeCtor::Adt(AdtId::EnumId(core_option_enum)); |
323 | |||
324 | let (params, required) = match &mismatch.expected { | ||
310 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { | 325 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { |
311 | parameters | 326 | (parameters, "Ok".to_string()) |
327 | } | ||
328 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_option_ctor => { | ||
329 | (parameters, "Some".to_string()) | ||
312 | } | 330 | } |
313 | _ => return, | 331 | _ => return, |
314 | }; | 332 | }; |
315 | 333 | ||
316 | if params.len() == 2 && params[0] == mismatch.actual { | 334 | if params.len() > 0 && params[0] == mismatch.actual { |
317 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | 335 | let (_, source_map) = db.body_with_source_map(self.owner.into()); |
318 | 336 | ||
319 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 337 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
320 | self.sink | 338 | self.sink.push(MissingOkOrSomeInTailExpr { |
321 | .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value }); | 339 | file: source_ptr.file_id, |
340 | expr: source_ptr.value, | ||
341 | required, | ||
342 | }); | ||
322 | } | 343 | } |
323 | } | 344 | } |
324 | } | 345 | } |
@@ -358,7 +379,7 @@ pub fn record_literal_missing_fields( | |||
358 | id: ExprId, | 379 | id: ExprId, |
359 | expr: &Expr, | 380 | expr: &Expr, |
360 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { | 381 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { |
361 | let (fields, exhausitve) = match expr { | 382 | let (fields, exhaustive) = match expr { |
362 | Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), | 383 | Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), |
363 | _ => return None, | 384 | _ => return None, |
364 | }; | 385 | }; |
@@ -379,7 +400,7 @@ pub fn record_literal_missing_fields( | |||
379 | if missed_fields.is_empty() { | 400 | if missed_fields.is_empty() { |
380 | return None; | 401 | return None; |
381 | } | 402 | } |
382 | Some((variant_def, missed_fields, exhausitve)) | 403 | Some((variant_def, missed_fields, exhaustive)) |
383 | } | 404 | } |
384 | 405 | ||
385 | pub fn record_pattern_missing_fields( | 406 | pub fn record_pattern_missing_fields( |
@@ -505,6 +526,22 @@ fn f() { | |||
505 | } | 526 | } |
506 | 527 | ||
507 | #[test] | 528 | #[test] |
529 | fn method_unknown_receiver() { | ||
530 | // note: this is incorrect code, so there might be errors on this in the | ||
531 | // future, but we shouldn't emit an argument count diagnostic here | ||
532 | check_diagnostics( | ||
533 | r#" | ||
534 | trait Foo { fn method(&self, arg: usize) {} } | ||
535 | |||
536 | fn f() { | ||
537 | let x; | ||
538 | x.method(); | ||
539 | } | ||
540 | "#, | ||
541 | ); | ||
542 | } | ||
543 | |||
544 | #[test] | ||
508 | fn tuple_struct() { | 545 | fn tuple_struct() { |
509 | check_diagnostics( | 546 | check_diagnostics( |
510 | r#" | 547 | r#" |
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 62c329731..61c47eec8 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -14,7 +14,7 @@ | |||
14 | //! The algorithm implemented here is a modified version of the one described in | 14 | //! The algorithm implemented here is a modified version of the one described in |
15 | //! <http://moscova.inria.fr/~maranget/papers/warn/index.html>. | 15 | //! <http://moscova.inria.fr/~maranget/papers/warn/index.html>. |
16 | //! However, to save future implementors from reading the original paper, we | 16 | //! However, to save future implementors from reading the original paper, we |
17 | //! summarise the algorithm here to hopefully save time and be a little clearer | 17 | //! summarize the algorithm here to hopefully save time and be a little clearer |
18 | //! (without being so rigorous). | 18 | //! (without being so rigorous). |
19 | //! | 19 | //! |
20 | //! The core of the algorithm revolves about a "usefulness" check. In particular, we | 20 | //! The core of the algorithm revolves about a "usefulness" check. In particular, we |
@@ -132,7 +132,7 @@ | |||
132 | //! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). | 132 | //! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). |
133 | //! That means we're going to check the components from left-to-right, so the algorithm | 133 | //! That means we're going to check the components from left-to-right, so the algorithm |
134 | //! operates principally on the first component of the matrix and new pattern-stack `p`. | 134 | //! operates principally on the first component of the matrix and new pattern-stack `p`. |
135 | //! This algorithm is realised in the `is_useful` function. | 135 | //! This algorithm is realized in the `is_useful` function. |
136 | //! | 136 | //! |
137 | //! Base case (`n = 0`, i.e., an empty tuple pattern): | 137 | //! Base case (`n = 0`, i.e., an empty tuple pattern): |
138 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then | 138 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 0e827a29e..d2f1b4014 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -1,14 +1,15 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::fmt; | 3 | use std::{borrow::Cow, fmt}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, | 6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, |
7 | Lifetime, Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 7 | Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
8 | }; | 8 | }; |
9 | use arrayvec::ArrayVec; | ||
9 | use hir_def::{ | 10 | use hir_def::{ |
10 | find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, | 11 | db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, |
11 | Lookup, ModuleId, | 12 | AssocContainerId, HasModule, Lookup, ModuleId, TraitId, |
12 | }; | 13 | }; |
13 | use hir_expand::name::Name; | 14 | use hir_expand::name::Name; |
14 | 15 | ||
@@ -168,7 +169,7 @@ pub enum DisplayTarget { | |||
168 | 169 | ||
169 | impl DisplayTarget { | 170 | impl DisplayTarget { |
170 | fn is_source_code(&self) -> bool { | 171 | fn is_source_code(&self) -> bool { |
171 | matches!(self, Self::SourceCode {..}) | 172 | matches!(self, Self::SourceCode { .. }) |
172 | } | 173 | } |
173 | fn is_test(&self) -> bool { | 174 | fn is_test(&self) -> bool { |
174 | matches!(self, Self::Test) | 175 | matches!(self, Self::Test) |
@@ -257,25 +258,45 @@ impl HirDisplay for ApplicationTy { | |||
257 | t.hir_fmt(f)?; | 258 | t.hir_fmt(f)?; |
258 | write!(f, "; _]")?; | 259 | write!(f, "; _]")?; |
259 | } | 260 | } |
260 | TypeCtor::RawPtr(m) => { | 261 | TypeCtor::RawPtr(m) | TypeCtor::Ref(m) => { |
261 | let t = self.parameters.as_single(); | 262 | let t = self.parameters.as_single(); |
263 | let ty_display = | ||
264 | t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); | ||
262 | 265 | ||
263 | write!(f, "*{}", m.as_keyword_for_ptr())?; | 266 | if matches!(self.ctor, TypeCtor::RawPtr(_)) { |
264 | if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) { | 267 | write!(f, "*{}", m.as_keyword_for_ptr())?; |
265 | write!(f, "(")?; | ||
266 | t.hir_fmt(f)?; | ||
267 | write!(f, ")")?; | ||
268 | } else { | 268 | } else { |
269 | t.hir_fmt(f)?; | 269 | write!(f, "&{}", m.as_keyword_for_ref())?; |
270 | } | ||
271 | |||
272 | let datas; | ||
273 | let predicates = match t { | ||
274 | Ty::Dyn(predicates) if predicates.len() > 1 => { | ||
275 | Cow::Borrowed(predicates.as_ref()) | ||
276 | } | ||
277 | &Ty::Opaque(OpaqueTy { | ||
278 | opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx), | ||
279 | ref parameters, | ||
280 | }) => { | ||
281 | datas = | ||
282 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | ||
283 | let data = (*datas) | ||
284 | .as_ref() | ||
285 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
286 | let bounds = data.subst(parameters); | ||
287 | Cow::Owned(bounds.value) | ||
288 | } | ||
289 | _ => Cow::Borrowed(&[][..]), | ||
290 | }; | ||
291 | |||
292 | if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() { | ||
293 | let trait_ = trait_ref.trait_; | ||
294 | if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) { | ||
295 | return write!(f, "{}", ty_display); | ||
296 | } | ||
270 | } | 297 | } |
271 | } | ||
272 | TypeCtor::Ref(m) => { | ||
273 | let t = self.parameters.as_single(); | ||
274 | let ty_display = | ||
275 | t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); | ||
276 | 298 | ||
277 | write!(f, "&{}", m.as_keyword_for_ref())?; | 299 | if predicates.len() > 1 { |
278 | if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) { | ||
279 | write!(f, "(")?; | 300 | write!(f, "(")?; |
280 | write!(f, "{}", ty_display)?; | 301 | write!(f, "{}", ty_display)?; |
281 | write!(f, ")")?; | 302 | write!(f, ")")?; |
@@ -595,7 +616,18 @@ impl HirDisplay for FnSig { | |||
595 | } | 616 | } |
596 | } | 617 | } |
597 | 618 | ||
598 | fn write_bounds_like_dyn_trait( | 619 | fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> { |
620 | let krate = trait_.lookup(db).container.module(db).krate; | ||
621 | let fn_traits = [ | ||
622 | db.lang_item(krate, "fn".into()), | ||
623 | db.lang_item(krate, "fn_mut".into()), | ||
624 | db.lang_item(krate, "fn_once".into()), | ||
625 | ]; | ||
626 | // FIXME: Replace ArrayVec when into_iter is a thing on arrays | ||
627 | ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait()) | ||
628 | } | ||
629 | |||
630 | pub fn write_bounds_like_dyn_trait( | ||
599 | predicates: &[GenericPredicate], | 631 | predicates: &[GenericPredicate], |
600 | f: &mut HirFormatter, | 632 | f: &mut HirFormatter, |
601 | ) -> Result<(), HirDisplayError> { | 633 | ) -> Result<(), HirDisplayError> { |
@@ -607,10 +639,15 @@ fn write_bounds_like_dyn_trait( | |||
607 | // predicate for that trait). | 639 | // predicate for that trait). |
608 | let mut first = true; | 640 | let mut first = true; |
609 | let mut angle_open = false; | 641 | let mut angle_open = false; |
642 | let mut is_fn_trait = false; | ||
610 | for p in predicates.iter() { | 643 | for p in predicates.iter() { |
611 | match p { | 644 | match p { |
612 | GenericPredicate::Implemented(trait_ref) => { | 645 | GenericPredicate::Implemented(trait_ref) => { |
613 | if angle_open { | 646 | let trait_ = trait_ref.trait_; |
647 | if !is_fn_trait { | ||
648 | is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_); | ||
649 | } | ||
650 | if !is_fn_trait && angle_open { | ||
614 | write!(f, ">")?; | 651 | write!(f, ">")?; |
615 | angle_open = false; | 652 | angle_open = false; |
616 | } | 653 | } |
@@ -620,14 +657,27 @@ fn write_bounds_like_dyn_trait( | |||
620 | // We assume that the self type is $0 (i.e. the | 657 | // We assume that the self type is $0 (i.e. the |
621 | // existential) here, which is the only thing that's | 658 | // existential) here, which is the only thing that's |
622 | // possible in actual Rust, and hence don't print it | 659 | // possible in actual Rust, and hence don't print it |
623 | write!(f, "{}", f.db.trait_data(trait_ref.trait_).name)?; | 660 | write!(f, "{}", f.db.trait_data(trait_).name)?; |
624 | if trait_ref.substs.len() > 1 { | 661 | if let [_, params @ ..] = &*trait_ref.substs.0 { |
625 | write!(f, "<")?; | 662 | if is_fn_trait { |
626 | f.write_joined(&trait_ref.substs[1..], ", ")?; | 663 | if let Some(args) = params.first().and_then(|it| it.as_tuple()) { |
627 | // there might be assoc type bindings, so we leave the angle brackets open | 664 | write!(f, "(")?; |
628 | angle_open = true; | 665 | f.write_joined(&*args.0, ", ")?; |
666 | write!(f, ")")?; | ||
667 | } | ||
668 | } else if !params.is_empty() { | ||
669 | write!(f, "<")?; | ||
670 | f.write_joined(params, ", ")?; | ||
671 | // there might be assoc type bindings, so we leave the angle brackets open | ||
672 | angle_open = true; | ||
673 | } | ||
629 | } | 674 | } |
630 | } | 675 | } |
676 | GenericPredicate::Projection(projection_pred) if is_fn_trait => { | ||
677 | is_fn_trait = false; | ||
678 | write!(f, " -> ")?; | ||
679 | projection_pred.ty.hir_fmt(f)?; | ||
680 | } | ||
631 | GenericPredicate::Projection(projection_pred) => { | 681 | GenericPredicate::Projection(projection_pred) => { |
632 | // in types in actual Rust, these will always come | 682 | // in types in actual Rust, these will always come |
633 | // after the corresponding Implemented predicate | 683 | // after the corresponding Implemented predicate |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 70a3f3075..f2fc69b2f 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -648,6 +648,8 @@ impl<'a> InferenceContext<'a> { | |||
648 | } | 648 | } |
649 | Expr::Array(array) => { | 649 | Expr::Array(array) => { |
650 | let elem_ty = match &expected.ty { | 650 | let elem_ty = match &expected.ty { |
651 | // FIXME: remove when https://github.com/rust-lang/rust/issues/80501 is fixed | ||
652 | #[allow(unreachable_patterns)] | ||
651 | ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { | 653 | ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { |
652 | st.as_single().clone() | 654 | st.as_single().clone() |
653 | } | 655 | } |
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index 80d7ed10e..5d541104e 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs | |||
@@ -89,6 +89,7 @@ impl<'a> InferenceContext<'a> { | |||
89 | return None; | 89 | return None; |
90 | } | 90 | } |
91 | } | 91 | } |
92 | ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | let ty = self.db.value_ty(typable); | 95 | let ty = self.db.value_ty(typable); |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 357bd92f9..e00c7e176 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -791,6 +791,10 @@ impl Ty { | |||
791 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) | 791 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) |
792 | } | 792 | } |
793 | 793 | ||
794 | pub fn is_unknown(&self) -> bool { | ||
795 | matches!(self, Ty::Unknown) | ||
796 | } | ||
797 | |||
794 | /// If this is a `dyn Trait` type, this returns the `Trait` part. | 798 | /// If this is a `dyn Trait` type, this returns the `Trait` part. |
795 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { | 799 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { |
796 | match self { | 800 | match self { |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8da56cd11..9594cce8b 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -16,9 +16,9 @@ use hir_def::{ | |||
16 | path::{GenericArg, Path, PathSegment, PathSegments}, | 16 | path::{GenericArg, Path, PathSegment, PathSegments}, |
17 | resolver::{HasResolver, Resolver, TypeNs}, | 17 | resolver::{HasResolver, Resolver, TypeNs}, |
18 | type_ref::{TypeBound, TypeRef}, | 18 | type_ref::{TypeBound, TypeRef}, |
19 | AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, | 19 | AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, |
20 | HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 20 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, |
21 | UnionId, VariantId, | 21 | TypeAliasId, TypeParamId, UnionId, VariantId, |
22 | }; | 22 | }; |
23 | use hir_expand::name::Name; | 23 | use hir_expand::name::Name; |
24 | use smallvec::SmallVec; | 24 | use smallvec::SmallVec; |
@@ -491,16 +491,16 @@ impl Ty { | |||
491 | fn from_hir_path_inner( | 491 | fn from_hir_path_inner( |
492 | ctx: &TyLoweringContext<'_>, | 492 | ctx: &TyLoweringContext<'_>, |
493 | segment: PathSegment<'_>, | 493 | segment: PathSegment<'_>, |
494 | typable: TyDefId, | 494 | typeable: TyDefId, |
495 | infer_args: bool, | 495 | infer_args: bool, |
496 | ) -> Ty { | 496 | ) -> Ty { |
497 | let generic_def = match typable { | 497 | let generic_def = match typeable { |
498 | TyDefId::BuiltinType(_) => None, | 498 | TyDefId::BuiltinType(_) => None, |
499 | TyDefId::AdtId(it) => Some(it.into()), | 499 | TyDefId::AdtId(it) => Some(it.into()), |
500 | TyDefId::TypeAliasId(it) => Some(it.into()), | 500 | TyDefId::TypeAliasId(it) => Some(it.into()), |
501 | }; | 501 | }; |
502 | let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); | 502 | let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); |
503 | ctx.db.ty(typable).subst(&substs) | 503 | ctx.db.ty(typeable).subst(&substs) |
504 | } | 504 | } |
505 | 505 | ||
506 | /// Collect generic arguments from a path into a `Substs`. See also | 506 | /// Collect generic arguments from a path into a `Substs`. See also |
@@ -1221,6 +1221,15 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde | |||
1221 | Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) | 1221 | Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) |
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { | ||
1225 | let parent_data = db.generic_params(def.parent); | ||
1226 | let data = &parent_data.consts[def.local_id]; | ||
1227 | let resolver = def.parent.resolver(db.upcast()); | ||
1228 | let ctx = TyLoweringContext::new(db, &resolver); | ||
1229 | |||
1230 | Ty::from_hir(&ctx, &data.ty) | ||
1231 | } | ||
1232 | |||
1224 | pub(crate) fn impl_self_ty_recover( | 1233 | pub(crate) fn impl_self_ty_recover( |
1225 | db: &dyn HirDatabase, | 1234 | db: &dyn HirDatabase, |
1226 | _cycle: &[String], | 1235 | _cycle: &[String], |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 0a400cb70..3b1675f0b 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -314,7 +314,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
314 | " | 314 | " |
315 | //- /lib.rs | 315 | //- /lib.rs |
316 | fn foo() -> i32 { | 316 | fn foo() -> i32 { |
317 | <|>1 + 1 | 317 | $01 + 1 |
318 | } | 318 | } |
319 | ", | 319 | ", |
320 | ); | 320 | ); |
diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs index b502135d8..3d29021aa 100644 --- a/crates/hir_ty/src/tests/display_source_code.rs +++ b/crates/hir_ty/src/tests/display_source_code.rs | |||
@@ -39,3 +39,18 @@ fn main() { | |||
39 | "#, | 39 | "#, |
40 | ); | 40 | ); |
41 | } | 41 | } |
42 | |||
43 | #[test] | ||
44 | fn render_raw_ptr_impl_ty() { | ||
45 | check_types_source_code( | ||
46 | r#" | ||
47 | trait Sized {} | ||
48 | trait Unpin {} | ||
49 | fn foo() -> *const (impl Unpin + Sized) { loop {} } | ||
50 | fn main() { | ||
51 | let foo = foo(); | ||
52 | foo; | ||
53 | } //^ *const (impl Unpin + Sized) | ||
54 | "#, | ||
55 | ); | ||
56 | } | ||
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index a7656b864..c64f0b5b5 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -371,6 +371,37 @@ expand!(); | |||
371 | } | 371 | } |
372 | 372 | ||
373 | #[test] | 373 | #[test] |
374 | fn infer_macro_with_dollar_crate_in_def_site() { | ||
375 | check_types( | ||
376 | r#" | ||
377 | //- /main.rs crate:main deps:foo | ||
378 | use foo::expand; | ||
379 | |||
380 | macro_rules! list { | ||
381 | ($($tt:tt)*) => { $($tt)* } | ||
382 | } | ||
383 | |||
384 | fn test() { | ||
385 | let r = expand!(); | ||
386 | r; | ||
387 | //^ u128 | ||
388 | } | ||
389 | |||
390 | //- /lib.rs crate:foo | ||
391 | #[macro_export] | ||
392 | macro_rules! expand { | ||
393 | () => { list!($crate::m!()) }; | ||
394 | } | ||
395 | |||
396 | #[macro_export] | ||
397 | macro_rules! m { | ||
398 | () => { 0u128 }; | ||
399 | } | ||
400 | "#, | ||
401 | ); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
374 | fn infer_type_value_non_legacy_macro_use_as() { | 405 | fn infer_type_value_non_legacy_macro_use_as() { |
375 | check_infer( | 406 | check_infer( |
376 | r#" | 407 | r#" |
@@ -540,6 +571,52 @@ fn bar() -> u32 {0} | |||
540 | } | 571 | } |
541 | 572 | ||
542 | #[test] | 573 | #[test] |
574 | fn infer_builtin_macros_include_str() { | ||
575 | check_types( | ||
576 | r#" | ||
577 | //- /main.rs | ||
578 | #[rustc_builtin_macro] | ||
579 | macro_rules! include_str {() => {}} | ||
580 | |||
581 | fn main() { | ||
582 | let a = include_str!("foo.rs"); | ||
583 | a; | ||
584 | } //^ &str | ||
585 | |||
586 | //- /foo.rs | ||
587 | hello | ||
588 | "#, | ||
589 | ); | ||
590 | } | ||
591 | |||
592 | #[test] | ||
593 | fn infer_builtin_macros_include_str_with_lazy_nested() { | ||
594 | check_types( | ||
595 | r#" | ||
596 | //- /main.rs | ||
597 | #[rustc_builtin_macro] | ||
598 | macro_rules! concat {() => {}} | ||
599 | #[rustc_builtin_macro] | ||
600 | macro_rules! include_str {() => {}} | ||
601 | |||
602 | macro_rules! m { | ||
603 | ($x:expr) => { | ||
604 | concat!("foo", $x) | ||
605 | }; | ||
606 | } | ||
607 | |||
608 | fn main() { | ||
609 | let a = include_str!(m!(".rs")); | ||
610 | a; | ||
611 | } //^ &str | ||
612 | |||
613 | //- /foo.rs | ||
614 | hello | ||
615 | "#, | ||
616 | ); | ||
617 | } | ||
618 | |||
619 | #[test] | ||
543 | #[ignore] | 620 | #[ignore] |
544 | fn include_accidentally_quadratic() { | 621 | fn include_accidentally_quadratic() { |
545 | let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic"); | 622 | let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic"); |
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 307a257b1..cffe8630b 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -326,6 +326,24 @@ fn infer_paren_macro_call() { | |||
326 | } | 326 | } |
327 | 327 | ||
328 | #[test] | 328 | #[test] |
329 | fn infer_array_macro_call() { | ||
330 | check_infer( | ||
331 | r#" | ||
332 | macro_rules! bar { () => {0u32} } | ||
333 | fn test() { | ||
334 | let a = [bar!()]; | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | !0..4 '0u32': u32 | ||
339 | 44..69 '{ ...()]; }': () | ||
340 | 54..55 'a': [u32; _] | ||
341 | 58..66 '[bar!()]': [u32; _] | ||
342 | "#]], | ||
343 | ); | ||
344 | } | ||
345 | |||
346 | #[test] | ||
329 | fn bug_1030() { | 347 | fn bug_1030() { |
330 | check_infer( | 348 | check_infer( |
331 | r#" | 349 | r#" |
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index a61282d5a..8d431b920 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -2375,3 +2375,19 @@ fn infer_operator_overload() { | |||
2375 | "#]], | 2375 | "#]], |
2376 | ); | 2376 | ); |
2377 | } | 2377 | } |
2378 | |||
2379 | #[test] | ||
2380 | fn infer_const_params() { | ||
2381 | check_infer( | ||
2382 | r#" | ||
2383 | fn foo<const FOO: usize>() { | ||
2384 | let bar = FOO; | ||
2385 | } | ||
2386 | "#, | ||
2387 | expect![[r#" | ||
2388 | 27..49 '{ ...FOO; }': () | ||
2389 | 37..40 'bar': usize | ||
2390 | 43..46 'FOO': usize | ||
2391 | "#]], | ||
2392 | ); | ||
2393 | } | ||
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 41d097519..e5a3f95a6 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -3038,16 +3038,16 @@ fn infer_box_fn_arg() { | |||
3038 | 406..417 '&self.inner': &*mut T | 3038 | 406..417 '&self.inner': &*mut T |
3039 | 407..411 'self': &Box<T> | 3039 | 407..411 'self': &Box<T> |
3040 | 407..417 'self.inner': *mut T | 3040 | 407..417 'self.inner': *mut T |
3041 | 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | 3041 | 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> |
3042 | 488..489 's': Option<i32> | 3042 | 488..489 's': Option<i32> |
3043 | 492..504 'Option::None': Option<i32> | 3043 | 492..504 'Option::None': Option<i32> |
3044 | 514..515 'f': Box<dyn FnOnce<(&Option<i32>,)>> | 3044 | 514..515 'f': Box<dyn FnOnce(&Option<i32>)> |
3045 | 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> | 3045 | 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> |
3046 | 554..561 '|ps| {}': |{unknown}| -> () | 3046 | 554..561 '|ps| {}': |{unknown}| -> () |
3047 | 555..557 'ps': {unknown} | 3047 | 555..557 'ps': {unknown} |
3048 | 559..561 '{}': () | 3048 | 559..561 '{}': () |
3049 | 568..569 'f': Box<dyn FnOnce<(&Option<i32>,)>> | 3049 | 568..569 'f': Box<dyn FnOnce(&Option<i32>)> |
3050 | 568..573 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | 3050 | 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> |
3051 | 570..572 '&s': &Option<i32> | 3051 | 570..572 '&s': &Option<i32> |
3052 | 571..572 's': Option<i32> | 3052 | 571..572 's': Option<i32> |
3053 | "#]], | 3053 | "#]], |
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 4d483580d..bb28cca4d 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | [dependencies] | 12 | [dependencies] |
13 | either = "1.5.3" | 13 | either = "1.5.3" |
14 | indexmap = "1.4.0" | 14 | indexmap = "1.4.0" |
15 | itertools = "0.9.0" | 15 | itertools = "0.10.0" |
16 | log = "0.4.8" | 16 | log = "0.4.8" |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | oorandom = "11.1.2" | 18 | oorandom = "11.1.2" |
@@ -36,4 +36,4 @@ completion = { path = "../completion", version = "0.0.0" } | |||
36 | hir = { path = "../hir", version = "0.0.0" } | 36 | hir = { path = "../hir", version = "0.0.0" } |
37 | 37 | ||
38 | [dev-dependencies] | 38 | [dev-dependencies] |
39 | expect-test = "1.0" | 39 | expect-test = "1.1" |
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index 60e0cd4ad..e8999a7f3 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs | |||
@@ -5,10 +5,10 @@ use indexmap::IndexMap; | |||
5 | use hir::Semantics; | 5 | use hir::Semantics; |
6 | use ide_db::call_info::FnCallNode; | 6 | use ide_db::call_info::FnCallNode; |
7 | use ide_db::RootDatabase; | 7 | use ide_db::RootDatabase; |
8 | use syntax::{ast, match_ast, AstNode, TextRange}; | 8 | use syntax::{ast, AstNode, TextRange}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, | 11 | display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | #[derive(Debug, Clone)] | 14 | #[derive(Debug, Clone)] |
@@ -47,28 +47,23 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
47 | 47 | ||
48 | let mut calls = CallLocations::default(); | 48 | let mut calls = CallLocations::default(); |
49 | 49 | ||
50 | for reference in refs.info.references() { | 50 | for (&file_id, references) in refs.info.references().iter() { |
51 | let file_id = reference.file_range.file_id; | ||
52 | let file = sema.parse(file_id); | 51 | let file = sema.parse(file_id); |
53 | let file = file.syntax(); | 52 | let file = file.syntax(); |
54 | let token = file.token_at_offset(reference.file_range.range.start()).next()?; | 53 | for reference in references { |
55 | let token = sema.descend_into_macros(token); | 54 | let token = file.token_at_offset(reference.range.start()).next()?; |
56 | let syntax = token.parent(); | 55 | let token = sema.descend_into_macros(token); |
57 | 56 | let syntax = token.parent(); | |
58 | // This target is the containing function | 57 | |
59 | if let Some(nav) = syntax.ancestors().find_map(|node| { | 58 | // This target is the containing function |
60 | match_ast! { | 59 | if let Some(nav) = syntax.ancestors().find_map(|node| { |
61 | match node { | 60 | let fn_ = ast::Fn::cast(node)?; |
62 | ast::Fn(it) => { | 61 | let def = sema.to_def(&fn_)?; |
63 | let def = sema.to_def(&it)?; | 62 | def.try_to_nav(sema.db) |
64 | Some(def.to_nav(sema.db)) | 63 | }) { |
65 | }, | 64 | let relative_range = reference.range; |
66 | _ => None, | 65 | calls.add(&nav, relative_range); |
67 | } | ||
68 | } | 66 | } |
69 | }) { | ||
70 | let relative_range = reference.file_range.range; | ||
71 | calls.add(&nav, relative_range); | ||
72 | } | 67 | } |
73 | } | 68 | } |
74 | 69 | ||
@@ -91,29 +86,21 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
91 | .filter_map(|node| FnCallNode::with_node_exact(&node)) | 86 | .filter_map(|node| FnCallNode::with_node_exact(&node)) |
92 | .filter_map(|call_node| { | 87 | .filter_map(|call_node| { |
93 | let name_ref = call_node.name_ref()?; | 88 | let name_ref = call_node.name_ref()?; |
94 | 89 | let func_target = match call_node { | |
95 | if let Some(func_target) = match &call_node { | ||
96 | FnCallNode::CallExpr(expr) => { | 90 | FnCallNode::CallExpr(expr) => { |
97 | //FIXME: Type::as_callable is broken | 91 | //FIXME: Type::as_callable is broken |
98 | let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?; | 92 | let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?; |
99 | match callable.kind() { | 93 | match callable.kind() { |
100 | hir::CallableKind::Function(it) => { | 94 | hir::CallableKind::Function(it) => it.try_to_nav(db), |
101 | let fn_def: hir::Function = it.into(); | ||
102 | let nav = fn_def.to_nav(db); | ||
103 | Some(nav) | ||
104 | } | ||
105 | _ => None, | 95 | _ => None, |
106 | } | 96 | } |
107 | } | 97 | } |
108 | FnCallNode::MethodCallExpr(expr) => { | 98 | FnCallNode::MethodCallExpr(expr) => { |
109 | let function = sema.resolve_method_call(&expr)?; | 99 | let function = sema.resolve_method_call(&expr)?; |
110 | Some(function.to_nav(db)) | 100 | function.try_to_nav(db) |
111 | } | 101 | } |
112 | } { | 102 | }?; |
113 | Some((func_target, name_ref.syntax().text_range())) | 103 | Some((func_target, name_ref.syntax().text_range())) |
114 | } else { | ||
115 | None | ||
116 | } | ||
117 | }) | 104 | }) |
118 | .for_each(|(nav, range)| calls.add(&nav, range)); | 105 | .for_each(|(nav, range)| calls.add(&nav, range)); |
119 | 106 | ||
@@ -178,7 +165,7 @@ mod tests { | |||
178 | //- /lib.rs | 165 | //- /lib.rs |
179 | fn callee() {} | 166 | fn callee() {} |
180 | fn caller() { | 167 | fn caller() { |
181 | call<|>ee(); | 168 | call$0ee(); |
182 | } | 169 | } |
183 | "#, | 170 | "#, |
184 | "callee Function FileId(0) 0..14 3..9", | 171 | "callee Function FileId(0) 0..14 3..9", |
@@ -192,7 +179,7 @@ fn caller() { | |||
192 | check_hierarchy( | 179 | check_hierarchy( |
193 | r#" | 180 | r#" |
194 | //- /lib.rs | 181 | //- /lib.rs |
195 | fn call<|>ee() {} | 182 | fn call$0ee() {} |
196 | fn caller() { | 183 | fn caller() { |
197 | callee(); | 184 | callee(); |
198 | } | 185 | } |
@@ -210,7 +197,7 @@ fn caller() { | |||
210 | //- /lib.rs | 197 | //- /lib.rs |
211 | fn callee() {} | 198 | fn callee() {} |
212 | fn caller() { | 199 | fn caller() { |
213 | call<|>ee(); | 200 | call$0ee(); |
214 | callee(); | 201 | callee(); |
215 | } | 202 | } |
216 | "#, | 203 | "#, |
@@ -227,7 +214,7 @@ fn caller() { | |||
227 | //- /lib.rs | 214 | //- /lib.rs |
228 | fn callee() {} | 215 | fn callee() {} |
229 | fn caller1() { | 216 | fn caller1() { |
230 | call<|>ee(); | 217 | call$0ee(); |
231 | } | 218 | } |
232 | 219 | ||
233 | fn caller2() { | 220 | fn caller2() { |
@@ -250,7 +237,7 @@ fn caller2() { | |||
250 | //- /lib.rs cfg:test | 237 | //- /lib.rs cfg:test |
251 | fn callee() {} | 238 | fn callee() {} |
252 | fn caller1() { | 239 | fn caller1() { |
253 | call<|>ee(); | 240 | call$0ee(); |
254 | } | 241 | } |
255 | 242 | ||
256 | #[cfg(test)] | 243 | #[cfg(test)] |
@@ -281,7 +268,7 @@ mod foo; | |||
281 | use foo::callee; | 268 | use foo::callee; |
282 | 269 | ||
283 | fn caller() { | 270 | fn caller() { |
284 | call<|>ee(); | 271 | call$0ee(); |
285 | } | 272 | } |
286 | 273 | ||
287 | //- /foo/mod.rs | 274 | //- /foo/mod.rs |
@@ -299,7 +286,7 @@ pub fn callee() {} | |||
299 | r#" | 286 | r#" |
300 | //- /lib.rs | 287 | //- /lib.rs |
301 | fn callee() {} | 288 | fn callee() {} |
302 | fn call<|>er() { | 289 | fn call$0er() { |
303 | callee(); | 290 | callee(); |
304 | callee(); | 291 | callee(); |
305 | } | 292 | } |
@@ -318,7 +305,7 @@ fn call<|>er() { | |||
318 | mod foo; | 305 | mod foo; |
319 | use foo::callee; | 306 | use foo::callee; |
320 | 307 | ||
321 | fn call<|>er() { | 308 | fn call$0er() { |
322 | callee(); | 309 | callee(); |
323 | } | 310 | } |
324 | 311 | ||
@@ -337,7 +324,7 @@ pub fn callee() {} | |||
337 | r#" | 324 | r#" |
338 | //- /lib.rs | 325 | //- /lib.rs |
339 | fn caller1() { | 326 | fn caller1() { |
340 | call<|>er2(); | 327 | call$0er2(); |
341 | } | 328 | } |
342 | 329 | ||
343 | fn caller2() { | 330 | fn caller2() { |
@@ -365,7 +352,7 @@ fn a() { | |||
365 | fn b() {} | 352 | fn b() {} |
366 | 353 | ||
367 | fn main() { | 354 | fn main() { |
368 | a<|>() | 355 | a$0() |
369 | } | 356 | } |
370 | "#, | 357 | "#, |
371 | "a Function FileId(0) 0..18 3..4", | 358 | "a Function FileId(0) 0..18 3..4", |
@@ -376,7 +363,7 @@ fn main() { | |||
376 | check_hierarchy( | 363 | check_hierarchy( |
377 | r#" | 364 | r#" |
378 | fn a() { | 365 | fn a() { |
379 | b<|>() | 366 | b$0() |
380 | } | 367 | } |
381 | 368 | ||
382 | fn b() {} | 369 | fn b() {} |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 79d126ff2..055c0a79c 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -125,7 +125,7 @@ pub(crate) fn diagnostics( | |||
125 | .on::<hir::diagnostics::MissingFields, _>(|d| { | 125 | .on::<hir::diagnostics::MissingFields, _>(|d| { |
126 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 126 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
127 | }) | 127 | }) |
128 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { | 128 | .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| { |
129 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 129 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
130 | }) | 130 | }) |
131 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 131 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
@@ -305,6 +305,40 @@ mod tests { | |||
305 | } | 305 | } |
306 | 306 | ||
307 | #[test] | 307 | #[test] |
308 | fn test_wrap_return_type_option() { | ||
309 | check_fix( | ||
310 | r#" | ||
311 | //- /main.rs crate:main deps:core | ||
312 | use core::option::Option::{self, Some, None}; | ||
313 | |||
314 | fn div(x: i32, y: i32) -> Option<i32> { | ||
315 | if y == 0 { | ||
316 | return None; | ||
317 | } | ||
318 | x / y$0 | ||
319 | } | ||
320 | //- /core/lib.rs crate:core | ||
321 | pub mod result { | ||
322 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
323 | } | ||
324 | pub mod option { | ||
325 | pub enum Option<T> { Some(T), None } | ||
326 | } | ||
327 | "#, | ||
328 | r#" | ||
329 | use core::option::Option::{self, Some, None}; | ||
330 | |||
331 | fn div(x: i32, y: i32) -> Option<i32> { | ||
332 | if y == 0 { | ||
333 | return None; | ||
334 | } | ||
335 | Some(x / y) | ||
336 | } | ||
337 | "#, | ||
338 | ); | ||
339 | } | ||
340 | |||
341 | #[test] | ||
308 | fn test_wrap_return_type() { | 342 | fn test_wrap_return_type() { |
309 | check_fix( | 343 | check_fix( |
310 | r#" | 344 | r#" |
@@ -315,12 +349,15 @@ fn div(x: i32, y: i32) -> Result<i32, ()> { | |||
315 | if y == 0 { | 349 | if y == 0 { |
316 | return Err(()); | 350 | return Err(()); |
317 | } | 351 | } |
318 | x / y<|> | 352 | x / y$0 |
319 | } | 353 | } |
320 | //- /core/lib.rs crate:core | 354 | //- /core/lib.rs crate:core |
321 | pub mod result { | 355 | pub mod result { |
322 | pub enum Result<T, E> { Ok(T), Err(E) } | 356 | pub enum Result<T, E> { Ok(T), Err(E) } |
323 | } | 357 | } |
358 | pub mod option { | ||
359 | pub enum Option<T> { Some(T), None } | ||
360 | } | ||
324 | "#, | 361 | "#, |
325 | r#" | 362 | r#" |
326 | use core::result::Result::{self, Ok, Err}; | 363 | use core::result::Result::{self, Ok, Err}; |
@@ -346,12 +383,15 @@ fn div<T>(x: T) -> Result<T, i32> { | |||
346 | if x == 0 { | 383 | if x == 0 { |
347 | return Err(7); | 384 | return Err(7); |
348 | } | 385 | } |
349 | <|>x | 386 | $0x |
350 | } | 387 | } |
351 | //- /core/lib.rs crate:core | 388 | //- /core/lib.rs crate:core |
352 | pub mod result { | 389 | pub mod result { |
353 | pub enum Result<T, E> { Ok(T), Err(E) } | 390 | pub enum Result<T, E> { Ok(T), Err(E) } |
354 | } | 391 | } |
392 | pub mod option { | ||
393 | pub enum Option<T> { Some(T), None } | ||
394 | } | ||
355 | "#, | 395 | "#, |
356 | r#" | 396 | r#" |
357 | use core::result::Result::{self, Ok, Err}; | 397 | use core::result::Result::{self, Ok, Err}; |
@@ -379,12 +419,15 @@ fn div(x: i32, y: i32) -> MyResult<i32> { | |||
379 | if y == 0 { | 419 | if y == 0 { |
380 | return Err(()); | 420 | return Err(()); |
381 | } | 421 | } |
382 | x <|>/ y | 422 | x $0/ y |
383 | } | 423 | } |
384 | //- /core/lib.rs crate:core | 424 | //- /core/lib.rs crate:core |
385 | pub mod result { | 425 | pub mod result { |
386 | pub enum Result<T, E> { Ok(T), Err(E) } | 426 | pub enum Result<T, E> { Ok(T), Err(E) } |
387 | } | 427 | } |
428 | pub mod option { | ||
429 | pub enum Option<T> { Some(T), None } | ||
430 | } | ||
388 | "#, | 431 | "#, |
389 | r#" | 432 | r#" |
390 | use core::result::Result::{self, Ok, Err}; | 433 | use core::result::Result::{self, Ok, Err}; |
@@ -414,12 +457,15 @@ fn foo() -> Result<(), i32> { 0 } | |||
414 | pub mod result { | 457 | pub mod result { |
415 | pub enum Result<T, E> { Ok(T), Err(E) } | 458 | pub enum Result<T, E> { Ok(T), Err(E) } |
416 | } | 459 | } |
460 | pub mod option { | ||
461 | pub enum Option<T> { Some(T), None } | ||
462 | } | ||
417 | "#, | 463 | "#, |
418 | ); | 464 | ); |
419 | } | 465 | } |
420 | 466 | ||
421 | #[test] | 467 | #[test] |
422 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { | 468 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { |
423 | check_no_diagnostics( | 469 | check_no_diagnostics( |
424 | r#" | 470 | r#" |
425 | //- /main.rs crate:main deps:core | 471 | //- /main.rs crate:main deps:core |
@@ -433,6 +479,9 @@ fn foo() -> SomeOtherEnum { 0 } | |||
433 | pub mod result { | 479 | pub mod result { |
434 | pub enum Result<T, E> { Ok(T), Err(E) } | 480 | pub enum Result<T, E> { Ok(T), Err(E) } |
435 | } | 481 | } |
482 | pub mod option { | ||
483 | pub enum Option<T> { Some(T), None } | ||
484 | } | ||
436 | "#, | 485 | "#, |
437 | ); | 486 | ); |
438 | } | 487 | } |
@@ -444,7 +493,7 @@ pub mod result { | |||
444 | struct TestStruct { one: i32, two: i64 } | 493 | struct TestStruct { one: i32, two: i64 } |
445 | 494 | ||
446 | fn test_fn() { | 495 | fn test_fn() { |
447 | let s = TestStruct {<|>}; | 496 | let s = TestStruct {$0}; |
448 | } | 497 | } |
449 | "#, | 498 | "#, |
450 | r#" | 499 | r#" |
@@ -464,7 +513,7 @@ fn test_fn() { | |||
464 | struct TestStruct { one: i32 } | 513 | struct TestStruct { one: i32 } |
465 | 514 | ||
466 | impl TestStruct { | 515 | impl TestStruct { |
467 | fn test_fn() { let s = Self {<|>}; } | 516 | fn test_fn() { let s = Self {$0}; } |
468 | } | 517 | } |
469 | "#, | 518 | "#, |
470 | r#" | 519 | r#" |
@@ -487,7 +536,7 @@ enum Expr { | |||
487 | 536 | ||
488 | impl Expr { | 537 | impl Expr { |
489 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { | 538 | fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { |
490 | Expr::Bin {<|> } | 539 | Expr::Bin {$0 } |
491 | } | 540 | } |
492 | } | 541 | } |
493 | "#, | 542 | "#, |
@@ -512,7 +561,7 @@ impl Expr { | |||
512 | struct TestStruct { one: i32, two: i64 } | 561 | struct TestStruct { one: i32, two: i64 } |
513 | 562 | ||
514 | fn test_fn() { | 563 | fn test_fn() { |
515 | let s = TestStruct{ two: 2<|> }; | 564 | let s = TestStruct{ two: 2$0 }; |
516 | } | 565 | } |
517 | "#, | 566 | "#, |
518 | r" | 567 | r" |
@@ -608,7 +657,7 @@ fn here() {} | |||
608 | macro_rules! id { ($($tt:tt)*) => { $($tt)*}; } | 657 | macro_rules! id { ($($tt:tt)*) => { $($tt)*}; } |
609 | 658 | ||
610 | fn main() { | 659 | fn main() { |
611 | let _x = id![Foo { a: <|>42 }]; | 660 | let _x = id![Foo { a: $042 }]; |
612 | } | 661 | } |
613 | 662 | ||
614 | pub struct Foo { pub a: i32, pub b: i32 } | 663 | pub struct Foo { pub a: i32, pub b: i32 } |
@@ -663,7 +712,7 @@ mod a { | |||
663 | check_fix( | 712 | check_fix( |
664 | r" | 713 | r" |
665 | mod b {} | 714 | mod b {} |
666 | use {<|>b}; | 715 | use {$0b}; |
667 | ", | 716 | ", |
668 | r" | 717 | r" |
669 | mod b {} | 718 | mod b {} |
@@ -673,7 +722,7 @@ mod a { | |||
673 | check_fix( | 722 | check_fix( |
674 | r" | 723 | r" |
675 | mod b {} | 724 | mod b {} |
676 | use {b<|>}; | 725 | use {b$0}; |
677 | ", | 726 | ", |
678 | r" | 727 | r" |
679 | mod b {} | 728 | mod b {} |
@@ -683,7 +732,7 @@ mod a { | |||
683 | check_fix( | 732 | check_fix( |
684 | r" | 733 | r" |
685 | mod a { mod c {} } | 734 | mod a { mod c {} } |
686 | use a::{c<|>}; | 735 | use a::{c$0}; |
687 | ", | 736 | ", |
688 | r" | 737 | r" |
689 | mod a { mod c {} } | 738 | mod a { mod c {} } |
@@ -693,7 +742,7 @@ mod a { | |||
693 | check_fix( | 742 | check_fix( |
694 | r" | 743 | r" |
695 | mod a {} | 744 | mod a {} |
696 | use a::{self<|>}; | 745 | use a::{self$0}; |
697 | ", | 746 | ", |
698 | r" | 747 | r" |
699 | mod a {} | 748 | mod a {} |
@@ -703,7 +752,7 @@ mod a { | |||
703 | check_fix( | 752 | check_fix( |
704 | r" | 753 | r" |
705 | mod a { mod c {} mod d { mod e {} } } | 754 | mod a { mod c {} mod d { mod e {} } } |
706 | use a::{c, d::{e<|>}}; | 755 | use a::{c, d::{e$0}}; |
707 | ", | 756 | ", |
708 | r" | 757 | r" |
709 | mod a { mod c {} mod d { mod e {} } } | 758 | mod a { mod c {} mod d { mod e {} } } |
@@ -717,7 +766,7 @@ mod a { | |||
717 | check_fix( | 766 | check_fix( |
718 | r" | 767 | r" |
719 | fn main() { | 768 | fn main() { |
720 | Foo { bar: 3, baz<|>: false}; | 769 | Foo { bar: 3, baz$0: false}; |
721 | } | 770 | } |
722 | struct Foo { | 771 | struct Foo { |
723 | bar: i32 | 772 | bar: i32 |
@@ -743,7 +792,7 @@ struct Foo { | |||
743 | mod foo; | 792 | mod foo; |
744 | 793 | ||
745 | fn main() { | 794 | fn main() { |
746 | foo::Foo { bar: 3, <|>baz: false}; | 795 | foo::Foo { bar: 3, $0baz: false}; |
747 | } | 796 | } |
748 | //- /foo.rs | 797 | //- /foo.rs |
749 | struct Foo { | 798 | struct Foo { |
@@ -777,7 +826,7 @@ struct Foo { | |||
777 | fn test_rename_incorrect_case() { | 826 | fn test_rename_incorrect_case() { |
778 | check_fix( | 827 | check_fix( |
779 | r#" | 828 | r#" |
780 | pub struct test_struct<|> { one: i32 } | 829 | pub struct test_struct$0 { one: i32 } |
781 | 830 | ||
782 | pub fn some_fn(val: test_struct) -> test_struct { | 831 | pub fn some_fn(val: test_struct) -> test_struct { |
783 | test_struct { one: val.one + 1 } | 832 | test_struct { one: val.one + 1 } |
@@ -794,7 +843,7 @@ pub fn some_fn(val: TestStruct) -> TestStruct { | |||
794 | 843 | ||
795 | check_fix( | 844 | check_fix( |
796 | r#" | 845 | r#" |
797 | pub fn some_fn(NonSnakeCase<|>: u8) -> u8 { | 846 | pub fn some_fn(NonSnakeCase$0: u8) -> u8 { |
798 | NonSnakeCase | 847 | NonSnakeCase |
799 | } | 848 | } |
800 | "#, | 849 | "#, |
@@ -807,7 +856,7 @@ pub fn some_fn(non_snake_case: u8) -> u8 { | |||
807 | 856 | ||
808 | check_fix( | 857 | check_fix( |
809 | r#" | 858 | r#" |
810 | pub fn SomeFn<|>(val: u8) -> u8 { | 859 | pub fn SomeFn$0(val: u8) -> u8 { |
811 | if val != 0 { SomeFn(val - 1) } else { val } | 860 | if val != 0 { SomeFn(val - 1) } else { val } |
812 | } | 861 | } |
813 | "#, | 862 | "#, |
@@ -821,7 +870,7 @@ pub fn some_fn(val: u8) -> u8 { | |||
821 | check_fix( | 870 | check_fix( |
822 | r#" | 871 | r#" |
823 | fn some_fn() { | 872 | fn some_fn() { |
824 | let whatAWeird_Formatting<|> = 10; | 873 | let whatAWeird_Formatting$0 = 10; |
825 | another_func(whatAWeird_Formatting); | 874 | another_func(whatAWeird_Formatting); |
826 | } | 875 | } |
827 | "#, | 876 | "#, |
@@ -839,7 +888,7 @@ fn some_fn() { | |||
839 | check_no_diagnostics( | 888 | check_no_diagnostics( |
840 | r#" | 889 | r#" |
841 | fn foo() { | 890 | fn foo() { |
842 | const ANOTHER_ITEM<|>: &str = "some_item"; | 891 | const ANOTHER_ITEM$0: &str = "some_item"; |
843 | } | 892 | } |
844 | "#, | 893 | "#, |
845 | ); | 894 | ); |
@@ -852,7 +901,7 @@ fn foo() { | |||
852 | pub struct TestStruct; | 901 | pub struct TestStruct; |
853 | 902 | ||
854 | impl TestStruct { | 903 | impl TestStruct { |
855 | pub fn SomeFn<|>() -> TestStruct { | 904 | pub fn SomeFn$0() -> TestStruct { |
856 | TestStruct | 905 | TestStruct |
857 | } | 906 | } |
858 | } | 907 | } |
@@ -871,7 +920,7 @@ impl TestStruct { | |||
871 | 920 | ||
872 | #[test] | 921 | #[test] |
873 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { | 922 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { |
874 | let input = r#"fn FOO<|>() {}"#; | 923 | let input = r#"fn FOO$0() {}"#; |
875 | let expected = r#"fn foo() {}"#; | 924 | let expected = r#"fn foo() {}"#; |
876 | 925 | ||
877 | let (analysis, file_position) = fixture::position(input); | 926 | let (analysis, file_position) = fixture::position(input); |
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs index f41bcd619..16c6ea827 100644 --- a/crates/ide/src/diagnostics/field_shorthand.rs +++ b/crates/ide/src/diagnostics/field_shorthand.rs | |||
@@ -120,7 +120,7 @@ fn main() { A { 0: 0 } } | |||
120 | struct A { a: &'static str } | 120 | struct A { a: &'static str } |
121 | fn main() { | 121 | fn main() { |
122 | let a = "haha"; | 122 | let a = "haha"; |
123 | A { a<|>: a } | 123 | A { a$0: a } |
124 | } | 124 | } |
125 | "#, | 125 | "#, |
126 | r#" | 126 | r#" |
@@ -138,7 +138,7 @@ struct A { a: &'static str, b: &'static str } | |||
138 | fn main() { | 138 | fn main() { |
139 | let a = "haha"; | 139 | let a = "haha"; |
140 | let b = "bb"; | 140 | let b = "bb"; |
141 | A { a<|>: a, b } | 141 | A { a$0: a, b } |
142 | } | 142 | } |
143 | "#, | 143 | "#, |
144 | r#" | 144 | r#" |
@@ -171,7 +171,7 @@ fn f(a: A) { let A { 0: 0 } = a; } | |||
171 | r#" | 171 | r#" |
172 | struct A { a: &'static str } | 172 | struct A { a: &'static str } |
173 | fn f(a: A) { | 173 | fn f(a: A) { |
174 | let A { a<|>: a } = a; | 174 | let A { a$0: a } = a; |
175 | } | 175 | } |
176 | "#, | 176 | "#, |
177 | r#" | 177 | r#" |
@@ -186,7 +186,7 @@ fn f(a: A) { | |||
186 | r#" | 186 | r#" |
187 | struct A { a: &'static str, b: &'static str } | 187 | struct A { a: &'static str, b: &'static str } |
188 | fn f(a: A) { | 188 | fn f(a: A) { |
189 | let A { a<|>: a, b } = a; | 189 | let A { a$0: a, b } = a; |
190 | } | 190 | } |
191 | "#, | 191 | "#, |
192 | r#" | 192 | r#" |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index d79f5c170..d7ad88ed5 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use hir::{ | 3 | use hir::{ |
4 | db::AstDatabase, | 4 | db::AstDatabase, |
5 | diagnostics::{ | 5 | diagnostics::{ |
6 | Diagnostic, IncorrectCase, MissingFields, MissingOkInTailExpr, NoSuchField, | 6 | Diagnostic, IncorrectCase, MissingFields, MissingOkOrSomeInTailExpr, NoSuchField, |
7 | RemoveThisSemicolon, UnresolvedModule, | 7 | RemoveThisSemicolon, UnresolvedModule, |
8 | }, | 8 | }, |
9 | HasSource, HirDisplay, InFile, Semantics, VariantDef, | 9 | HasSource, HirDisplay, InFile, Semantics, VariantDef, |
@@ -94,15 +94,17 @@ impl DiagnosticWithFix for MissingFields { | |||
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | impl DiagnosticWithFix for MissingOkInTailExpr { | 97 | impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { |
98 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | 98 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { |
99 | let root = sema.db.parse_or_expand(self.file)?; | 99 | let root = sema.db.parse_or_expand(self.file)?; |
100 | let tail_expr = self.expr.to_node(&root); | 100 | let tail_expr = self.expr.to_node(&root); |
101 | let tail_expr_range = tail_expr.syntax().text_range(); | 101 | let tail_expr_range = tail_expr.syntax().text_range(); |
102 | let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); | 102 | let replacement = format!("{}({})", self.required, tail_expr.syntax()); |
103 | let edit = TextEdit::replace(tail_expr_range, replacement); | ||
103 | let source_change = | 104 | let source_change = |
104 | SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); | 105 | SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); |
105 | Some(Fix::new("Wrap with ok", source_change, tail_expr_range)) | 106 | let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" }; |
107 | Some(Fix::new(name, source_change, tail_expr_range)) | ||
106 | } | 108 | } |
107 | } | 109 | } |
108 | 110 | ||
@@ -156,20 +158,20 @@ fn missing_record_expr_field_fix( | |||
156 | let record_fields = match VariantDef::from(def_id) { | 158 | let record_fields = match VariantDef::from(def_id) { |
157 | VariantDef::Struct(s) => { | 159 | VariantDef::Struct(s) => { |
158 | module = s.module(sema.db); | 160 | module = s.module(sema.db); |
159 | let source = s.source(sema.db); | 161 | let source = s.source(sema.db)?; |
160 | def_file_id = source.file_id; | 162 | def_file_id = source.file_id; |
161 | let fields = source.value.field_list()?; | 163 | let fields = source.value.field_list()?; |
162 | record_field_list(fields)? | 164 | record_field_list(fields)? |
163 | } | 165 | } |
164 | VariantDef::Union(u) => { | 166 | VariantDef::Union(u) => { |
165 | module = u.module(sema.db); | 167 | module = u.module(sema.db); |
166 | let source = u.source(sema.db); | 168 | let source = u.source(sema.db)?; |
167 | def_file_id = source.file_id; | 169 | def_file_id = source.file_id; |
168 | source.value.record_field_list()? | 170 | source.value.record_field_list()? |
169 | } | 171 | } |
170 | VariantDef::Variant(e) => { | 172 | VariantDef::Variant(e) => { |
171 | module = e.module(sema.db); | 173 | module = e.module(sema.db); |
172 | let source = e.source(sema.db); | 174 | let source = e.source(sema.db)?; |
173 | def_file_id = source.file_id; | 175 | def_file_id = source.file_id; |
174 | let fields = source.value.field_list()?; | 176 | let fields = source.value.field_list()?; |
175 | record_field_list(fields)? | 177 | record_field_list(fields)? |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 6431e7d6d..4eecae697 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -24,6 +24,7 @@ pub enum SymbolKind { | |||
24 | Impl, | 24 | Impl, |
25 | Field, | 25 | Field, |
26 | TypeParam, | 26 | TypeParam, |
27 | ConstParam, | ||
27 | LifetimeParam, | 28 | LifetimeParam, |
28 | ValueParam, | 29 | ValueParam, |
29 | SelfParam, | 30 | SelfParam, |
@@ -209,21 +210,12 @@ impl ToNav for FileSymbol { | |||
209 | impl TryToNav for Definition { | 210 | impl TryToNav for Definition { |
210 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 211 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
211 | match self { | 212 | match self { |
212 | Definition::Macro(it) => { | 213 | Definition::Macro(it) => it.try_to_nav(db), |
213 | // FIXME: Currently proc-macro do not have ast-node, | 214 | Definition::Field(it) => it.try_to_nav(db), |
214 | // such that it does not have source | ||
215 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
216 | if it.is_proc_macro() { | ||
217 | return None; | ||
218 | } | ||
219 | Some(it.to_nav(db)) | ||
220 | } | ||
221 | Definition::Field(it) => Some(it.to_nav(db)), | ||
222 | Definition::ModuleDef(it) => it.try_to_nav(db), | 215 | Definition::ModuleDef(it) => it.try_to_nav(db), |
223 | Definition::SelfType(it) => Some(it.to_nav(db)), | 216 | Definition::SelfType(it) => it.try_to_nav(db), |
224 | Definition::Local(it) => Some(it.to_nav(db)), | 217 | Definition::Local(it) => Some(it.to_nav(db)), |
225 | Definition::TypeParam(it) => Some(it.to_nav(db)), | 218 | Definition::GenericParam(it) => it.try_to_nav(db), |
226 | Definition::LifetimeParam(it) => Some(it.to_nav(db)), | ||
227 | Definition::Label(it) => Some(it.to_nav(db)), | 219 | Definition::Label(it) => Some(it.to_nav(db)), |
228 | } | 220 | } |
229 | } | 221 | } |
@@ -231,18 +223,17 @@ impl TryToNav for Definition { | |||
231 | 223 | ||
232 | impl TryToNav for hir::ModuleDef { | 224 | impl TryToNav for hir::ModuleDef { |
233 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 225 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
234 | let res = match self { | 226 | match self { |
235 | hir::ModuleDef::Module(it) => it.to_nav(db), | 227 | hir::ModuleDef::Module(it) => Some(it.to_nav(db)), |
236 | hir::ModuleDef::Function(it) => it.to_nav(db), | 228 | hir::ModuleDef::Function(it) => it.try_to_nav(db), |
237 | hir::ModuleDef::Adt(it) => it.to_nav(db), | 229 | hir::ModuleDef::Adt(it) => it.try_to_nav(db), |
238 | hir::ModuleDef::Variant(it) => it.to_nav(db), | 230 | hir::ModuleDef::Variant(it) => it.try_to_nav(db), |
239 | hir::ModuleDef::Const(it) => it.to_nav(db), | 231 | hir::ModuleDef::Const(it) => it.try_to_nav(db), |
240 | hir::ModuleDef::Static(it) => it.to_nav(db), | 232 | hir::ModuleDef::Static(it) => it.try_to_nav(db), |
241 | hir::ModuleDef::Trait(it) => it.to_nav(db), | 233 | hir::ModuleDef::Trait(it) => it.try_to_nav(db), |
242 | hir::ModuleDef::TypeAlias(it) => it.to_nav(db), | 234 | hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), |
243 | hir::ModuleDef::BuiltinType(_) => return None, | 235 | hir::ModuleDef::BuiltinType(_) => None, |
244 | }; | 236 | } |
245 | Some(res) | ||
246 | } | 237 | } |
247 | } | 238 | } |
248 | 239 | ||
@@ -277,13 +268,13 @@ impl ToNavFromAst for hir::Trait { | |||
277 | const KIND: SymbolKind = SymbolKind::Trait; | 268 | const KIND: SymbolKind = SymbolKind::Trait; |
278 | } | 269 | } |
279 | 270 | ||
280 | impl<D> ToNav for D | 271 | impl<D> TryToNav for D |
281 | where | 272 | where |
282 | D: HasSource + ToNavFromAst + Copy + HasAttrs, | 273 | D: HasSource + ToNavFromAst + Copy + HasAttrs, |
283 | D::Ast: ast::NameOwner + ShortLabel, | 274 | D::Ast: ast::NameOwner + ShortLabel, |
284 | { | 275 | { |
285 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 276 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
286 | let src = self.source(db); | 277 | let src = self.source(db)?; |
287 | let mut res = NavigationTarget::from_named( | 278 | let mut res = NavigationTarget::from_named( |
288 | db, | 279 | db, |
289 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 280 | src.as_ref().map(|it| it as &dyn ast::NameOwner), |
@@ -291,7 +282,7 @@ where | |||
291 | ); | 282 | ); |
292 | res.docs = self.docs(db); | 283 | res.docs = self.docs(db); |
293 | res.description = src.value.short_label(); | 284 | res.description = src.value.short_label(); |
294 | res | 285 | Some(res) |
295 | } | 286 | } |
296 | } | 287 | } |
297 | 288 | ||
@@ -310,9 +301,9 @@ impl ToNav for hir::Module { | |||
310 | } | 301 | } |
311 | } | 302 | } |
312 | 303 | ||
313 | impl ToNav for hir::Impl { | 304 | impl TryToNav for hir::Impl { |
314 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 305 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
315 | let src = self.source(db); | 306 | let src = self.source(db)?; |
316 | let derive_attr = self.is_builtin_derive(db); | 307 | let derive_attr = self.is_builtin_derive(db); |
317 | let frange = if let Some(item) = &derive_attr { | 308 | let frange = if let Some(item) = &derive_attr { |
318 | item.syntax().original_file_range(db) | 309 | item.syntax().original_file_range(db) |
@@ -325,21 +316,21 @@ impl ToNav for hir::Impl { | |||
325 | src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) | 316 | src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) |
326 | }; | 317 | }; |
327 | 318 | ||
328 | NavigationTarget::from_syntax( | 319 | Some(NavigationTarget::from_syntax( |
329 | frange.file_id, | 320 | frange.file_id, |
330 | "impl".into(), | 321 | "impl".into(), |
331 | focus_range, | 322 | focus_range, |
332 | frange.range, | 323 | frange.range, |
333 | SymbolKind::Impl, | 324 | SymbolKind::Impl, |
334 | ) | 325 | )) |
335 | } | 326 | } |
336 | } | 327 | } |
337 | 328 | ||
338 | impl ToNav for hir::Field { | 329 | impl TryToNav for hir::Field { |
339 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 330 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
340 | let src = self.source(db); | 331 | let src = self.source(db)?; |
341 | 332 | ||
342 | match &src.value { | 333 | let field_source = match &src.value { |
343 | FieldSource::Named(it) => { | 334 | FieldSource::Named(it) => { |
344 | let mut res = | 335 | let mut res = |
345 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); | 336 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); |
@@ -357,13 +348,14 @@ impl ToNav for hir::Field { | |||
357 | SymbolKind::Field, | 348 | SymbolKind::Field, |
358 | ) | 349 | ) |
359 | } | 350 | } |
360 | } | 351 | }; |
352 | Some(field_source) | ||
361 | } | 353 | } |
362 | } | 354 | } |
363 | 355 | ||
364 | impl ToNav for hir::MacroDef { | 356 | impl TryToNav for hir::MacroDef { |
365 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 357 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
366 | let src = self.source(db); | 358 | let src = self.source(db)?; |
367 | log::debug!("nav target {:#?}", src.value.syntax()); | 359 | log::debug!("nav target {:#?}", src.value.syntax()); |
368 | let mut res = NavigationTarget::from_named( | 360 | let mut res = NavigationTarget::from_named( |
369 | db, | 361 | db, |
@@ -371,26 +363,36 @@ impl ToNav for hir::MacroDef { | |||
371 | SymbolKind::Macro, | 363 | SymbolKind::Macro, |
372 | ); | 364 | ); |
373 | res.docs = self.docs(db); | 365 | res.docs = self.docs(db); |
374 | res | 366 | Some(res) |
375 | } | 367 | } |
376 | } | 368 | } |
377 | 369 | ||
378 | impl ToNav for hir::Adt { | 370 | impl TryToNav for hir::Adt { |
379 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 371 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
380 | match self { | 372 | match self { |
381 | hir::Adt::Struct(it) => it.to_nav(db), | 373 | hir::Adt::Struct(it) => it.try_to_nav(db), |
382 | hir::Adt::Union(it) => it.to_nav(db), | 374 | hir::Adt::Union(it) => it.try_to_nav(db), |
383 | hir::Adt::Enum(it) => it.to_nav(db), | 375 | hir::Adt::Enum(it) => it.try_to_nav(db), |
384 | } | 376 | } |
385 | } | 377 | } |
386 | } | 378 | } |
387 | 379 | ||
388 | impl ToNav for hir::AssocItem { | 380 | impl TryToNav for hir::AssocItem { |
389 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 381 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
390 | match self { | 382 | match self { |
391 | AssocItem::Function(it) => it.to_nav(db), | 383 | AssocItem::Function(it) => it.try_to_nav(db), |
392 | AssocItem::Const(it) => it.to_nav(db), | 384 | AssocItem::Const(it) => it.try_to_nav(db), |
393 | AssocItem::TypeAlias(it) => it.to_nav(db), | 385 | AssocItem::TypeAlias(it) => it.try_to_nav(db), |
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | impl TryToNav for hir::GenericParam { | ||
391 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | ||
392 | match self { | ||
393 | hir::GenericParam::TypeParam(it) => it.try_to_nav(db), | ||
394 | hir::GenericParam::ConstParam(it) => it.try_to_nav(db), | ||
395 | hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db), | ||
394 | } | 396 | } |
395 | } | 397 | } |
396 | } | 398 | } |
@@ -444,9 +446,9 @@ impl ToNav for hir::Label { | |||
444 | } | 446 | } |
445 | } | 447 | } |
446 | 448 | ||
447 | impl ToNav for hir::TypeParam { | 449 | impl TryToNav for hir::TypeParam { |
448 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 450 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
449 | let src = self.source(db); | 451 | let src = self.source(db)?; |
450 | let full_range = match &src.value { | 452 | let full_range = match &src.value { |
451 | Either::Left(it) => it.syntax().text_range(), | 453 | Either::Left(it) => it.syntax().text_range(), |
452 | Either::Right(it) => it.syntax().text_range(), | 454 | Either::Right(it) => it.syntax().text_range(), |
@@ -455,7 +457,7 @@ impl ToNav for hir::TypeParam { | |||
455 | Either::Left(_) => None, | 457 | Either::Left(_) => None, |
456 | Either::Right(it) => it.name().map(|it| it.syntax().text_range()), | 458 | Either::Right(it) => it.name().map(|it| it.syntax().text_range()), |
457 | }; | 459 | }; |
458 | NavigationTarget { | 460 | Some(NavigationTarget { |
459 | file_id: src.file_id.original_file(db), | 461 | file_id: src.file_id.original_file(db), |
460 | name: self.name(db).to_string().into(), | 462 | name: self.name(db).to_string().into(), |
461 | kind: Some(SymbolKind::TypeParam), | 463 | kind: Some(SymbolKind::TypeParam), |
@@ -464,15 +466,15 @@ impl ToNav for hir::TypeParam { | |||
464 | container_name: None, | 466 | container_name: None, |
465 | description: None, | 467 | description: None, |
466 | docs: None, | 468 | docs: None, |
467 | } | 469 | }) |
468 | } | 470 | } |
469 | } | 471 | } |
470 | 472 | ||
471 | impl ToNav for hir::LifetimeParam { | 473 | impl TryToNav for hir::LifetimeParam { |
472 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 474 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
473 | let src = self.source(db); | 475 | let src = self.source(db)?; |
474 | let full_range = src.value.syntax().text_range(); | 476 | let full_range = src.value.syntax().text_range(); |
475 | NavigationTarget { | 477 | Some(NavigationTarget { |
476 | file_id: src.file_id.original_file(db), | 478 | file_id: src.file_id.original_file(db), |
477 | name: self.name(db).to_string().into(), | 479 | name: self.name(db).to_string().into(), |
478 | kind: Some(SymbolKind::LifetimeParam), | 480 | kind: Some(SymbolKind::LifetimeParam), |
@@ -481,7 +483,24 @@ impl ToNav for hir::LifetimeParam { | |||
481 | container_name: None, | 483 | container_name: None, |
482 | description: None, | 484 | description: None, |
483 | docs: None, | 485 | docs: None, |
484 | } | 486 | }) |
487 | } | ||
488 | } | ||
489 | |||
490 | impl TryToNav for hir::ConstParam { | ||
491 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | ||
492 | let src = self.source(db)?; | ||
493 | let full_range = src.value.syntax().text_range(); | ||
494 | Some(NavigationTarget { | ||
495 | file_id: src.file_id.original_file(db), | ||
496 | name: self.name(db).to_string().into(), | ||
497 | kind: Some(SymbolKind::ConstParam), | ||
498 | full_range, | ||
499 | focus_range: src.value.name().map(|n| n.syntax().text_range()), | ||
500 | container_name: None, | ||
501 | description: None, | ||
502 | docs: None, | ||
503 | }) | ||
485 | } | 504 | } |
486 | } | 505 | } |
487 | 506 | ||
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs index ea49d9f97..990f740b8 100644 --- a/crates/ide/src/display/short_label.rs +++ b/crates/ide/src/display/short_label.rs | |||
@@ -87,6 +87,17 @@ impl ShortLabel for ast::Variant { | |||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | impl ShortLabel for ast::ConstParam { | ||
91 | fn short_label(&self) -> Option<String> { | ||
92 | let mut buf = "const ".to_owned(); | ||
93 | buf.push_str(self.name()?.text().as_str()); | ||
94 | if let Some(type_ref) = self.ty() { | ||
95 | format_to!(buf, ": {}", type_ref.syntax()); | ||
96 | } | ||
97 | Some(buf) | ||
98 | } | ||
99 | } | ||
100 | |||
90 | fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> | 101 | fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> |
91 | where | 102 | where |
92 | T: NameOwner + VisibilityOwner, | 103 | T: NameOwner + VisibilityOwner, |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index e10516f43..de10406bc 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Resolves and rewrites links in markdown documentation. | 1 | //! Resolves and rewrites links in markdown documentation. |
2 | 2 | ||
3 | use std::{convert::TryFrom, iter::once}; | 3 | use std::{convert::TryFrom, iter::once, ops::Range}; |
4 | 4 | ||
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; | 6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; |
@@ -39,7 +39,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi | |||
39 | if target.contains("://") { | 39 | if target.contains("://") { |
40 | (target.to_string(), title.to_string()) | 40 | (target.to_string(), title.to_string()) |
41 | } else { | 41 | } else { |
42 | // Two posibilities: | 42 | // Two possibilities: |
43 | // * path-based links: `../../module/struct.MyStruct.html` | 43 | // * path-based links: `../../module/struct.MyStruct.html` |
44 | // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` | 44 | // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` |
45 | if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) { | 45 | if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) { |
@@ -61,6 +61,30 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi | |||
61 | out | 61 | out |
62 | } | 62 | } |
63 | 63 | ||
64 | pub(crate) fn extract_definitions_from_markdown( | ||
65 | markdown: &str, | ||
66 | ) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> { | ||
67 | let mut res = vec![]; | ||
68 | let mut cb = |link: BrokenLink| { | ||
69 | Some(( | ||
70 | /*url*/ link.reference.to_owned().into(), | ||
71 | /*title*/ link.reference.to_owned().into(), | ||
72 | )) | ||
73 | }; | ||
74 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); | ||
75 | for (event, range) in doc.into_offset_iter() { | ||
76 | match event { | ||
77 | Event::Start(Tag::Link(_link_type, ref target, ref title)) => { | ||
78 | let link = if target.is_empty() { title } else { target }; | ||
79 | let (link, ns) = parse_link(link); | ||
80 | res.push((link.to_string(), ns, range)); | ||
81 | } | ||
82 | _ => {} | ||
83 | } | ||
84 | } | ||
85 | res | ||
86 | } | ||
87 | |||
64 | /// Remove all links in markdown documentation. | 88 | /// Remove all links in markdown documentation. |
65 | pub(crate) fn remove_links(markdown: &str) -> String { | 89 | pub(crate) fn remove_links(markdown: &str) -> String { |
66 | let mut drop_link = false; | 90 | let mut drop_link = false; |
@@ -192,8 +216,7 @@ fn rewrite_intra_doc_link( | |||
192 | Definition::Field(it) => it.resolve_doc_path(db, link, ns), | 216 | Definition::Field(it) => it.resolve_doc_path(db, link, ns), |
193 | Definition::SelfType(_) | 217 | Definition::SelfType(_) |
194 | | Definition::Local(_) | 218 | | Definition::Local(_) |
195 | | Definition::TypeParam(_) | 219 | | Definition::GenericParam(_) |
196 | | Definition::LifetimeParam(_) | ||
197 | | Definition::Label(_) => return None, | 220 | | Definition::Label(_) => return None, |
198 | }?; | 221 | }?; |
199 | let krate = resolved.module(db)?.krate(); | 222 | let krate = resolved.module(db)?.krate(); |
@@ -419,7 +442,7 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem) | |||
419 | function.as_assoc_item(db).map(|assoc| assoc.container(db)), | 442 | function.as_assoc_item(db).map(|assoc| assoc.container(db)), |
420 | Some(AssocItemContainer::Trait(..)) | 443 | Some(AssocItemContainer::Trait(..)) |
421 | ); | 444 | ); |
422 | // This distinction may get more complicated when specialisation is available. | 445 | // This distinction may get more complicated when specialization is available. |
423 | // Rustdoc makes this decision based on whether a method 'has defaultness'. | 446 | // Rustdoc makes this decision based on whether a method 'has defaultness'. |
424 | // Currently this is only the case for provided trait methods. | 447 | // Currently this is only the case for provided trait methods. |
425 | if is_trait_method && !function.has_body(db) { | 448 | if is_trait_method && !function.has_body(db) { |
@@ -463,7 +486,7 @@ mod tests { | |||
463 | fn test_doc_url_struct() { | 486 | fn test_doc_url_struct() { |
464 | check( | 487 | check( |
465 | r#" | 488 | r#" |
466 | pub struct Fo<|>o; | 489 | pub struct Fo$0o; |
467 | "#, | 490 | "#, |
468 | expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]], | 491 | expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]], |
469 | ); | 492 | ); |
@@ -473,7 +496,7 @@ pub struct Fo<|>o; | |||
473 | fn test_doc_url_fn() { | 496 | fn test_doc_url_fn() { |
474 | check( | 497 | check( |
475 | r#" | 498 | r#" |
476 | pub fn fo<|>o() {} | 499 | pub fn fo$0o() {} |
477 | "#, | 500 | "#, |
478 | expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]], | 501 | expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]], |
479 | ); | 502 | ); |
@@ -486,7 +509,7 @@ pub fn fo<|>o() {} | |||
486 | pub struct Foo; | 509 | pub struct Foo; |
487 | 510 | ||
488 | impl Foo { | 511 | impl Foo { |
489 | pub fn met<|>hod() {} | 512 | pub fn met$0hod() {} |
490 | } | 513 | } |
491 | 514 | ||
492 | "#, | 515 | "#, |
@@ -499,7 +522,7 @@ impl Foo { | |||
499 | check( | 522 | check( |
500 | r#" | 523 | r#" |
501 | pub trait Bar { | 524 | pub trait Bar { |
502 | fn met<|>hod() {} | 525 | fn met$0hod() {} |
503 | } | 526 | } |
504 | 527 | ||
505 | "#, | 528 | "#, |
@@ -512,7 +535,7 @@ pub trait Bar { | |||
512 | check( | 535 | check( |
513 | r#" | 536 | r#" |
514 | pub trait Foo { | 537 | pub trait Foo { |
515 | fn met<|>hod(); | 538 | fn met$0hod(); |
516 | } | 539 | } |
517 | 540 | ||
518 | "#, | 541 | "#, |
@@ -525,7 +548,7 @@ pub trait Foo { | |||
525 | check( | 548 | check( |
526 | r#" | 549 | r#" |
527 | pub struct Foo { | 550 | pub struct Foo { |
528 | pub fie<|>ld: () | 551 | pub fie$0ld: () |
529 | } | 552 | } |
530 | 553 | ||
531 | "#, | 554 | "#, |
@@ -538,7 +561,7 @@ pub struct Foo { | |||
538 | check( | 561 | check( |
539 | r#" | 562 | r#" |
540 | pub mod foo { | 563 | pub mod foo { |
541 | pub mod ba<|>r {} | 564 | pub mod ba$0r {} |
542 | } | 565 | } |
543 | "#, | 566 | "#, |
544 | expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]], | 567 | expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]], |
@@ -563,7 +586,7 @@ pub mod wrapper { | |||
563 | } | 586 | } |
564 | 587 | ||
565 | fn foo() { | 588 | fn foo() { |
566 | let bar: wrapper::It<|>em; | 589 | let bar: wrapper::It$0em; |
567 | } | 590 | } |
568 | "#, | 591 | "#, |
569 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], | 592 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], |
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 8d75e0f05..ffb3a6f7d 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs | |||
@@ -144,7 +144,7 @@ macro_rules! foo { | |||
144 | macro_rules! baz { | 144 | macro_rules! baz { |
145 | () => { foo!(); } | 145 | () => { foo!(); } |
146 | } | 146 | } |
147 | f<|>oo!(); | 147 | f$0oo!(); |
148 | "#, | 148 | "#, |
149 | expect![[r#" | 149 | expect![[r#" |
150 | foo | 150 | foo |
@@ -165,7 +165,7 @@ macro_rules! foo { | |||
165 | } | 165 | } |
166 | } | 166 | } |
167 | } | 167 | } |
168 | f<|>oo!(); | 168 | f$0oo!(); |
169 | "#, | 169 | "#, |
170 | expect![[r#" | 170 | expect![[r#" |
171 | foo | 171 | foo |
@@ -192,7 +192,7 @@ macro_rules! match_ast { | |||
192 | } | 192 | } |
193 | 193 | ||
194 | fn main() { | 194 | fn main() { |
195 | mat<|>ch_ast! { | 195 | mat$0ch_ast! { |
196 | match container { | 196 | match container { |
197 | ast::TraitDef(it) => {}, | 197 | ast::TraitDef(it) => {}, |
198 | ast::ImplDef(it) => {}, | 198 | ast::ImplDef(it) => {}, |
@@ -226,7 +226,7 @@ macro_rules! match_ast { | |||
226 | 226 | ||
227 | fn main() { | 227 | fn main() { |
228 | let p = f(|it| { | 228 | let p = f(|it| { |
229 | let res = mat<|>ch_ast! { match c {}}; | 229 | let res = mat$0ch_ast! { match c {}}; |
230 | Some(res) | 230 | Some(res) |
231 | })?; | 231 | })?; |
232 | } | 232 | } |
@@ -250,7 +250,7 @@ macro_rules! foo { | |||
250 | } | 250 | } |
251 | 251 | ||
252 | fn main() { | 252 | fn main() { |
253 | let res = fo<|>o!(); | 253 | let res = fo$0o!(); |
254 | } | 254 | } |
255 | "#, | 255 | "#, |
256 | expect![[r#" | 256 | expect![[r#" |
@@ -272,7 +272,7 @@ macro_rules! foo { | |||
272 | } | 272 | } |
273 | 273 | ||
274 | fn main() { | 274 | fn main() { |
275 | let res = fo<|>o!(); | 275 | let res = fo$0o!(); |
276 | } | 276 | } |
277 | "#, | 277 | "#, |
278 | expect![[r#" | 278 | expect![[r#" |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 6f3022dfd..56418c960 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -334,29 +334,29 @@ mod tests { | |||
334 | 334 | ||
335 | #[test] | 335 | #[test] |
336 | fn test_extend_selection_arith() { | 336 | fn test_extend_selection_arith() { |
337 | do_check(r#"fn foo() { <|>1 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); | 337 | do_check(r#"fn foo() { $01 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); |
338 | } | 338 | } |
339 | 339 | ||
340 | #[test] | 340 | #[test] |
341 | fn test_extend_selection_list() { | 341 | fn test_extend_selection_list() { |
342 | do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]); | 342 | do_check(r#"fn foo($0x: i32) {}"#, &["x", "x: i32"]); |
343 | do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); | 343 | do_check(r#"fn foo($0x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); |
344 | do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]); | 344 | do_check(r#"fn foo($0x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]); |
345 | do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]); | 345 | do_check(r#"fn foo(x: i32, $0y: i32) {}"#, &["y", "y: i32", ", y: i32"]); |
346 | do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]); | 346 | do_check(r#"fn foo(x: i32, $0y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]); |
347 | do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]); | 347 | do_check(r#"fn foo(x: i32,$0y: i32) {}"#, &["y", "y: i32", ",y: i32"]); |
348 | 348 | ||
349 | do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]); | 349 | do_check(r#"const FOO: [usize; 2] = [ 22$0 , 33];"#, &["22", "22 , "]); |
350 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); | 350 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0];"#, &["33", ", 33"]); |
351 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]); | 351 | do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0 ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]); |
352 | 352 | ||
353 | do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]); | 353 | do_check(r#"fn main() { (1, 2$0) }"#, &["2", ", 2", "(1, 2)"]); |
354 | 354 | ||
355 | do_check( | 355 | do_check( |
356 | r#" | 356 | r#" |
357 | const FOO: [usize; 2] = [ | 357 | const FOO: [usize; 2] = [ |
358 | 22, | 358 | 22, |
359 | <|>33, | 359 | $033, |
360 | ]"#, | 360 | ]"#, |
361 | &["33", "33,"], | 361 | &["33", "33,"], |
362 | ); | 362 | ); |
@@ -365,7 +365,7 @@ const FOO: [usize; 2] = [ | |||
365 | r#" | 365 | r#" |
366 | const FOO: [usize; 2] = [ | 366 | const FOO: [usize; 2] = [ |
367 | 22 | 367 | 22 |
368 | , 33<|>, | 368 | , 33$0, |
369 | ]"#, | 369 | ]"#, |
370 | &["33", "33,"], | 370 | &["33", "33,"], |
371 | ); | 371 | ); |
@@ -376,7 +376,7 @@ const FOO: [usize; 2] = [ | |||
376 | do_check( | 376 | do_check( |
377 | r#" | 377 | r#" |
378 | impl S { | 378 | impl S { |
379 | <|> fn foo() { | 379 | $0 fn foo() { |
380 | 380 | ||
381 | } | 381 | } |
382 | }"#, | 382 | }"#, |
@@ -393,7 +393,7 @@ struct A; | |||
393 | /// bla | 393 | /// bla |
394 | /// bla | 394 | /// bla |
395 | struct B { | 395 | struct B { |
396 | <|> | 396 | $0 |
397 | } | 397 | } |
398 | "#, | 398 | "#, |
399 | &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"], | 399 | &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"], |
@@ -407,7 +407,7 @@ struct B { | |||
407 | fn bar(){} | 407 | fn bar(){} |
408 | 408 | ||
409 | // fn foo() { | 409 | // fn foo() { |
410 | // 1 + <|>1 | 410 | // 1 + $01 |
411 | // } | 411 | // } |
412 | 412 | ||
413 | // fn foo(){} | 413 | // fn foo(){} |
@@ -419,7 +419,7 @@ fn bar(){} | |||
419 | r#" | 419 | r#" |
420 | // #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 420 | // #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
421 | // pub enum Direction { | 421 | // pub enum Direction { |
422 | // <|> Next, | 422 | // $0 Next, |
423 | // Prev | 423 | // Prev |
424 | // } | 424 | // } |
425 | "#, | 425 | "#, |
@@ -433,27 +433,27 @@ fn bar(){} | |||
433 | r#" | 433 | r#" |
434 | /* | 434 | /* |
435 | foo | 435 | foo |
436 | _bar1<|>*/ | 436 | _bar1$0*/ |
437 | "#, | 437 | "#, |
438 | &["_bar1", "/*\nfoo\n_bar1*/"], | 438 | &["_bar1", "/*\nfoo\n_bar1*/"], |
439 | ); | 439 | ); |
440 | 440 | ||
441 | do_check(r#"//!<|>foo_2 bar"#, &["foo_2", "//!foo_2 bar"]); | 441 | do_check(r#"//!$0foo_2 bar"#, &["foo_2", "//!foo_2 bar"]); |
442 | 442 | ||
443 | do_check(r#"/<|>/foo bar"#, &["//foo bar"]); | 443 | do_check(r#"/$0/foo bar"#, &["//foo bar"]); |
444 | } | 444 | } |
445 | 445 | ||
446 | #[test] | 446 | #[test] |
447 | fn test_extend_selection_prefer_idents() { | 447 | fn test_extend_selection_prefer_idents() { |
448 | do_check( | 448 | do_check( |
449 | r#" | 449 | r#" |
450 | fn main() { foo<|>+bar;} | 450 | fn main() { foo$0+bar;} |
451 | "#, | 451 | "#, |
452 | &["foo", "foo+bar"], | 452 | &["foo", "foo+bar"], |
453 | ); | 453 | ); |
454 | do_check( | 454 | do_check( |
455 | r#" | 455 | r#" |
456 | fn main() { foo+<|>bar;} | 456 | fn main() { foo+$0bar;} |
457 | "#, | 457 | "#, |
458 | &["bar", "foo+bar"], | 458 | &["bar", "foo+bar"], |
459 | ); | 459 | ); |
@@ -461,18 +461,18 @@ fn main() { foo+<|>bar;} | |||
461 | 461 | ||
462 | #[test] | 462 | #[test] |
463 | fn test_extend_selection_prefer_lifetimes() { | 463 | fn test_extend_selection_prefer_lifetimes() { |
464 | do_check(r#"fn foo<<|>'a>() {}"#, &["'a", "<'a>"]); | 464 | do_check(r#"fn foo<$0'a>() {}"#, &["'a", "<'a>"]); |
465 | do_check(r#"fn foo<'a<|>>() {}"#, &["'a", "<'a>"]); | 465 | do_check(r#"fn foo<'a$0>() {}"#, &["'a", "<'a>"]); |
466 | } | 466 | } |
467 | 467 | ||
468 | #[test] | 468 | #[test] |
469 | fn test_extend_selection_select_first_word() { | 469 | fn test_extend_selection_select_first_word() { |
470 | do_check(r#"// foo bar b<|>az quxx"#, &["baz", "// foo bar baz quxx"]); | 470 | do_check(r#"// foo bar b$0az quxx"#, &["baz", "// foo bar baz quxx"]); |
471 | do_check( | 471 | do_check( |
472 | r#" | 472 | r#" |
473 | impl S { | 473 | impl S { |
474 | fn foo() { | 474 | fn foo() { |
475 | // hel<|>lo world | 475 | // hel$0lo world |
476 | } | 476 | } |
477 | } | 477 | } |
478 | "#, | 478 | "#, |
@@ -486,7 +486,7 @@ fn foo() { | |||
486 | r#" | 486 | r#" |
487 | fn bar(){} | 487 | fn bar(){} |
488 | 488 | ||
489 | " fn f<|>oo() {" | 489 | " fn f$0oo() {" |
490 | "#, | 490 | "#, |
491 | &["foo", "\" fn foo() {\""], | 491 | &["foo", "\" fn foo() {\""], |
492 | ); | 492 | ); |
@@ -499,7 +499,7 @@ fn bar(){} | |||
499 | fn foo<R>() | 499 | fn foo<R>() |
500 | where | 500 | where |
501 | R: req::Request + 'static, | 501 | R: req::Request + 'static, |
502 | R::Params: DeserializeOwned<|> + panic::UnwindSafe + 'static, | 502 | R::Params: DeserializeOwned$0 + panic::UnwindSafe + 'static, |
503 | R::Result: Serialize + 'static, | 503 | R::Result: Serialize + 'static, |
504 | "#, | 504 | "#, |
505 | &[ | 505 | &[ |
@@ -510,26 +510,26 @@ fn foo<R>() | |||
510 | "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,", | 510 | "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,", |
511 | ], | 511 | ], |
512 | ); | 512 | ); |
513 | do_check(r#"fn foo<T>() where T: <|>Copy"#, &["Copy"]); | 513 | do_check(r#"fn foo<T>() where T: $0Copy"#, &["Copy"]); |
514 | do_check(r#"fn foo<T>() where T: <|>Copy + Display"#, &["Copy", "Copy + "]); | 514 | do_check(r#"fn foo<T>() where T: $0Copy + Display"#, &["Copy", "Copy + "]); |
515 | do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]); | 515 | do_check(r#"fn foo<T>() where T: $0Copy +Display"#, &["Copy", "Copy +"]); |
516 | do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]); | 516 | do_check(r#"fn foo<T>() where T: $0Copy+Display"#, &["Copy", "Copy+"]); |
517 | do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]); | 517 | do_check(r#"fn foo<T>() where T: Copy + $0Display"#, &["Display", "+ Display"]); |
518 | do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "Display + "]); | 518 | do_check(r#"fn foo<T>() where T: Copy + $0Display + Sync"#, &["Display", "Display + "]); |
519 | do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]); | 519 | do_check(r#"fn foo<T>() where T: Copy +$0Display"#, &["Display", "+Display"]); |
520 | } | 520 | } |
521 | 521 | ||
522 | #[test] | 522 | #[test] |
523 | fn test_extend_trait_bounds_list_inline() { | 523 | fn test_extend_trait_bounds_list_inline() { |
524 | do_check(r#"fn foo<T: <|>Copy>() {}"#, &["Copy"]); | 524 | do_check(r#"fn foo<T: $0Copy>() {}"#, &["Copy"]); |
525 | do_check(r#"fn foo<T: <|>Copy + Display>() {}"#, &["Copy", "Copy + "]); | 525 | do_check(r#"fn foo<T: $0Copy + Display>() {}"#, &["Copy", "Copy + "]); |
526 | do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]); | 526 | do_check(r#"fn foo<T: $0Copy +Display>() {}"#, &["Copy", "Copy +"]); |
527 | do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]); | 527 | do_check(r#"fn foo<T: $0Copy+Display>() {}"#, &["Copy", "Copy+"]); |
528 | do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]); | 528 | do_check(r#"fn foo<T: Copy + $0Display>() {}"#, &["Display", "+ Display"]); |
529 | do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "Display + "]); | 529 | do_check(r#"fn foo<T: Copy + $0Display + Sync>() {}"#, &["Display", "Display + "]); |
530 | do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]); | 530 | do_check(r#"fn foo<T: Copy +$0Display>() {}"#, &["Display", "+Display"]); |
531 | do_check( | 531 | do_check( |
532 | r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#, | 532 | r#"fn foo<T: Copy$0 + Display, U: Copy>() {}"#, |
533 | &[ | 533 | &[ |
534 | "Copy", | 534 | "Copy", |
535 | "Copy + ", | 535 | "Copy + ", |
@@ -544,19 +544,19 @@ fn foo<R>() | |||
544 | #[test] | 544 | #[test] |
545 | fn test_extend_selection_on_tuple_in_type() { | 545 | fn test_extend_selection_on_tuple_in_type() { |
546 | do_check( | 546 | do_check( |
547 | r#"fn main() { let _: (krate, <|>_crate_def_map, module_id) = (); }"#, | 547 | r#"fn main() { let _: (krate, $0_crate_def_map, module_id) = (); }"#, |
548 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], | 548 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], |
549 | ); | 549 | ); |
550 | // white space variations | 550 | // white space variations |
551 | do_check( | 551 | do_check( |
552 | r#"fn main() { let _: (krate,<|>_crate_def_map,module_id) = (); }"#, | 552 | r#"fn main() { let _: (krate,$0_crate_def_map,module_id) = (); }"#, |
553 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], | 553 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], |
554 | ); | 554 | ); |
555 | do_check( | 555 | do_check( |
556 | r#" | 556 | r#" |
557 | fn main() { let _: ( | 557 | fn main() { let _: ( |
558 | krate, | 558 | krate, |
559 | _crate<|>_def_map, | 559 | _crate$0_def_map, |
560 | module_id | 560 | module_id |
561 | ) = (); }"#, | 561 | ) = (); }"#, |
562 | &[ | 562 | &[ |
@@ -570,19 +570,19 @@ fn main() { let _: ( | |||
570 | #[test] | 570 | #[test] |
571 | fn test_extend_selection_on_tuple_in_rvalue() { | 571 | fn test_extend_selection_on_tuple_in_rvalue() { |
572 | do_check( | 572 | do_check( |
573 | r#"fn main() { let var = (krate, _crate_def_map<|>, module_id); }"#, | 573 | r#"fn main() { let var = (krate, _crate_def_map$0, module_id); }"#, |
574 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], | 574 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], |
575 | ); | 575 | ); |
576 | // white space variations | 576 | // white space variations |
577 | do_check( | 577 | do_check( |
578 | r#"fn main() { let var = (krate,_crate<|>_def_map,module_id); }"#, | 578 | r#"fn main() { let var = (krate,_crate$0_def_map,module_id); }"#, |
579 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], | 579 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], |
580 | ); | 580 | ); |
581 | do_check( | 581 | do_check( |
582 | r#" | 582 | r#" |
583 | fn main() { let var = ( | 583 | fn main() { let var = ( |
584 | krate, | 584 | krate, |
585 | _crate_def_map<|>, | 585 | _crate_def_map$0, |
586 | module_id | 586 | module_id |
587 | ); }"#, | 587 | ); }"#, |
588 | &[ | 588 | &[ |
@@ -596,19 +596,19 @@ fn main() { let var = ( | |||
596 | #[test] | 596 | #[test] |
597 | fn test_extend_selection_on_tuple_pat() { | 597 | fn test_extend_selection_on_tuple_pat() { |
598 | do_check( | 598 | do_check( |
599 | r#"fn main() { let (krate, _crate_def_map<|>, module_id) = var; }"#, | 599 | r#"fn main() { let (krate, _crate_def_map$0, module_id) = var; }"#, |
600 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], | 600 | &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], |
601 | ); | 601 | ); |
602 | // white space variations | 602 | // white space variations |
603 | do_check( | 603 | do_check( |
604 | r#"fn main() { let (krate,_crate<|>_def_map,module_id) = var; }"#, | 604 | r#"fn main() { let (krate,_crate$0_def_map,module_id) = var; }"#, |
605 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], | 605 | &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], |
606 | ); | 606 | ); |
607 | do_check( | 607 | do_check( |
608 | r#" | 608 | r#" |
609 | fn main() { let ( | 609 | fn main() { let ( |
610 | krate, | 610 | krate, |
611 | _crate_def_map<|>, | 611 | _crate_def_map$0, |
612 | module_id | 612 | module_id |
613 | ) = var; }"#, | 613 | ) = var; }"#, |
614 | &[ | 614 | &[ |
@@ -623,7 +623,7 @@ fn main() { let ( | |||
623 | fn extend_selection_inside_macros() { | 623 | fn extend_selection_inside_macros() { |
624 | do_check( | 624 | do_check( |
625 | r#"macro_rules! foo { ($item:item) => {$item} } | 625 | r#"macro_rules! foo { ($item:item) => {$item} } |
626 | foo!{fn hello(na<|>me:usize){}}"#, | 626 | foo!{fn hello(na$0me:usize){}}"#, |
627 | &[ | 627 | &[ |
628 | "name", | 628 | "name", |
629 | "name:usize", | 629 | "name:usize", |
@@ -640,7 +640,7 @@ fn main() { let ( | |||
640 | do_check( | 640 | do_check( |
641 | r#" macro_rules! foo2 { ($item:item) => {$item} } | 641 | r#" macro_rules! foo2 { ($item:item) => {$item} } |
642 | macro_rules! foo { ($item:item) => {foo2!($item);} } | 642 | macro_rules! foo { ($item:item) => {foo2!($item);} } |
643 | foo!{fn hello(na<|>me:usize){}}"#, | 643 | foo!{fn hello(na$0me:usize){}}"#, |
644 | &[ | 644 | &[ |
645 | "name", | 645 | "name", |
646 | "name:usize", | 646 | "name:usize", |
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs index eb57f9224..cc8218885 100644 --- a/crates/ide/src/fixture.rs +++ b/crates/ide/src/fixture.rs | |||
@@ -20,12 +20,12 @@ pub(crate) fn files(ra_fixture: &str) -> (Analysis, Vec<FileId>) { | |||
20 | (host.analysis(), change_fixture.files) | 20 | (host.analysis(), change_fixture.files) |
21 | } | 21 | } |
22 | 22 | ||
23 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 23 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
24 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { | 24 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { |
25 | let mut host = AnalysisHost::default(); | 25 | let mut host = AnalysisHost::default(); |
26 | let change_fixture = ChangeFixture::parse(ra_fixture); | 26 | let change_fixture = ChangeFixture::parse(ra_fixture); |
27 | host.db.apply_change(change_fixture.change); | 27 | host.db.apply_change(change_fixture.change); |
28 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 28 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
29 | let offset = match range_or_offset { | 29 | let offset = match range_or_offset { |
30 | RangeOrOffset::Range(_) => panic!(), | 30 | RangeOrOffset::Range(_) => panic!(), |
31 | RangeOrOffset::Offset(it) => it, | 31 | RangeOrOffset::Offset(it) => it, |
@@ -33,12 +33,12 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { | |||
33 | (host.analysis(), FilePosition { file_id, offset }) | 33 | (host.analysis(), FilePosition { file_id, offset }) |
34 | } | 34 | } |
35 | 35 | ||
36 | /// Creates analysis for a single file, returns range marked with a pair of <|>. | 36 | /// Creates analysis for a single file, returns range marked with a pair of $0. |
37 | pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { | 37 | pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { |
38 | let mut host = AnalysisHost::default(); | 38 | let mut host = AnalysisHost::default(); |
39 | let change_fixture = ChangeFixture::parse(ra_fixture); | 39 | let change_fixture = ChangeFixture::parse(ra_fixture); |
40 | host.db.apply_change(change_fixture.change); | 40 | host.db.apply_change(change_fixture.change); |
41 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 41 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
42 | let range = match range_or_offset { | 42 | let range = match range_or_offset { |
43 | RangeOrOffset::Range(it) => it, | 43 | RangeOrOffset::Range(it) => it, |
44 | RangeOrOffset::Offset(_) => panic!(), | 44 | RangeOrOffset::Offset(_) => panic!(), |
@@ -46,12 +46,12 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { | |||
46 | (host.analysis(), FileRange { file_id, range }) | 46 | (host.analysis(), FileRange { file_id, range }) |
47 | } | 47 | } |
48 | 48 | ||
49 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 49 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
50 | pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { | 50 | pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { |
51 | let mut host = AnalysisHost::default(); | 51 | let mut host = AnalysisHost::default(); |
52 | let change_fixture = ChangeFixture::parse(ra_fixture); | 52 | let change_fixture = ChangeFixture::parse(ra_fixture); |
53 | host.db.apply_change(change_fixture.change); | 53 | host.db.apply_change(change_fixture.change); |
54 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 54 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
55 | let offset = match range_or_offset { | 55 | let offset = match range_or_offset { |
56 | RangeOrOffset::Range(_) => panic!(), | 56 | RangeOrOffset::Range(_) => panic!(), |
57 | RangeOrOffset::Offset(it) => it, | 57 | RangeOrOffset::Offset(it) => it, |
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs index 5cbbe306e..f6e5a522b 100644 --- a/crates/ide/src/fn_references.rs +++ b/crates/ide/src/fn_references.rs | |||
@@ -34,7 +34,7 @@ mod tests { | |||
34 | fn test_find_all_methods() { | 34 | fn test_find_all_methods() { |
35 | let (analysis, pos) = fixture::position( | 35 | let (analysis, pos) = fixture::position( |
36 | r#" | 36 | r#" |
37 | fn private_fn() {<|>} | 37 | fn private_fn() {$0} |
38 | 38 | ||
39 | pub fn pub_fn() {} | 39 | pub fn pub_fn() {} |
40 | 40 | ||
@@ -51,7 +51,7 @@ mod tests { | |||
51 | let (analysis, pos) = fixture::position( | 51 | let (analysis, pos) = fixture::position( |
52 | r#" | 52 | r#" |
53 | trait Foo { | 53 | trait Foo { |
54 | fn bar() {<|>} | 54 | fn bar() {$0} |
55 | fn baz() {} | 55 | fn baz() {} |
56 | } | 56 | } |
57 | "#, | 57 | "#, |
@@ -67,7 +67,7 @@ mod tests { | |||
67 | r#" | 67 | r#" |
68 | //- /lib.rs | 68 | //- /lib.rs |
69 | #[test] | 69 | #[test] |
70 | fn foo() {<|>} | 70 | fn foo() {$0} |
71 | 71 | ||
72 | pub fn pub_fn() {} | 72 | pub fn pub_fn() {} |
73 | 73 | ||
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 912144f8b..cd4afc804 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -1,14 +1,18 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::Semantics; | 2 | use hir::{HasAttrs, ModuleDef, Semantics}; |
3 | use ide_db::{ | 3 | use ide_db::{ |
4 | base_db::FileId, | 4 | base_db::FileId, |
5 | defs::{NameClass, NameRefClass}, | 5 | defs::{Definition, NameClass, NameRefClass}, |
6 | symbol_index, RootDatabase, | 6 | symbol_index, RootDatabase, |
7 | }; | 7 | }; |
8 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 8 | use syntax::{ |
9 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, | ||
10 | }; | ||
9 | 11 | ||
10 | use crate::{ | 12 | use crate::{ |
11 | display::{ToNav, TryToNav}, | 13 | display::{ToNav, TryToNav}, |
14 | doc_links::extract_definitions_from_markdown, | ||
15 | runnables::doc_owner_to_def, | ||
12 | FilePosition, NavigationTarget, RangeInfo, SymbolKind, | 16 | FilePosition, NavigationTarget, RangeInfo, SymbolKind, |
13 | }; | 17 | }; |
14 | 18 | ||
@@ -30,6 +34,10 @@ pub(crate) fn goto_definition( | |||
30 | let original_token = pick_best(file.token_at_offset(position.offset))?; | 34 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
31 | let token = sema.descend_into_macros(original_token.clone()); | 35 | let token = sema.descend_into_macros(original_token.clone()); |
32 | let parent = token.parent(); | 36 | let parent = token.parent(); |
37 | if let Some(comment) = ast::Comment::cast(token.clone()) { | ||
38 | let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?; | ||
39 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); | ||
40 | } | ||
33 | 41 | ||
34 | let nav_targets = match_ast! { | 42 | let nav_targets = match_ast! { |
35 | match parent { | 43 | match parent { |
@@ -68,11 +76,58 @@ pub(crate) fn goto_definition( | |||
68 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) | 76 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) |
69 | } | 77 | } |
70 | 78 | ||
79 | fn def_for_doc_comment( | ||
80 | sema: &Semantics<RootDatabase>, | ||
81 | position: FilePosition, | ||
82 | doc_comment: &ast::Comment, | ||
83 | ) -> Option<hir::ModuleDef> { | ||
84 | let parent = doc_comment.syntax().parent(); | ||
85 | let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?; | ||
86 | |||
87 | let def = doc_owner_to_def(sema, parent)?; | ||
88 | match def { | ||
89 | Definition::ModuleDef(def) => match def { | ||
90 | ModuleDef::Module(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
91 | ModuleDef::Function(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
92 | ModuleDef::Adt(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
93 | ModuleDef::Variant(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
94 | ModuleDef::Const(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
95 | ModuleDef::Static(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
96 | ModuleDef::Trait(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
97 | ModuleDef::TypeAlias(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
98 | ModuleDef::BuiltinType(_) => return None, | ||
99 | }, | ||
100 | Definition::Macro(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
101 | Definition::Field(it) => it.resolve_doc_path(sema.db, &link, ns), | ||
102 | Definition::SelfType(_) | ||
103 | | Definition::Local(_) | ||
104 | | Definition::GenericParam(_) | ||
105 | | Definition::Label(_) => return None, | ||
106 | } | ||
107 | } | ||
108 | |||
109 | fn extract_positioned_link_from_comment( | ||
110 | position: FilePosition, | ||
111 | comment: &ast::Comment, | ||
112 | ) -> Option<(String, Option<hir::Namespace>)> { | ||
113 | let comment_range = comment.syntax().text_range(); | ||
114 | let doc_comment = comment.doc_comment()?; | ||
115 | let def_links = extract_definitions_from_markdown(doc_comment); | ||
116 | let (def_link, ns, _) = def_links.iter().min_by_key(|(_, _, def_link_range)| { | ||
117 | let matched_position = comment_range.start() + TextSize::from(def_link_range.start as u32); | ||
118 | match position.offset.checked_sub(matched_position) { | ||
119 | Some(distance) => distance, | ||
120 | None => comment_range.end(), | ||
121 | } | ||
122 | })?; | ||
123 | Some((def_link.to_string(), ns.clone())) | ||
124 | } | ||
125 | |||
71 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | 126 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { |
72 | return tokens.max_by_key(priority); | 127 | return tokens.max_by_key(priority); |
73 | fn priority(n: &SyntaxToken) -> usize { | 128 | fn priority(n: &SyntaxToken) -> usize { |
74 | match n.kind() { | 129 | match n.kind() { |
75 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 2, | 130 | IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | COMMENT => 2, |
76 | kind if kind.is_trivia() => 0, | 131 | kind if kind.is_trivia() => 0, |
77 | _ => 1, | 132 | _ => 1, |
78 | } | 133 | } |
@@ -166,7 +221,7 @@ mod tests { | |||
166 | check( | 221 | check( |
167 | r#" | 222 | r#" |
168 | //- /main.rs crate:main deps:std | 223 | //- /main.rs crate:main deps:std |
169 | extern crate std<|>; | 224 | extern crate std$0; |
170 | //- /std/lib.rs crate:std | 225 | //- /std/lib.rs crate:std |
171 | // empty | 226 | // empty |
172 | //^ file | 227 | //^ file |
@@ -179,7 +234,7 @@ mod tests { | |||
179 | check( | 234 | check( |
180 | r#" | 235 | r#" |
181 | //- /main.rs crate:main deps:std | 236 | //- /main.rs crate:main deps:std |
182 | extern crate std as abc<|>; | 237 | extern crate std as abc$0; |
183 | //- /std/lib.rs crate:std | 238 | //- /std/lib.rs crate:std |
184 | // empty | 239 | // empty |
185 | //^ file | 240 | //^ file |
@@ -193,7 +248,7 @@ mod tests { | |||
193 | r#" | 248 | r#" |
194 | struct Foo; | 249 | struct Foo; |
195 | //^^^ | 250 | //^^^ |
196 | enum E { X(Foo<|>) } | 251 | enum E { X(Foo$0) } |
197 | "#, | 252 | "#, |
198 | ); | 253 | ); |
199 | } | 254 | } |
@@ -204,7 +259,7 @@ enum E { X(Foo<|>) } | |||
204 | r#" | 259 | r#" |
205 | struct Foo; | 260 | struct Foo; |
206 | //^^^ | 261 | //^^^ |
207 | enum E { X(<|>Foo) } | 262 | enum E { X($0Foo) } |
208 | "#, | 263 | "#, |
209 | ); | 264 | ); |
210 | } | 265 | } |
@@ -217,7 +272,7 @@ enum E { X(<|>Foo) } | |||
217 | use a::Foo; | 272 | use a::Foo; |
218 | mod a; | 273 | mod a; |
219 | mod b; | 274 | mod b; |
220 | enum E { X(Foo<|>) } | 275 | enum E { X(Foo$0) } |
221 | 276 | ||
222 | //- /a.rs | 277 | //- /a.rs |
223 | struct Foo; | 278 | struct Foo; |
@@ -233,7 +288,7 @@ struct Foo; | |||
233 | check( | 288 | check( |
234 | r#" | 289 | r#" |
235 | //- /lib.rs | 290 | //- /lib.rs |
236 | mod <|>foo; | 291 | mod $0foo; |
237 | 292 | ||
238 | //- /foo.rs | 293 | //- /foo.rs |
239 | // empty | 294 | // empty |
@@ -244,7 +299,7 @@ mod <|>foo; | |||
244 | check( | 299 | check( |
245 | r#" | 300 | r#" |
246 | //- /lib.rs | 301 | //- /lib.rs |
247 | mod <|>foo; | 302 | mod $0foo; |
248 | 303 | ||
249 | //- /foo/mod.rs | 304 | //- /foo/mod.rs |
250 | // empty | 305 | // empty |
@@ -260,7 +315,7 @@ mod <|>foo; | |||
260 | macro_rules! foo { () => { () } } | 315 | macro_rules! foo { () => { () } } |
261 | //^^^ | 316 | //^^^ |
262 | fn bar() { | 317 | fn bar() { |
263 | <|>foo!(); | 318 | $0foo!(); |
264 | } | 319 | } |
265 | "#, | 320 | "#, |
266 | ); | 321 | ); |
@@ -273,7 +328,7 @@ fn bar() { | |||
273 | //- /lib.rs | 328 | //- /lib.rs |
274 | use foo::foo; | 329 | use foo::foo; |
275 | fn bar() { | 330 | fn bar() { |
276 | <|>foo!(); | 331 | $0foo!(); |
277 | } | 332 | } |
278 | 333 | ||
279 | //- /foo/lib.rs | 334 | //- /foo/lib.rs |
@@ -289,7 +344,7 @@ macro_rules! foo { () => { () } } | |||
289 | check( | 344 | check( |
290 | r#" | 345 | r#" |
291 | //- /lib.rs | 346 | //- /lib.rs |
292 | use foo::foo<|>; | 347 | use foo::foo$0; |
293 | 348 | ||
294 | //- /foo/lib.rs | 349 | //- /foo/lib.rs |
295 | #[macro_export] | 350 | #[macro_export] |
@@ -312,7 +367,7 @@ define_fn!(foo); | |||
312 | //^^^ | 367 | //^^^ |
313 | 368 | ||
314 | fn bar() { | 369 | fn bar() { |
315 | <|>foo(); | 370 | $0foo(); |
316 | } | 371 | } |
317 | "#, | 372 | "#, |
318 | ); | 373 | ); |
@@ -331,7 +386,7 @@ macro_rules! define_fn { | |||
331 | //^^^^^^^^^^^^^ | 386 | //^^^^^^^^^^^^^ |
332 | 387 | ||
333 | fn bar() { | 388 | fn bar() { |
334 | <|>foo(); | 389 | $0foo(); |
335 | } | 390 | } |
336 | "#, | 391 | "#, |
337 | ); | 392 | ); |
@@ -347,7 +402,7 @@ macro_rules! foo {() => {0}} | |||
347 | 402 | ||
348 | fn bar() { | 403 | fn bar() { |
349 | match (0,1) { | 404 | match (0,1) { |
350 | (<|>foo!(), _) => {} | 405 | ($0foo!(), _) => {} |
351 | } | 406 | } |
352 | } | 407 | } |
353 | "#, | 408 | "#, |
@@ -363,7 +418,7 @@ macro_rules! foo {() => {0}} | |||
363 | //^^^ | 418 | //^^^ |
364 | fn bar() { | 419 | fn bar() { |
365 | match 0 { | 420 | match 0 { |
366 | <|>foo!() => {} | 421 | $0foo!() => {} |
367 | } | 422 | } |
368 | } | 423 | } |
369 | "#, | 424 | "#, |
@@ -375,7 +430,7 @@ fn bar() { | |||
375 | check( | 430 | check( |
376 | r#" | 431 | r#" |
377 | //- /lib.rs crate:main deps:foo | 432 | //- /lib.rs crate:main deps:foo |
378 | use foo as bar<|>; | 433 | use foo as bar$0; |
379 | 434 | ||
380 | //- /foo/lib.rs crate:foo | 435 | //- /foo/lib.rs crate:foo |
381 | // empty | 436 | // empty |
@@ -389,7 +444,7 @@ use foo as bar<|>; | |||
389 | check( | 444 | check( |
390 | r#" | 445 | r#" |
391 | //- /lib.rs crate:main deps:foo | 446 | //- /lib.rs crate:main deps:foo |
392 | use foo::foo as bar<|>; | 447 | use foo::foo as bar$0; |
393 | 448 | ||
394 | //- /foo/lib.rs crate:foo | 449 | //- /foo/lib.rs crate:foo |
395 | #[macro_export] | 450 | #[macro_export] |
@@ -410,7 +465,7 @@ impl Foo { | |||
410 | } | 465 | } |
411 | 466 | ||
412 | fn bar(foo: &Foo) { | 467 | fn bar(foo: &Foo) { |
413 | foo.frobnicate<|>(); | 468 | foo.frobnicate$0(); |
414 | } | 469 | } |
415 | "#, | 470 | "#, |
416 | ); | 471 | ); |
@@ -425,7 +480,7 @@ struct Foo { | |||
425 | } //^^^^ | 480 | } //^^^^ |
426 | 481 | ||
427 | fn bar(foo: &Foo) { | 482 | fn bar(foo: &Foo) { |
428 | foo.spam<|>; | 483 | foo.spam$0; |
429 | } | 484 | } |
430 | "#, | 485 | "#, |
431 | ); | 486 | ); |
@@ -442,7 +497,7 @@ struct Foo { | |||
442 | 497 | ||
443 | fn bar() -> Foo { | 498 | fn bar() -> Foo { |
444 | Foo { | 499 | Foo { |
445 | spam<|>: 0, | 500 | spam$0: 0, |
446 | } | 501 | } |
447 | } | 502 | } |
448 | "#, | 503 | "#, |
@@ -459,7 +514,7 @@ struct Foo { | |||
459 | } //^^^^ | 514 | } //^^^^ |
460 | 515 | ||
461 | fn bar(foo: Foo) -> Foo { | 516 | fn bar(foo: Foo) -> Foo { |
462 | let Foo { spam<|>: _, } = foo | 517 | let Foo { spam$0: _, } = foo |
463 | } | 518 | } |
464 | "#, | 519 | "#, |
465 | ); | 520 | ); |
@@ -474,7 +529,7 @@ struct Foo { spam: u32 } | |||
474 | //^^^^ | 529 | //^^^^ |
475 | 530 | ||
476 | fn bar() -> Foo { | 531 | fn bar() -> Foo { |
477 | Foo { spam<|>: m!() } | 532 | Foo { spam$0: m!() } |
478 | } | 533 | } |
479 | ", | 534 | ", |
480 | ); | 535 | ); |
@@ -489,7 +544,7 @@ struct Foo(u32); | |||
489 | 544 | ||
490 | fn bar() { | 545 | fn bar() { |
491 | let foo = Foo(0); | 546 | let foo = Foo(0); |
492 | foo.<|>0; | 547 | foo.$00; |
493 | } | 548 | } |
494 | "#, | 549 | "#, |
495 | ); | 550 | ); |
@@ -505,7 +560,7 @@ impl Foo { | |||
505 | } //^^^^^^^^^^ | 560 | } //^^^^^^^^^^ |
506 | 561 | ||
507 | fn bar(foo: &Foo) { | 562 | fn bar(foo: &Foo) { |
508 | Foo::frobnicate<|>(); | 563 | Foo::frobnicate$0(); |
509 | } | 564 | } |
510 | "#, | 565 | "#, |
511 | ); | 566 | ); |
@@ -520,7 +575,7 @@ trait Foo { | |||
520 | } //^^^^^^^^^^ | 575 | } //^^^^^^^^^^ |
521 | 576 | ||
522 | fn bar() { | 577 | fn bar() { |
523 | Foo::frobnicate<|>(); | 578 | Foo::frobnicate$0(); |
524 | } | 579 | } |
525 | "#, | 580 | "#, |
526 | ); | 581 | ); |
@@ -537,7 +592,7 @@ trait Trait { | |||
537 | impl Trait for Foo {} | 592 | impl Trait for Foo {} |
538 | 593 | ||
539 | fn bar() { | 594 | fn bar() { |
540 | Foo::frobnicate<|>(); | 595 | Foo::frobnicate$0(); |
541 | } | 596 | } |
542 | "#, | 597 | "#, |
543 | ); | 598 | ); |
@@ -551,7 +606,7 @@ struct Foo; | |||
551 | impl Foo { | 606 | impl Foo { |
552 | //^^^ | 607 | //^^^ |
553 | pub fn new() -> Self { | 608 | pub fn new() -> Self { |
554 | Self<|> {} | 609 | Self$0 {} |
555 | } | 610 | } |
556 | } | 611 | } |
557 | "#, | 612 | "#, |
@@ -561,7 +616,7 @@ impl Foo { | |||
561 | struct Foo; | 616 | struct Foo; |
562 | impl Foo { | 617 | impl Foo { |
563 | //^^^ | 618 | //^^^ |
564 | pub fn new() -> Self<|> { | 619 | pub fn new() -> Self$0 { |
565 | Self {} | 620 | Self {} |
566 | } | 621 | } |
567 | } | 622 | } |
@@ -573,7 +628,7 @@ impl Foo { | |||
573 | enum Foo { A } | 628 | enum Foo { A } |
574 | impl Foo { | 629 | impl Foo { |
575 | //^^^ | 630 | //^^^ |
576 | pub fn new() -> Self<|> { | 631 | pub fn new() -> Self$0 { |
577 | Foo::A | 632 | Foo::A |
578 | } | 633 | } |
579 | } | 634 | } |
@@ -585,7 +640,7 @@ impl Foo { | |||
585 | enum Foo { A } | 640 | enum Foo { A } |
586 | impl Foo { | 641 | impl Foo { |
587 | //^^^ | 642 | //^^^ |
588 | pub fn thing(a: &Self<|>) { | 643 | pub fn thing(a: &Self$0) { |
589 | } | 644 | } |
590 | } | 645 | } |
591 | "#, | 646 | "#, |
@@ -603,7 +658,7 @@ trait Make { | |||
603 | impl Make for Foo { | 658 | impl Make for Foo { |
604 | //^^^ | 659 | //^^^ |
605 | fn new() -> Self { | 660 | fn new() -> Self { |
606 | Self<|> {} | 661 | Self$0 {} |
607 | } | 662 | } |
608 | } | 663 | } |
609 | "#, | 664 | "#, |
@@ -617,7 +672,7 @@ trait Make { | |||
617 | } | 672 | } |
618 | impl Make for Foo { | 673 | impl Make for Foo { |
619 | //^^^ | 674 | //^^^ |
620 | fn new() -> Self<|> { | 675 | fn new() -> Self$0 { |
621 | Self {} | 676 | Self {} |
622 | } | 677 | } |
623 | } | 678 | } |
@@ -629,7 +684,7 @@ impl Make for Foo { | |||
629 | fn goto_def_when_used_on_definition_name_itself() { | 684 | fn goto_def_when_used_on_definition_name_itself() { |
630 | check( | 685 | check( |
631 | r#" | 686 | r#" |
632 | struct Foo<|> { value: u32 } | 687 | struct Foo$0 { value: u32 } |
633 | //^^^ | 688 | //^^^ |
634 | "#, | 689 | "#, |
635 | ); | 690 | ); |
@@ -637,21 +692,21 @@ struct Foo<|> { value: u32 } | |||
637 | check( | 692 | check( |
638 | r#" | 693 | r#" |
639 | struct Foo { | 694 | struct Foo { |
640 | field<|>: string, | 695 | field$0: string, |
641 | } //^^^^^ | 696 | } //^^^^^ |
642 | "#, | 697 | "#, |
643 | ); | 698 | ); |
644 | 699 | ||
645 | check( | 700 | check( |
646 | r#" | 701 | r#" |
647 | fn foo_test<|>() { } | 702 | fn foo_test$0() { } |
648 | //^^^^^^^^ | 703 | //^^^^^^^^ |
649 | "#, | 704 | "#, |
650 | ); | 705 | ); |
651 | 706 | ||
652 | check( | 707 | check( |
653 | r#" | 708 | r#" |
654 | enum Foo<|> { Variant } | 709 | enum Foo$0 { Variant } |
655 | //^^^ | 710 | //^^^ |
656 | "#, | 711 | "#, |
657 | ); | 712 | ); |
@@ -660,7 +715,7 @@ enum Foo<|> { Variant } | |||
660 | r#" | 715 | r#" |
661 | enum Foo { | 716 | enum Foo { |
662 | Variant1, | 717 | Variant1, |
663 | Variant2<|>, | 718 | Variant2$0, |
664 | //^^^^^^^^ | 719 | //^^^^^^^^ |
665 | Variant3, | 720 | Variant3, |
666 | } | 721 | } |
@@ -669,35 +724,35 @@ enum Foo { | |||
669 | 724 | ||
670 | check( | 725 | check( |
671 | r#" | 726 | r#" |
672 | static INNER<|>: &str = ""; | 727 | static INNER$0: &str = ""; |
673 | //^^^^^ | 728 | //^^^^^ |
674 | "#, | 729 | "#, |
675 | ); | 730 | ); |
676 | 731 | ||
677 | check( | 732 | check( |
678 | r#" | 733 | r#" |
679 | const INNER<|>: &str = ""; | 734 | const INNER$0: &str = ""; |
680 | //^^^^^ | 735 | //^^^^^ |
681 | "#, | 736 | "#, |
682 | ); | 737 | ); |
683 | 738 | ||
684 | check( | 739 | check( |
685 | r#" | 740 | r#" |
686 | type Thing<|> = Option<()>; | 741 | type Thing$0 = Option<()>; |
687 | //^^^^^ | 742 | //^^^^^ |
688 | "#, | 743 | "#, |
689 | ); | 744 | ); |
690 | 745 | ||
691 | check( | 746 | check( |
692 | r#" | 747 | r#" |
693 | trait Foo<|> { } | 748 | trait Foo$0 { } |
694 | //^^^ | 749 | //^^^ |
695 | "#, | 750 | "#, |
696 | ); | 751 | ); |
697 | 752 | ||
698 | check( | 753 | check( |
699 | r#" | 754 | r#" |
700 | mod bar<|> { } | 755 | mod bar$0 { } |
701 | //^^^ | 756 | //^^^ |
702 | "#, | 757 | "#, |
703 | ); | 758 | ); |
@@ -714,7 +769,7 @@ fn foo() {} | |||
714 | //^^^ | 769 | //^^^ |
715 | id! { | 770 | id! { |
716 | fn bar() { | 771 | fn bar() { |
717 | fo<|>o(); | 772 | fo$0o(); |
718 | } | 773 | } |
719 | } | 774 | } |
720 | mod confuse_index { fn foo(); } | 775 | mod confuse_index { fn foo(); } |
@@ -743,7 +798,7 @@ pub mod __export { | |||
743 | fn foo() -> i8 {} | 798 | fn foo() -> i8 {} |
744 | //^^^ | 799 | //^^^ |
745 | fn test() { | 800 | fn test() { |
746 | format!("{}", fo<|>o()) | 801 | format!("{}", fo$0o()) |
747 | } | 802 | } |
748 | "#, | 803 | "#, |
749 | ); | 804 | ); |
@@ -761,7 +816,7 @@ macro_rules! include {} | |||
761 | //^^^^^^^^^^^^^^^^^^^ | 816 | //^^^^^^^^^^^^^^^^^^^ |
762 | 817 | ||
763 | fn f() { | 818 | fn f() { |
764 | foo<|>(); | 819 | foo$0(); |
765 | } | 820 | } |
766 | 821 | ||
767 | mod confuse_index { | 822 | mod confuse_index { |
@@ -778,7 +833,7 @@ fn foo() {} | |||
778 | fn goto_for_type_param() { | 833 | fn goto_for_type_param() { |
779 | check( | 834 | check( |
780 | r#" | 835 | r#" |
781 | struct Foo<T: Clone> { t: <|>T } | 836 | struct Foo<T: Clone> { t: $0T } |
782 | //^ | 837 | //^ |
783 | "#, | 838 | "#, |
784 | ); | 839 | ); |
@@ -796,7 +851,7 @@ fn foo() { | |||
796 | let x = 1; | 851 | let x = 1; |
797 | //^ | 852 | //^ |
798 | id!({ | 853 | id!({ |
799 | let y = <|>x; | 854 | let y = $0x; |
800 | let z = y; | 855 | let z = y; |
801 | }); | 856 | }); |
802 | } | 857 | } |
@@ -814,7 +869,7 @@ fn foo() { | |||
814 | id!({ | 869 | id!({ |
815 | let y = x; | 870 | let y = x; |
816 | //^ | 871 | //^ |
817 | let z = <|>y; | 872 | let z = $0y; |
818 | }); | 873 | }); |
819 | } | 874 | } |
820 | "#, | 875 | "#, |
@@ -829,7 +884,7 @@ fn main() { | |||
829 | fn foo() { | 884 | fn foo() { |
830 | let x = 92; | 885 | let x = 92; |
831 | //^ | 886 | //^ |
832 | <|>x; | 887 | $0x; |
833 | } | 888 | } |
834 | } | 889 | } |
835 | "#, | 890 | "#, |
@@ -843,7 +898,7 @@ fn main() { | |||
843 | fn bar() { | 898 | fn bar() { |
844 | macro_rules! foo { () => { () } } | 899 | macro_rules! foo { () => { () } } |
845 | //^^^ | 900 | //^^^ |
846 | <|>foo!(); | 901 | $0foo!(); |
847 | } | 902 | } |
848 | "#, | 903 | "#, |
849 | ); | 904 | ); |
@@ -857,7 +912,7 @@ struct Foo { x: i32 } | |||
857 | fn main() { | 912 | fn main() { |
858 | let x = 92; | 913 | let x = 92; |
859 | //^ | 914 | //^ |
860 | Foo { x<|> }; | 915 | Foo { x$0 }; |
861 | } | 916 | } |
862 | "#, | 917 | "#, |
863 | ) | 918 | ) |
@@ -872,7 +927,7 @@ enum Foo { | |||
872 | } //^ | 927 | } //^ |
873 | fn baz(foo: Foo) { | 928 | fn baz(foo: Foo) { |
874 | match foo { | 929 | match foo { |
875 | Foo::Bar { x<|> } => x | 930 | Foo::Bar { x$0 } => x |
876 | }; | 931 | }; |
877 | } | 932 | } |
878 | "#, | 933 | "#, |
@@ -887,7 +942,7 @@ enum Foo { Bar } | |||
887 | //^^^ | 942 | //^^^ |
888 | impl Foo { | 943 | impl Foo { |
889 | fn baz(self) { | 944 | fn baz(self) { |
890 | match self { Self::Bar<|> => {} } | 945 | match self { Self::Bar$0 => {} } |
891 | } | 946 | } |
892 | } | 947 | } |
893 | "#, | 948 | "#, |
@@ -902,7 +957,7 @@ enum Foo { Bar { val: i32 } } | |||
902 | //^^^ | 957 | //^^^ |
903 | impl Foo { | 958 | impl Foo { |
904 | fn baz(self) -> i32 { | 959 | fn baz(self) -> i32 { |
905 | match self { Self::Bar<|> { val } => {} } | 960 | match self { Self::Bar$0 { val } => {} } |
906 | } | 961 | } |
907 | } | 962 | } |
908 | "#, | 963 | "#, |
@@ -916,7 +971,7 @@ impl Foo { | |||
916 | enum Foo { Bar } | 971 | enum Foo { Bar } |
917 | //^^^ | 972 | //^^^ |
918 | impl Foo { | 973 | impl Foo { |
919 | fn baz(self) { Self::Bar<|>; } | 974 | fn baz(self) { Self::Bar$0; } |
920 | } | 975 | } |
921 | "#, | 976 | "#, |
922 | ); | 977 | ); |
@@ -929,7 +984,7 @@ impl Foo { | |||
929 | enum Foo { Bar { val: i32 } } | 984 | enum Foo { Bar { val: i32 } } |
930 | //^^^ | 985 | //^^^ |
931 | impl Foo { | 986 | impl Foo { |
932 | fn baz(self) { Self::Bar<|> {val: 4}; } | 987 | fn baz(self) { Self::Bar$0 {val: 4}; } |
933 | } | 988 | } |
934 | "#, | 989 | "#, |
935 | ); | 990 | ); |
@@ -939,7 +994,7 @@ impl Foo { | |||
939 | fn goto_def_for_type_alias_generic_parameter() { | 994 | fn goto_def_for_type_alias_generic_parameter() { |
940 | check( | 995 | check( |
941 | r#" | 996 | r#" |
942 | type Alias<T> = T<|>; | 997 | type Alias<T> = T$0; |
943 | //^ | 998 | //^ |
944 | "#, | 999 | "#, |
945 | ) | 1000 | ) |
@@ -950,7 +1005,7 @@ type Alias<T> = T<|>; | |||
950 | check( | 1005 | check( |
951 | r#" | 1006 | r#" |
952 | //- /lib.rs | 1007 | //- /lib.rs |
953 | foo::module<|>::mac!(); | 1008 | foo::module$0::mac!(); |
954 | 1009 | ||
955 | //- /foo/lib.rs | 1010 | //- /foo/lib.rs |
956 | pub mod module { | 1011 | pub mod module { |
@@ -972,7 +1027,7 @@ trait Iterator { | |||
972 | //^^^^ | 1027 | //^^^^ |
973 | } | 1028 | } |
974 | 1029 | ||
975 | fn f() -> impl Iterator<Item<|> = u8> {} | 1030 | fn f() -> impl Iterator<Item$0 = u8> {} |
976 | "#, | 1031 | "#, |
977 | ); | 1032 | ); |
978 | } | 1033 | } |
@@ -987,7 +1042,7 @@ trait Iterator { | |||
987 | type B; | 1042 | type B; |
988 | } | 1043 | } |
989 | 1044 | ||
990 | fn f() -> impl Iterator<A<|> = u8, B = ()> {} | 1045 | fn f() -> impl Iterator<A$0 = u8, B = ()> {} |
991 | "#, | 1046 | "#, |
992 | ); | 1047 | ); |
993 | check( | 1048 | check( |
@@ -998,7 +1053,7 @@ trait Iterator { | |||
998 | //^ | 1053 | //^ |
999 | } | 1054 | } |
1000 | 1055 | ||
1001 | fn f() -> impl Iterator<A = u8, B<|> = ()> {} | 1056 | fn f() -> impl Iterator<A = u8, B$0 = ()> {} |
1002 | "#, | 1057 | "#, |
1003 | ); | 1058 | ); |
1004 | } | 1059 | } |
@@ -1012,7 +1067,7 @@ trait Iterator { | |||
1012 | //^^^^ | 1067 | //^^^^ |
1013 | } | 1068 | } |
1014 | 1069 | ||
1015 | fn g() -> <() as Iterator<Item<|> = ()>>::Item {} | 1070 | fn g() -> <() as Iterator<Item$0 = ()>>::Item {} |
1016 | "#, | 1071 | "#, |
1017 | ); | 1072 | ); |
1018 | } | 1073 | } |
@@ -1027,7 +1082,7 @@ trait Iterator { | |||
1027 | type B; | 1082 | type B; |
1028 | } | 1083 | } |
1029 | 1084 | ||
1030 | fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {} | 1085 | fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {} |
1031 | "#, | 1086 | "#, |
1032 | ); | 1087 | ); |
1033 | check( | 1088 | check( |
@@ -1038,7 +1093,7 @@ trait Iterator { | |||
1038 | //^ | 1093 | //^ |
1039 | } | 1094 | } |
1040 | 1095 | ||
1041 | fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {} | 1096 | fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {} |
1042 | "#, | 1097 | "#, |
1043 | ); | 1098 | ); |
1044 | } | 1099 | } |
@@ -1052,7 +1107,7 @@ struct Foo {} | |||
1052 | impl Foo { | 1107 | impl Foo { |
1053 | fn bar(self: &Foo) { | 1108 | fn bar(self: &Foo) { |
1054 | //^^^^ | 1109 | //^^^^ |
1055 | let foo = sel<|>f; | 1110 | let foo = sel$0f; |
1056 | } | 1111 | } |
1057 | }"#, | 1112 | }"#, |
1058 | ) | 1113 | ) |
@@ -1065,7 +1120,7 @@ impl Foo { | |||
1065 | struct Foo {} | 1120 | struct Foo {} |
1066 | 1121 | ||
1067 | impl Foo { | 1122 | impl Foo { |
1068 | fn bar(&self<|>) { | 1123 | fn bar(&self$0) { |
1069 | //^^^^ | 1124 | //^^^^ |
1070 | } | 1125 | } |
1071 | }"#, | 1126 | }"#, |
@@ -1076,7 +1131,7 @@ impl Foo { | |||
1076 | fn goto_lifetime_param_on_decl() { | 1131 | fn goto_lifetime_param_on_decl() { |
1077 | check( | 1132 | check( |
1078 | r#" | 1133 | r#" |
1079 | fn foo<'foobar<|>>(_: &'foobar ()) { | 1134 | fn foo<'foobar$0>(_: &'foobar ()) { |
1080 | //^^^^^^^ | 1135 | //^^^^^^^ |
1081 | }"#, | 1136 | }"#, |
1082 | ) | 1137 | ) |
@@ -1086,7 +1141,7 @@ fn foo<'foobar<|>>(_: &'foobar ()) { | |||
1086 | fn goto_lifetime_param_decl() { | 1141 | fn goto_lifetime_param_decl() { |
1087 | check( | 1142 | check( |
1088 | r#" | 1143 | r#" |
1089 | fn foo<'foobar>(_: &'foobar<|> ()) { | 1144 | fn foo<'foobar>(_: &'foobar$0 ()) { |
1090 | //^^^^^^^ | 1145 | //^^^^^^^ |
1091 | }"#, | 1146 | }"#, |
1092 | ) | 1147 | ) |
@@ -1097,7 +1152,7 @@ fn foo<'foobar>(_: &'foobar<|> ()) { | |||
1097 | check( | 1152 | check( |
1098 | r#" | 1153 | r#" |
1099 | fn foo<'foobar>(_: &'foobar ()) { | 1154 | fn foo<'foobar>(_: &'foobar ()) { |
1100 | fn foo<'foobar>(_: &'foobar<|> ()) {} | 1155 | fn foo<'foobar>(_: &'foobar$0 ()) {} |
1101 | //^^^^^^^ | 1156 | //^^^^^^^ |
1102 | }"#, | 1157 | }"#, |
1103 | ) | 1158 | ) |
@@ -1108,13 +1163,13 @@ fn foo<'foobar>(_: &'foobar ()) { | |||
1108 | fn goto_lifetime_hrtb() { | 1163 | fn goto_lifetime_hrtb() { |
1109 | check( | 1164 | check( |
1110 | r#"trait Foo<T> {} | 1165 | r#"trait Foo<T> {} |
1111 | fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {} | 1166 | fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} |
1112 | //^^ | 1167 | //^^ |
1113 | "#, | 1168 | "#, |
1114 | ); | 1169 | ); |
1115 | check( | 1170 | check( |
1116 | r#"trait Foo<T> {} | 1171 | r#"trait Foo<T> {} |
1117 | fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} | 1172 | fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} |
1118 | //^^ | 1173 | //^^ |
1119 | "#, | 1174 | "#, |
1120 | ); | 1175 | ); |
@@ -1125,7 +1180,7 @@ fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} | |||
1125 | fn goto_lifetime_hrtb_for_type() { | 1180 | fn goto_lifetime_hrtb_for_type() { |
1126 | check( | 1181 | check( |
1127 | r#"trait Foo<T> {} | 1182 | r#"trait Foo<T> {} |
1128 | fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {} | 1183 | fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} |
1129 | //^^ | 1184 | //^^ |
1130 | "#, | 1185 | "#, |
1131 | ); | 1186 | ); |
@@ -1139,10 +1194,40 @@ fn foo<'foo>(_: &'foo ()) { | |||
1139 | 'foo: { | 1194 | 'foo: { |
1140 | //^^^^ | 1195 | //^^^^ |
1141 | 'bar: loop { | 1196 | 'bar: loop { |
1142 | break 'foo<|>; | 1197 | break 'foo$0; |
1143 | } | 1198 | } |
1144 | } | 1199 | } |
1145 | }"#, | 1200 | }"#, |
1146 | ) | 1201 | ) |
1147 | } | 1202 | } |
1203 | |||
1204 | #[test] | ||
1205 | fn goto_def_for_intra_doc_link_same_file() { | ||
1206 | check( | ||
1207 | r#" | ||
1208 | /// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar) | ||
1209 | pub fn bar() { } | ||
1210 | |||
1211 | /// You might want to see [`std::fs::read()`] too. | ||
1212 | pub fn foo() { } | ||
1213 | //^^^ | ||
1214 | |||
1215 | }"#, | ||
1216 | ) | ||
1217 | } | ||
1218 | |||
1219 | #[test] | ||
1220 | fn goto_def_for_intra_doc_link_inner() { | ||
1221 | check( | ||
1222 | r#" | ||
1223 | //- /main.rs | ||
1224 | mod m; | ||
1225 | struct S; | ||
1226 | //^ | ||
1227 | |||
1228 | //- /m.rs | ||
1229 | //! [`super::S$0`] | ||
1230 | "#, | ||
1231 | ) | ||
1232 | } | ||
1148 | } | 1233 | } |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 6eac39639..761a98b2c 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -2,7 +2,7 @@ use hir::{Crate, Impl, Semantics}; | |||
2 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | 3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; |
4 | 4 | ||
5 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 5 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
6 | 6 | ||
7 | // Feature: Go to Implementation | 7 | // Feature: Go to Implementation |
8 | // | 8 | // |
@@ -55,7 +55,7 @@ fn impls_for_def( | |||
55 | impls | 55 | impls |
56 | .into_iter() | 56 | .into_iter() |
57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) | 57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) |
58 | .map(|imp| imp.to_nav(sema.db)) | 58 | .filter_map(|imp| imp.try_to_nav(sema.db)) |
59 | .collect(), | 59 | .collect(), |
60 | ) | 60 | ) |
61 | } | 61 | } |
@@ -69,7 +69,7 @@ fn impls_for_trait( | |||
69 | 69 | ||
70 | let impls = Impl::for_trait(sema.db, krate, tr); | 70 | let impls = Impl::for_trait(sema.db, krate, tr); |
71 | 71 | ||
72 | Some(impls.into_iter().map(|imp| imp.to_nav(sema.db)).collect()) | 72 | Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()) |
73 | } | 73 | } |
74 | 74 | ||
75 | #[cfg(test)] | 75 | #[cfg(test)] |
@@ -107,7 +107,7 @@ mod tests { | |||
107 | fn goto_implementation_works() { | 107 | fn goto_implementation_works() { |
108 | check( | 108 | check( |
109 | r#" | 109 | r#" |
110 | struct Foo<|>; | 110 | struct Foo$0; |
111 | impl Foo {} | 111 | impl Foo {} |
112 | //^^^ | 112 | //^^^ |
113 | "#, | 113 | "#, |
@@ -118,7 +118,7 @@ impl Foo {} | |||
118 | fn goto_implementation_works_multiple_blocks() { | 118 | fn goto_implementation_works_multiple_blocks() { |
119 | check( | 119 | check( |
120 | r#" | 120 | r#" |
121 | struct Foo<|>; | 121 | struct Foo$0; |
122 | impl Foo {} | 122 | impl Foo {} |
123 | //^^^ | 123 | //^^^ |
124 | impl Foo {} | 124 | impl Foo {} |
@@ -131,7 +131,7 @@ impl Foo {} | |||
131 | fn goto_implementation_works_multiple_mods() { | 131 | fn goto_implementation_works_multiple_mods() { |
132 | check( | 132 | check( |
133 | r#" | 133 | r#" |
134 | struct Foo<|>; | 134 | struct Foo$0; |
135 | mod a { | 135 | mod a { |
136 | impl super::Foo {} | 136 | impl super::Foo {} |
137 | //^^^^^^^^^^ | 137 | //^^^^^^^^^^ |
@@ -149,7 +149,7 @@ mod b { | |||
149 | check( | 149 | check( |
150 | r#" | 150 | r#" |
151 | //- /lib.rs | 151 | //- /lib.rs |
152 | struct Foo<|>; | 152 | struct Foo$0; |
153 | mod a; | 153 | mod a; |
154 | mod b; | 154 | mod b; |
155 | //- /a.rs | 155 | //- /a.rs |
@@ -166,7 +166,7 @@ impl crate::Foo {} | |||
166 | fn goto_implementation_for_trait() { | 166 | fn goto_implementation_for_trait() { |
167 | check( | 167 | check( |
168 | r#" | 168 | r#" |
169 | trait T<|> {} | 169 | trait T$0 {} |
170 | struct Foo; | 170 | struct Foo; |
171 | impl T for Foo {} | 171 | impl T for Foo {} |
172 | //^^^ | 172 | //^^^ |
@@ -179,7 +179,7 @@ impl T for Foo {} | |||
179 | check( | 179 | check( |
180 | r#" | 180 | r#" |
181 | //- /lib.rs | 181 | //- /lib.rs |
182 | trait T<|> {}; | 182 | trait T$0 {}; |
183 | struct Foo; | 183 | struct Foo; |
184 | mod a; | 184 | mod a; |
185 | mod b; | 185 | mod b; |
@@ -199,7 +199,7 @@ impl crate::T for crate::Foo {} | |||
199 | r#" | 199 | r#" |
200 | //- /lib.rs | 200 | //- /lib.rs |
201 | trait T {} | 201 | trait T {} |
202 | struct Foo<|>; | 202 | struct Foo$0; |
203 | impl Foo {} | 203 | impl Foo {} |
204 | //^^^ | 204 | //^^^ |
205 | impl T for Foo {} | 205 | impl T for Foo {} |
@@ -216,7 +216,7 @@ impl T for &Foo {} | |||
216 | r#" | 216 | r#" |
217 | #[derive(Copy)] | 217 | #[derive(Copy)] |
218 | //^^^^^^^^^^^^^^^ | 218 | //^^^^^^^^^^^^^^^ |
219 | struct Foo<|>; | 219 | struct Foo$0; |
220 | 220 | ||
221 | mod marker { | 221 | mod marker { |
222 | trait Copy {} | 222 | trait Copy {} |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index aba6bf5dc..369a59820 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ide_db::RootDatabase; | 1 | use ide_db::RootDatabase; |
2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 3 | ||
4 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 4 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
5 | 5 | ||
6 | // Feature: Go to Type Definition | 6 | // Feature: Go to Type Definition |
7 | // | 7 | // |
@@ -37,7 +37,7 @@ pub(crate) fn goto_type_definition( | |||
37 | 37 | ||
38 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; | 38 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; |
39 | 39 | ||
40 | let nav = adt_def.to_nav(db); | 40 | let nav = adt_def.try_to_nav(db)?; |
41 | Some(RangeInfo::new(node.text_range(), vec![nav])) | 41 | Some(RangeInfo::new(node.text_range(), vec![nav])) |
42 | } | 42 | } |
43 | 43 | ||
@@ -76,7 +76,7 @@ mod tests { | |||
76 | struct Foo; | 76 | struct Foo; |
77 | //^^^ | 77 | //^^^ |
78 | fn foo() { | 78 | fn foo() { |
79 | let f: Foo; f<|> | 79 | let f: Foo; f$0 |
80 | } | 80 | } |
81 | "#, | 81 | "#, |
82 | ); | 82 | ); |
@@ -89,7 +89,7 @@ fn foo() { | |||
89 | struct Foo; | 89 | struct Foo; |
90 | //^^^ | 90 | //^^^ |
91 | fn foo() { | 91 | fn foo() { |
92 | let f: &Foo; f<|> | 92 | let f: &Foo; f$0 |
93 | } | 93 | } |
94 | "#, | 94 | "#, |
95 | ); | 95 | ); |
@@ -103,7 +103,7 @@ macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | |||
103 | struct Foo {} | 103 | struct Foo {} |
104 | //^^^ | 104 | //^^^ |
105 | id! { | 105 | id! { |
106 | fn bar() { let f<|> = Foo {}; } | 106 | fn bar() { let f$0 = Foo {}; } |
107 | } | 107 | } |
108 | "#, | 108 | "#, |
109 | ); | 109 | ); |
@@ -115,7 +115,7 @@ id! { | |||
115 | r#" | 115 | r#" |
116 | struct Foo; | 116 | struct Foo; |
117 | //^^^ | 117 | //^^^ |
118 | fn foo(<|>f: Foo) {} | 118 | fn foo($0f: Foo) {} |
119 | "#, | 119 | "#, |
120 | ); | 120 | ); |
121 | } | 121 | } |
@@ -129,7 +129,7 @@ struct Foo; | |||
129 | struct Bar(Foo); | 129 | struct Bar(Foo); |
130 | fn foo() { | 130 | fn foo() { |
131 | let bar = Bar(Foo); | 131 | let bar = Bar(Foo); |
132 | bar.<|>0; | 132 | bar.$00; |
133 | } | 133 | } |
134 | "#, | 134 | "#, |
135 | ); | 135 | ); |
@@ -142,7 +142,7 @@ fn foo() { | |||
142 | struct Foo; | 142 | struct Foo; |
143 | //^^^ | 143 | //^^^ |
144 | impl Foo { | 144 | impl Foo { |
145 | fn f(&self<|>) {} | 145 | fn f(&self$0) {} |
146 | } | 146 | } |
147 | "#, | 147 | "#, |
148 | ) | 148 | ) |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 73245fbe7..317b6f011 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use hir::{ | 1 | use hir::{ |
2 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasAttrs, HasSource, HirDisplay, Module, | 2 | Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource, |
3 | ModuleDef, ModuleSource, Semantics, | 3 | HirDisplay, Module, ModuleDef, ModuleSource, Semantics, |
4 | }; | 4 | }; |
5 | use ide_db::base_db::SourceDatabase; | 5 | use ide_db::base_db::SourceDatabase; |
6 | use ide_db::{ | 6 | use ide_db::{ |
@@ -13,11 +13,11 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, | |||
13 | use test_utils::mark; | 13 | use test_utils::mark; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{macro_label, ShortLabel, ToNav, TryToNav}, | 16 | display::{macro_label, ShortLabel, TryToNav}, |
17 | doc_links::{remove_links, rewrite_links}, | 17 | doc_links::{remove_links, rewrite_links}, |
18 | markdown_remove::remove_markdown, | 18 | markdown_remove::remove_markdown, |
19 | markup::Markup, | 19 | markup::Markup, |
20 | runnables::runnable, | 20 | runnables::{runnable_fn, runnable_mod}, |
21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | 21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -31,19 +31,6 @@ pub struct HoverConfig { | |||
31 | pub markdown: bool, | 31 | pub markdown: bool, |
32 | } | 32 | } |
33 | 33 | ||
34 | impl Default for HoverConfig { | ||
35 | fn default() -> Self { | ||
36 | Self { | ||
37 | implementations: true, | ||
38 | run: true, | ||
39 | debug: true, | ||
40 | goto_type_def: true, | ||
41 | links_in_hover: true, | ||
42 | markdown: true, | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | |||
47 | impl HoverConfig { | 34 | impl HoverConfig { |
48 | pub const NO_ACTIONS: Self = Self { | 35 | pub const NO_ACTIONS: Self = Self { |
49 | implementations: false, | 36 | implementations: false, |
@@ -70,7 +57,7 @@ impl HoverConfig { | |||
70 | #[derive(Debug, Clone)] | 57 | #[derive(Debug, Clone)] |
71 | pub enum HoverAction { | 58 | pub enum HoverAction { |
72 | Runnable(Runnable), | 59 | Runnable(Runnable), |
73 | Implementaion(FilePosition), | 60 | Implementation(FilePosition), |
74 | GoToType(Vec<HoverGotoTypeData>), | 61 | GoToType(Vec<HoverGotoTypeData>), |
75 | } | 62 | } |
76 | 63 | ||
@@ -109,17 +96,20 @@ pub(crate) fn hover( | |||
109 | match node { | 96 | match node { |
110 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), | 97 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), |
111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 98 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), |
99 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) | ||
100 | .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), | ||
112 | _ => None, | 101 | _ => None, |
113 | } | 102 | } |
114 | }; | 103 | }; |
115 | if let Some(definition) = definition { | 104 | if let Some(definition) = definition { |
116 | if let Some(markup) = hover_for_definition(db, definition) { | 105 | if let Some(markup) = hover_for_definition(db, definition) { |
106 | let markup = markup.as_str(); | ||
117 | let markup = if !markdown { | 107 | let markup = if !markdown { |
118 | remove_markdown(&markup.as_str()) | 108 | remove_markdown(markup) |
119 | } else if links_in_hover { | 109 | } else if links_in_hover { |
120 | rewrite_links(db, &markup.as_str(), &definition) | 110 | rewrite_links(db, markup, &definition) |
121 | } else { | 111 | } else { |
122 | remove_links(&markup.as_str()) | 112 | remove_links(markup) |
123 | }; | 113 | }; |
124 | res.markup = Markup::from(markup); | 114 | res.markup = Markup::from(markup); |
125 | if let Some(action) = show_implementations_action(db, definition) { | 115 | if let Some(action) = show_implementations_action(db, definition) { |
@@ -173,22 +163,19 @@ pub(crate) fn hover( | |||
173 | 163 | ||
174 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 164 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
175 | fn to_action(nav_target: NavigationTarget) -> HoverAction { | 165 | fn to_action(nav_target: NavigationTarget) -> HoverAction { |
176 | HoverAction::Implementaion(FilePosition { | 166 | HoverAction::Implementation(FilePosition { |
177 | file_id: nav_target.file_id, | 167 | file_id: nav_target.file_id, |
178 | offset: nav_target.focus_or_full_range().start(), | 168 | offset: nav_target.focus_or_full_range().start(), |
179 | }) | 169 | }) |
180 | } | 170 | } |
181 | 171 | ||
182 | match def { | 172 | let adt = match def { |
183 | Definition::ModuleDef(it) => match it { | 173 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), |
184 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), | 174 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), |
185 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), | 175 | Definition::SelfType(it) => it.target_ty(db).as_adt(), |
186 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), | ||
187 | ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), | ||
188 | _ => None, | ||
189 | }, | ||
190 | _ => None, | 176 | _ => None, |
191 | } | 177 | }?; |
178 | adt.try_to_nav(db).map(to_action) | ||
192 | } | 179 | } |
193 | 180 | ||
194 | fn runnable_action( | 181 | fn runnable_action( |
@@ -199,21 +186,20 @@ fn runnable_action( | |||
199 | match def { | 186 | match def { |
200 | Definition::ModuleDef(it) => match it { | 187 | Definition::ModuleDef(it) => match it { |
201 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | 188 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { |
202 | ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id) | 189 | ModuleSource::Module(it) => { |
203 | .map(|it| HoverAction::Runnable(it)), | 190 | runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it)) |
191 | } | ||
204 | _ => None, | 192 | _ => None, |
205 | }, | 193 | }, |
206 | ModuleDef::Function(it) => { | 194 | ModuleDef::Function(func) => { |
207 | let src = it.source(sema.db); | 195 | let src = func.source(sema.db)?; |
208 | if src.file_id != file_id.into() { | 196 | if src.file_id != file_id.into() { |
209 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 197 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
210 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | 198 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); |
211 | |||
212 | return None; | 199 | return None; |
213 | } | 200 | } |
214 | 201 | ||
215 | runnable(&sema, src.value.syntax().clone(), file_id) | 202 | runnable_fn(&sema, func).map(HoverAction::Runnable) |
216 | .map(|it| HoverAction::Runnable(it)) | ||
217 | } | 203 | } |
218 | _ => None, | 204 | _ => None, |
219 | }, | 205 | }, |
@@ -222,45 +208,46 @@ fn runnable_action( | |||
222 | } | 208 | } |
223 | 209 | ||
224 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 210 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
225 | match def { | 211 | let mut targets: Vec<ModuleDef> = Vec::new(); |
226 | Definition::Local(it) => { | 212 | let mut push_new_def = |item: ModuleDef| { |
227 | let mut targets: Vec<ModuleDef> = Vec::new(); | 213 | if !targets.contains(&item) { |
228 | let mut push_new_def = |item: ModuleDef| { | 214 | targets.push(item); |
229 | if !targets.contains(&item) { | ||
230 | targets.push(item); | ||
231 | } | ||
232 | }; | ||
233 | |||
234 | it.ty(db).walk(db, |t| { | ||
235 | if let Some(adt) = t.as_adt() { | ||
236 | push_new_def(adt.into()); | ||
237 | } else if let Some(trait_) = t.as_dyn_trait() { | ||
238 | push_new_def(trait_.into()); | ||
239 | } else if let Some(traits) = t.as_impl_traits(db) { | ||
240 | traits.into_iter().for_each(|it| push_new_def(it.into())); | ||
241 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { | ||
242 | push_new_def(trait_.into()); | ||
243 | } | ||
244 | }); | ||
245 | |||
246 | let targets = targets | ||
247 | .into_iter() | ||
248 | .filter_map(|it| { | ||
249 | Some(HoverGotoTypeData { | ||
250 | mod_path: render_path( | ||
251 | db, | ||
252 | it.module(db)?, | ||
253 | it.name(db).map(|name| name.to_string()), | ||
254 | ), | ||
255 | nav: it.try_to_nav(db)?, | ||
256 | }) | ||
257 | }) | ||
258 | .collect(); | ||
259 | |||
260 | Some(HoverAction::GoToType(targets)) | ||
261 | } | 215 | } |
262 | _ => None, | 216 | }; |
217 | |||
218 | if let Definition::GenericParam(GenericParam::TypeParam(it)) = def { | ||
219 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); | ||
220 | } else { | ||
221 | let ty = match def { | ||
222 | Definition::Local(it) => it.ty(db), | ||
223 | Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db), | ||
224 | _ => return None, | ||
225 | }; | ||
226 | |||
227 | ty.walk(db, |t| { | ||
228 | if let Some(adt) = t.as_adt() { | ||
229 | push_new_def(adt.into()); | ||
230 | } else if let Some(trait_) = t.as_dyn_trait() { | ||
231 | push_new_def(trait_.into()); | ||
232 | } else if let Some(traits) = t.as_impl_traits(db) { | ||
233 | traits.into_iter().for_each(|it| push_new_def(it.into())); | ||
234 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { | ||
235 | push_new_def(trait_.into()); | ||
236 | } | ||
237 | }); | ||
263 | } | 238 | } |
239 | |||
240 | let targets = targets | ||
241 | .into_iter() | ||
242 | .filter_map(|it| { | ||
243 | Some(HoverGotoTypeData { | ||
244 | mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())), | ||
245 | nav: it.try_to_nav(db)?, | ||
246 | }) | ||
247 | }) | ||
248 | .collect(); | ||
249 | |||
250 | Some(HoverAction::GoToType(targets)) | ||
264 | } | 251 | } |
265 | 252 | ||
266 | fn hover_markup( | 253 | fn hover_markup( |
@@ -324,17 +311,11 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
324 | let mod_path = definition_mod_path(db, &def); | 311 | let mod_path = definition_mod_path(db, &def); |
325 | return match def { | 312 | return match def { |
326 | Definition::Macro(it) => { | 313 | Definition::Macro(it) => { |
327 | // FIXME: Currently proc-macro do not have ast-node, | 314 | let label = macro_label(&it.source(db)?.value); |
328 | // such that it does not have source | ||
329 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
330 | if it.is_proc_macro() { | ||
331 | return None; | ||
332 | } | ||
333 | let label = macro_label(&it.source(db).value); | ||
334 | from_def_source_labeled(db, it, Some(label), mod_path) | 315 | from_def_source_labeled(db, it, Some(label), mod_path) |
335 | } | 316 | } |
336 | Definition::Field(def) => { | 317 | Definition::Field(def) => { |
337 | let src = def.source(db).value; | 318 | let src = def.source(db)?.value; |
338 | if let FieldSource::Named(it) = src { | 319 | if let FieldSource::Named(it) = src { |
339 | from_def_source_labeled(db, def, it.short_label(), mod_path) | 320 | from_def_source_labeled(db, def, it.short_label(), mod_path) |
340 | } else { | 321 | } else { |
@@ -360,9 +341,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
360 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), | 341 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), |
361 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), | 342 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), |
362 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), | 343 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
363 | ModuleDef::BuiltinType(it) => return Some(it.to_string().into()), | 344 | ModuleDef::BuiltinType(it) => Some(Markup::fenced_block(&it)), |
364 | }, | 345 | }, |
365 | Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))), | 346 | Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))), |
366 | Definition::SelfType(impl_def) => { | 347 | Definition::SelfType(impl_def) => { |
367 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { | 348 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { |
368 | Adt::Struct(it) => from_def_source(db, it, mod_path), | 349 | Adt::Struct(it) => from_def_source(db, it, mod_path), |
@@ -370,10 +351,12 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
370 | Adt::Enum(it) => from_def_source(db, it, mod_path), | 351 | Adt::Enum(it) => from_def_source(db, it, mod_path), |
371 | }) | 352 | }) |
372 | } | 353 | } |
373 | Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => { | 354 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
374 | // FIXME: Hover for generic param | 355 | Definition::GenericParam(it) => match it { |
375 | None | 356 | GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))), |
376 | } | 357 | GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), |
358 | GenericParam::ConstParam(it) => from_def_source(db, it, None), | ||
359 | }, | ||
377 | }; | 360 | }; |
378 | 361 | ||
379 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 362 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
@@ -381,7 +364,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
381 | D: HasSource<Ast = A> + HasAttrs + Copy, | 364 | D: HasSource<Ast = A> + HasAttrs + Copy, |
382 | A: ShortLabel, | 365 | A: ShortLabel, |
383 | { | 366 | { |
384 | let short_label = def.source(db).value.short_label(); | 367 | let short_label = def.source(db)?.value.short_label(); |
385 | from_def_source_labeled(db, def, short_label, mod_path) | 368 | from_def_source_labeled(db, def, short_label, mod_path) |
386 | } | 369 | } |
387 | 370 | ||
@@ -403,7 +386,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
403 | return tokens.max_by_key(priority); | 386 | return tokens.max_by_key(priority); |
404 | fn priority(n: &SyntaxToken) -> usize { | 387 | fn priority(n: &SyntaxToken) -> usize { |
405 | match n.kind() { | 388 | match n.kind() { |
406 | IDENT | INT_NUMBER => 3, | 389 | IDENT | INT_NUMBER | LIFETIME_IDENT => 3, |
407 | T!['('] | T![')'] => 2, | 390 | T!['('] | T![')'] => 2, |
408 | kind if kind.is_trivia() => 0, | 391 | kind if kind.is_trivia() => 0, |
409 | _ => 1, | 392 | _ => 1, |
@@ -471,7 +454,7 @@ mod tests { | |||
471 | pub fn foo() -> u32 { 1 } | 454 | pub fn foo() -> u32 { 1 } |
472 | 455 | ||
473 | fn main() { | 456 | fn main() { |
474 | let foo_test = foo()<|>; | 457 | let foo_test = foo()$0; |
475 | } | 458 | } |
476 | "#, | 459 | "#, |
477 | expect![[r#" | 460 | expect![[r#" |
@@ -490,7 +473,7 @@ fn main() { | |||
490 | pub fn foo() -> u32 { 1 } | 473 | pub fn foo() -> u32 { 1 } |
491 | 474 | ||
492 | fn main() { | 475 | fn main() { |
493 | let foo_test = foo()<|>; | 476 | let foo_test = foo()$0; |
494 | } | 477 | } |
495 | "#, | 478 | "#, |
496 | expect![[r#" | 479 | expect![[r#" |
@@ -520,7 +503,7 @@ fn main() { | |||
520 | Option::Some(*memo + value) | 503 | Option::Some(*memo + value) |
521 | }; | 504 | }; |
522 | let number = 5u32; | 505 | let number = 5u32; |
523 | let mut iter<|> = scan(OtherStruct { i: num }, closure, number); | 506 | let mut iter$0 = scan(OtherStruct { i: num }, closure, number); |
524 | } | 507 | } |
525 | "#, | 508 | "#, |
526 | expect![[r#" | 509 | expect![[r#" |
@@ -540,7 +523,7 @@ fn main() { | |||
540 | r#" | 523 | r#" |
541 | pub fn foo() -> u32 { 1 } | 524 | pub fn foo() -> u32 { 1 } |
542 | 525 | ||
543 | fn main() { let foo_test = fo<|>o(); } | 526 | fn main() { let foo_test = fo$0o(); } |
544 | "#, | 527 | "#, |
545 | expect![[r#" | 528 | expect![[r#" |
546 | *foo* | 529 | *foo* |
@@ -572,7 +555,7 @@ mod a; | |||
572 | mod b; | 555 | mod b; |
573 | mod c; | 556 | mod c; |
574 | 557 | ||
575 | fn main() { let foo_test = fo<|>o(); } | 558 | fn main() { let foo_test = fo$0o(); } |
576 | "#, | 559 | "#, |
577 | expect![[r#" | 560 | expect![[r#" |
578 | *foo* | 561 | *foo* |
@@ -589,7 +572,7 @@ fn main() { let foo_test = fo<|>o(); } | |||
589 | r#" | 572 | r#" |
590 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { } | 573 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { } |
591 | 574 | ||
592 | fn main() { let foo_test = fo<|>o(); } | 575 | fn main() { let foo_test = fo$0o(); } |
593 | "#, | 576 | "#, |
594 | expect![[r#" | 577 | expect![[r#" |
595 | *foo* | 578 | *foo* |
@@ -609,7 +592,7 @@ fn main() { let foo_test = fo<|>o(); } | |||
609 | fn hover_shows_fn_signature_on_fn_name() { | 592 | fn hover_shows_fn_signature_on_fn_name() { |
610 | check( | 593 | check( |
611 | r#" | 594 | r#" |
612 | pub fn foo<|>(a: u32, b: u32) -> u32 {} | 595 | pub fn foo$0(a: u32, b: u32) -> u32 {} |
613 | 596 | ||
614 | fn main() { } | 597 | fn main() { } |
615 | "#, | 598 | "#, |
@@ -637,7 +620,7 @@ fn main() { } | |||
637 | /// # | 620 | /// # |
638 | /// foo(Path::new("hello, world!")) | 621 | /// foo(Path::new("hello, world!")) |
639 | /// ``` | 622 | /// ``` |
640 | pub fn foo<|>(_: &Path) {} | 623 | pub fn foo$0(_: &Path) {} |
641 | 624 | ||
642 | fn main() { } | 625 | fn main() { } |
643 | "#, | 626 | "#, |
@@ -670,7 +653,7 @@ fn main() { } | |||
670 | check( | 653 | check( |
671 | r##" | 654 | r##" |
672 | #[doc = r#"Raw string doc attr"#] | 655 | #[doc = r#"Raw string doc attr"#] |
673 | pub fn foo<|>(_: &Path) {} | 656 | pub fn foo$0(_: &Path) {} |
674 | 657 | ||
675 | fn main() { } | 658 | fn main() { } |
676 | "##, | 659 | "##, |
@@ -700,7 +683,7 @@ fn main() { } | |||
700 | struct Foo { field_a: u32 } | 683 | struct Foo { field_a: u32 } |
701 | 684 | ||
702 | fn main() { | 685 | fn main() { |
703 | let foo = Foo { field_a<|>: 0, }; | 686 | let foo = Foo { field_a$0: 0, }; |
704 | } | 687 | } |
705 | "#, | 688 | "#, |
706 | expect![[r#" | 689 | expect![[r#" |
@@ -719,7 +702,7 @@ fn main() { | |||
719 | // Hovering over the field in the definition | 702 | // Hovering over the field in the definition |
720 | check( | 703 | check( |
721 | r#" | 704 | r#" |
722 | struct Foo { field_a<|>: u32 } | 705 | struct Foo { field_a$0: u32 } |
723 | 706 | ||
724 | fn main() { | 707 | fn main() { |
725 | let foo = Foo { field_a: 0 }; | 708 | let foo = Foo { field_a: 0 }; |
@@ -742,7 +725,7 @@ fn main() { | |||
742 | #[test] | 725 | #[test] |
743 | fn hover_const_static() { | 726 | fn hover_const_static() { |
744 | check( | 727 | check( |
745 | r#"const foo<|>: u32 = 123;"#, | 728 | r#"const foo$0: u32 = 123;"#, |
746 | expect![[r#" | 729 | expect![[r#" |
747 | *foo* | 730 | *foo* |
748 | 731 | ||
@@ -756,7 +739,7 @@ fn main() { | |||
756 | "#]], | 739 | "#]], |
757 | ); | 740 | ); |
758 | check( | 741 | check( |
759 | r#"static foo<|>: u32 = 456;"#, | 742 | r#"static foo$0: u32 = 456;"#, |
760 | expect![[r#" | 743 | expect![[r#" |
761 | *foo* | 744 | *foo* |
762 | 745 | ||
@@ -778,7 +761,7 @@ fn main() { | |||
778 | struct Test<K, T = u8> { k: K, t: T } | 761 | struct Test<K, T = u8> { k: K, t: T } |
779 | 762 | ||
780 | fn main() { | 763 | fn main() { |
781 | let zz<|> = Test { t: 23u8, k: 33 }; | 764 | let zz$0 = Test { t: 23u8, k: 33 }; |
782 | }"#, | 765 | }"#, |
783 | expect![[r#" | 766 | expect![[r#" |
784 | *zz* | 767 | *zz* |
@@ -797,7 +780,7 @@ fn main() { | |||
797 | enum Option<T> { Some(T) } | 780 | enum Option<T> { Some(T) } |
798 | use Option::Some; | 781 | use Option::Some; |
799 | 782 | ||
800 | fn main() { So<|>me(12); } | 783 | fn main() { So$0me(12); } |
801 | "#, | 784 | "#, |
802 | expect![[r#" | 785 | expect![[r#" |
803 | *Some* | 786 | *Some* |
@@ -817,7 +800,7 @@ fn main() { So<|>me(12); } | |||
817 | enum Option<T> { Some(T) } | 800 | enum Option<T> { Some(T) } |
818 | use Option::Some; | 801 | use Option::Some; |
819 | 802 | ||
820 | fn main() { let b<|>ar = Some(12); } | 803 | fn main() { let b$0ar = Some(12); } |
821 | "#, | 804 | "#, |
822 | expect![[r#" | 805 | expect![[r#" |
823 | *bar* | 806 | *bar* |
@@ -835,7 +818,7 @@ fn main() { let b<|>ar = Some(12); } | |||
835 | r#" | 818 | r#" |
836 | enum Option<T> { | 819 | enum Option<T> { |
837 | /// The None variant | 820 | /// The None variant |
838 | Non<|>e | 821 | Non$0e |
839 | } | 822 | } |
840 | "#, | 823 | "#, |
841 | expect![[r#" | 824 | expect![[r#" |
@@ -862,7 +845,7 @@ enum Option<T> { | |||
862 | Some(T) | 845 | Some(T) |
863 | } | 846 | } |
864 | fn main() { | 847 | fn main() { |
865 | let s = Option::Som<|>e(12); | 848 | let s = Option::Som$0e(12); |
866 | } | 849 | } |
867 | "#, | 850 | "#, |
868 | expect![[r#" | 851 | expect![[r#" |
@@ -886,7 +869,7 @@ fn main() { | |||
886 | #[test] | 869 | #[test] |
887 | fn hover_for_local_variable() { | 870 | fn hover_for_local_variable() { |
888 | check( | 871 | check( |
889 | r#"fn func(foo: i32) { fo<|>o; }"#, | 872 | r#"fn func(foo: i32) { fo$0o; }"#, |
890 | expect![[r#" | 873 | expect![[r#" |
891 | *foo* | 874 | *foo* |
892 | 875 | ||
@@ -900,7 +883,7 @@ fn main() { | |||
900 | #[test] | 883 | #[test] |
901 | fn hover_for_local_variable_pat() { | 884 | fn hover_for_local_variable_pat() { |
902 | check( | 885 | check( |
903 | r#"fn func(fo<|>o: i32) {}"#, | 886 | r#"fn func(fo$0o: i32) {}"#, |
904 | expect![[r#" | 887 | expect![[r#" |
905 | *foo* | 888 | *foo* |
906 | 889 | ||
@@ -914,7 +897,7 @@ fn main() { | |||
914 | #[test] | 897 | #[test] |
915 | fn hover_local_var_edge() { | 898 | fn hover_local_var_edge() { |
916 | check( | 899 | check( |
917 | r#"fn func(foo: i32) { if true { <|>foo; }; }"#, | 900 | r#"fn func(foo: i32) { if true { $0foo; }; }"#, |
918 | expect![[r#" | 901 | expect![[r#" |
919 | *foo* | 902 | *foo* |
920 | 903 | ||
@@ -928,7 +911,7 @@ fn main() { | |||
928 | #[test] | 911 | #[test] |
929 | fn hover_for_param_edge() { | 912 | fn hover_for_param_edge() { |
930 | check( | 913 | check( |
931 | r#"fn func(<|>foo: i32) {}"#, | 914 | r#"fn func($0foo: i32) {}"#, |
932 | expect![[r#" | 915 | expect![[r#" |
933 | *foo* | 916 | *foo* |
934 | 917 | ||
@@ -948,7 +931,7 @@ fn main() { | |||
948 | trait DerefMut { | 931 | trait DerefMut { |
949 | type Target: ?Sized; | 932 | type Target: ?Sized; |
950 | } | 933 | } |
951 | fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#, | 934 | fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#, |
952 | expect![[r#" | 935 | expect![[r#" |
953 | *_x* | 936 | *_x* |
954 | 937 | ||
@@ -969,7 +952,7 @@ impl Thing { | |||
969 | fn new() -> Thing { Thing { x: 0 } } | 952 | fn new() -> Thing { Thing { x: 0 } } |
970 | } | 953 | } |
971 | 954 | ||
972 | fn main() { let foo_<|>test = Thing::new(); } | 955 | fn main() { let foo_$0test = Thing::new(); } |
973 | "#, | 956 | "#, |
974 | expect![[r#" | 957 | expect![[r#" |
975 | *foo_test* | 958 | *foo_test* |
@@ -993,7 +976,7 @@ mod wrapper { | |||
993 | } | 976 | } |
994 | } | 977 | } |
995 | 978 | ||
996 | fn main() { let foo_test = wrapper::Thing::new<|>(); } | 979 | fn main() { let foo_test = wrapper::Thing::new$0(); } |
997 | "#, | 980 | "#, |
998 | expect![[r#" | 981 | expect![[r#" |
999 | *new* | 982 | *new* |
@@ -1020,7 +1003,7 @@ impl X { | |||
1020 | 1003 | ||
1021 | fn main() { | 1004 | fn main() { |
1022 | match 1 { | 1005 | match 1 { |
1023 | X::C<|> => {}, | 1006 | X::C$0 => {}, |
1024 | 2 => {}, | 1007 | 2 => {}, |
1025 | _ => {} | 1008 | _ => {} |
1026 | }; | 1009 | }; |
@@ -1046,7 +1029,7 @@ fn main() { | |||
1046 | r#" | 1029 | r#" |
1047 | struct Thing { x: u32 } | 1030 | struct Thing { x: u32 } |
1048 | impl Thing { | 1031 | impl Thing { |
1049 | fn new() -> Self { Self<|> { x: 0 } } | 1032 | fn new() -> Self { Self$0 { x: 0 } } |
1050 | } | 1033 | } |
1051 | "#, | 1034 | "#, |
1052 | expect![[r#" | 1035 | expect![[r#" |
@@ -1065,7 +1048,7 @@ impl Thing { | |||
1065 | r#" | 1048 | r#" |
1066 | struct Thing { x: u32 } | 1049 | struct Thing { x: u32 } |
1067 | impl Thing { | 1050 | impl Thing { |
1068 | fn new() -> Self<|> { Self { x: 0 } } | 1051 | fn new() -> Self$0 { Self { x: 0 } } |
1069 | } | 1052 | } |
1070 | "#, | 1053 | "#, |
1071 | expect![[r#" | 1054 | expect![[r#" |
@@ -1084,7 +1067,7 @@ impl Thing { | |||
1084 | r#" | 1067 | r#" |
1085 | enum Thing { A } | 1068 | enum Thing { A } |
1086 | impl Thing { | 1069 | impl Thing { |
1087 | pub fn new() -> Self<|> { Thing::A } | 1070 | pub fn new() -> Self$0 { Thing::A } |
1088 | } | 1071 | } |
1089 | "#, | 1072 | "#, |
1090 | expect![[r#" | 1073 | expect![[r#" |
@@ -1103,7 +1086,7 @@ impl Thing { | |||
1103 | r#" | 1086 | r#" |
1104 | enum Thing { A } | 1087 | enum Thing { A } |
1105 | impl Thing { | 1088 | impl Thing { |
1106 | pub fn thing(a: Self<|>) {} | 1089 | pub fn thing(a: Self$0) {} |
1107 | } | 1090 | } |
1108 | "#, | 1091 | "#, |
1109 | expect![[r#" | 1092 | expect![[r#" |
@@ -1128,7 +1111,7 @@ fn x() {} | |||
1128 | 1111 | ||
1129 | fn y() { | 1112 | fn y() { |
1130 | let x = 0i32; | 1113 | let x = 0i32; |
1131 | x<|>; | 1114 | x$0; |
1132 | } | 1115 | } |
1133 | "#, | 1116 | "#, |
1134 | expect![[r#" | 1117 | expect![[r#" |
@@ -1147,7 +1130,7 @@ fn y() { | |||
1147 | r#" | 1130 | r#" |
1148 | macro_rules! foo { () => {} } | 1131 | macro_rules! foo { () => {} } |
1149 | 1132 | ||
1150 | fn f() { fo<|>o!(); } | 1133 | fn f() { fo$0o!(); } |
1151 | "#, | 1134 | "#, |
1152 | expect![[r#" | 1135 | expect![[r#" |
1153 | *foo* | 1136 | *foo* |
@@ -1166,10 +1149,13 @@ fn f() { fo<|>o!(); } | |||
1166 | #[test] | 1149 | #[test] |
1167 | fn test_hover_tuple_field() { | 1150 | fn test_hover_tuple_field() { |
1168 | check( | 1151 | check( |
1169 | r#"struct TS(String, i32<|>);"#, | 1152 | r#"struct TS(String, i32$0);"#, |
1170 | expect![[r#" | 1153 | expect![[r#" |
1171 | *i32* | 1154 | *i32* |
1155 | |||
1156 | ```rust | ||
1172 | i32 | 1157 | i32 |
1158 | ``` | ||
1173 | "#]], | 1159 | "#]], |
1174 | ) | 1160 | ) |
1175 | } | 1161 | } |
@@ -1181,7 +1167,7 @@ fn f() { fo<|>o!(); } | |||
1181 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | 1167 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
1182 | fn foo() {} | 1168 | fn foo() {} |
1183 | id! { | 1169 | id! { |
1184 | fn bar() { fo<|>o(); } | 1170 | fn bar() { fo$0o(); } |
1185 | } | 1171 | } |
1186 | "#, | 1172 | "#, |
1187 | expect![[r#" | 1173 | expect![[r#" |
@@ -1203,7 +1189,7 @@ id! { | |||
1203 | check( | 1189 | check( |
1204 | r#" | 1190 | r#" |
1205 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | 1191 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
1206 | fn foo(bar:u32) { let a = id!(ba<|>r); } | 1192 | fn foo(bar:u32) { let a = id!(ba$0r); } |
1207 | "#, | 1193 | "#, |
1208 | expect![[r#" | 1194 | expect![[r#" |
1209 | *bar* | 1195 | *bar* |
@@ -1221,7 +1207,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); } | |||
1221 | r#" | 1207 | r#" |
1222 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } | 1208 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } |
1223 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } | 1209 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } |
1224 | fn foo(bar:u32) { let a = id!(ba<|>r); } | 1210 | fn foo(bar:u32) { let a = id!(ba$0r); } |
1225 | "#, | 1211 | "#, |
1226 | expect![[r#" | 1212 | expect![[r#" |
1227 | *bar* | 1213 | *bar* |
@@ -1240,7 +1226,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); } | |||
1240 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } | 1226 | macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } |
1241 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } | 1227 | macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } |
1242 | fn bar() -> u32 { 0 } | 1228 | fn bar() -> u32 { 0 } |
1243 | fn foo() { let a = id!([0u32, bar(<|>)] ); } | 1229 | fn foo() { let a = id!([0u32, bar($0)] ); } |
1244 | "#, | 1230 | "#, |
1245 | expect![[r#" | 1231 | expect![[r#" |
1246 | *bar()* | 1232 | *bar()* |
@@ -1258,7 +1244,7 @@ fn foo() { let a = id!([0u32, bar(<|>)] ); } | |||
1258 | macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } } | 1244 | macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } } |
1259 | fn foo() { | 1245 | fn foo() { |
1260 | let mastered_for_itunes = ""; | 1246 | let mastered_for_itunes = ""; |
1261 | let _ = arr!("Tr<|>acks", &mastered_for_itunes); | 1247 | let _ = arr!("Tr$0acks", &mastered_for_itunes); |
1262 | } | 1248 | } |
1263 | "#, | 1249 | "#, |
1264 | expect![[r#" | 1250 | expect![[r#" |
@@ -1279,7 +1265,7 @@ macro_rules! assert {} | |||
1279 | 1265 | ||
1280 | fn bar() -> bool { true } | 1266 | fn bar() -> bool { true } |
1281 | fn foo() { | 1267 | fn foo() { |
1282 | assert!(ba<|>r()); | 1268 | assert!(ba$0r()); |
1283 | } | 1269 | } |
1284 | "#, | 1270 | "#, |
1285 | expect![[r#" | 1271 | expect![[r#" |
@@ -1304,7 +1290,7 @@ fn foo() { | |||
1304 | macro_rules! format {} | 1290 | macro_rules! format {} |
1305 | 1291 | ||
1306 | fn foo() { | 1292 | fn foo() { |
1307 | format!("hel<|>lo {}", 0); | 1293 | format!("hel$0lo {}", 0); |
1308 | } | 1294 | } |
1309 | "#, | 1295 | "#, |
1310 | ); | 1296 | ); |
@@ -1317,7 +1303,7 @@ fn foo() { | |||
1317 | /// <- `\u{3000}` here | 1303 | /// <- `\u{3000}` here |
1318 | fn foo() { } | 1304 | fn foo() { } |
1319 | 1305 | ||
1320 | fn bar() { fo<|>o(); } | 1306 | fn bar() { fo$0o(); } |
1321 | ", | 1307 | ", |
1322 | expect![[r#" | 1308 | expect![[r#" |
1323 | *foo* | 1309 | *foo* |
@@ -1340,7 +1326,7 @@ fn bar() { fo<|>o(); } | |||
1340 | #[test] | 1326 | #[test] |
1341 | fn test_hover_function_show_qualifiers() { | 1327 | fn test_hover_function_show_qualifiers() { |
1342 | check( | 1328 | check( |
1343 | r#"async fn foo<|>() {}"#, | 1329 | r#"async fn foo$0() {}"#, |
1344 | expect![[r#" | 1330 | expect![[r#" |
1345 | *foo* | 1331 | *foo* |
1346 | 1332 | ||
@@ -1354,7 +1340,7 @@ fn bar() { fo<|>o(); } | |||
1354 | "#]], | 1340 | "#]], |
1355 | ); | 1341 | ); |
1356 | check( | 1342 | check( |
1357 | r#"pub const unsafe fn foo<|>() {}"#, | 1343 | r#"pub const unsafe fn foo$0() {}"#, |
1358 | expect![[r#" | 1344 | expect![[r#" |
1359 | *foo* | 1345 | *foo* |
1360 | 1346 | ||
@@ -1368,7 +1354,7 @@ fn bar() { fo<|>o(); } | |||
1368 | "#]], | 1354 | "#]], |
1369 | ); | 1355 | ); |
1370 | check( | 1356 | check( |
1371 | r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#, | 1357 | r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#, |
1372 | expect![[r#" | 1358 | expect![[r#" |
1373 | *foo* | 1359 | *foo* |
1374 | 1360 | ||
@@ -1386,10 +1372,10 @@ fn bar() { fo<|>o(); } | |||
1386 | #[test] | 1372 | #[test] |
1387 | fn test_hover_trait_show_qualifiers() { | 1373 | fn test_hover_trait_show_qualifiers() { |
1388 | check_actions( | 1374 | check_actions( |
1389 | r"unsafe trait foo<|>() {}", | 1375 | r"unsafe trait foo$0() {}", |
1390 | expect![[r#" | 1376 | expect![[r#" |
1391 | [ | 1377 | [ |
1392 | Implementaion( | 1378 | Implementation( |
1393 | FilePosition { | 1379 | FilePosition { |
1394 | file_id: FileId( | 1380 | file_id: FileId( |
1395 | 0, | 1381 | 0, |
@@ -1407,7 +1393,7 @@ fn bar() { fo<|>o(); } | |||
1407 | check( | 1393 | check( |
1408 | r#" | 1394 | r#" |
1409 | //- /main.rs crate:main deps:std | 1395 | //- /main.rs crate:main deps:std |
1410 | extern crate st<|>d; | 1396 | extern crate st$0d; |
1411 | //- /std/lib.rs crate:std | 1397 | //- /std/lib.rs crate:std |
1412 | //! Standard library for this test | 1398 | //! Standard library for this test |
1413 | //! | 1399 | //! |
@@ -1425,7 +1411,7 @@ extern crate st<|>d; | |||
1425 | check( | 1411 | check( |
1426 | r#" | 1412 | r#" |
1427 | //- /main.rs crate:main deps:std | 1413 | //- /main.rs crate:main deps:std |
1428 | extern crate std as ab<|>c; | 1414 | extern crate std as ab$0c; |
1429 | //- /std/lib.rs crate:std | 1415 | //- /std/lib.rs crate:std |
1430 | //! Standard library for this test | 1416 | //! Standard library for this test |
1431 | //! | 1417 | //! |
@@ -1446,7 +1432,7 @@ extern crate std as ab<|>c; | |||
1446 | fn test_hover_mod_with_same_name_as_function() { | 1432 | fn test_hover_mod_with_same_name_as_function() { |
1447 | check( | 1433 | check( |
1448 | r#" | 1434 | r#" |
1449 | use self::m<|>y::Bar; | 1435 | use self::m$0y::Bar; |
1450 | mod my { pub struct Bar; } | 1436 | mod my { pub struct Bar; } |
1451 | 1437 | ||
1452 | fn my() {} | 1438 | fn my() {} |
@@ -1472,7 +1458,7 @@ fn my() {} | |||
1472 | /// bar docs | 1458 | /// bar docs |
1473 | struct Bar; | 1459 | struct Bar; |
1474 | 1460 | ||
1475 | fn foo() { let bar = Ba<|>r; } | 1461 | fn foo() { let bar = Ba$0r; } |
1476 | "#, | 1462 | "#, |
1477 | expect![[r#" | 1463 | expect![[r#" |
1478 | *Bar* | 1464 | *Bar* |
@@ -1499,7 +1485,7 @@ fn foo() { let bar = Ba<|>r; } | |||
1499 | #[doc = "bar docs"] | 1485 | #[doc = "bar docs"] |
1500 | struct Bar; | 1486 | struct Bar; |
1501 | 1487 | ||
1502 | fn foo() { let bar = Ba<|>r; } | 1488 | fn foo() { let bar = Ba$0r; } |
1503 | "#, | 1489 | "#, |
1504 | expect![[r#" | 1490 | expect![[r#" |
1505 | *Bar* | 1491 | *Bar* |
@@ -1528,7 +1514,7 @@ fn foo() { let bar = Ba<|>r; } | |||
1528 | #[doc = "bar docs 2"] | 1514 | #[doc = "bar docs 2"] |
1529 | struct Bar; | 1515 | struct Bar; |
1530 | 1516 | ||
1531 | fn foo() { let bar = Ba<|>r; } | 1517 | fn foo() { let bar = Ba$0r; } |
1532 | "#, | 1518 | "#, |
1533 | expect![[r#" | 1519 | expect![[r#" |
1534 | *Bar* | 1520 | *Bar* |
@@ -1556,7 +1542,7 @@ fn foo() { let bar = Ba<|>r; } | |||
1556 | r#" | 1542 | r#" |
1557 | pub struct Foo; | 1543 | pub struct Foo; |
1558 | /// [Foo](struct.Foo.html) | 1544 | /// [Foo](struct.Foo.html) |
1559 | pub struct B<|>ar | 1545 | pub struct B$0ar |
1560 | "#, | 1546 | "#, |
1561 | expect![[r#" | 1547 | expect![[r#" |
1562 | *Bar* | 1548 | *Bar* |
@@ -1582,7 +1568,7 @@ pub struct B<|>ar | |||
1582 | r#" | 1568 | r#" |
1583 | pub struct Foo; | 1569 | pub struct Foo; |
1584 | /// [struct Foo](struct.Foo.html) | 1570 | /// [struct Foo](struct.Foo.html) |
1585 | pub struct B<|>ar | 1571 | pub struct B$0ar |
1586 | "#, | 1572 | "#, |
1587 | expect![[r#" | 1573 | expect![[r#" |
1588 | *Bar* | 1574 | *Bar* |
@@ -1610,7 +1596,7 @@ pub struct B<|>ar | |||
1610 | pub struct Foo; | 1596 | pub struct Foo; |
1611 | pub struct Bar { | 1597 | pub struct Bar { |
1612 | /// [Foo](struct.Foo.html) | 1598 | /// [Foo](struct.Foo.html) |
1613 | fie<|>ld: () | 1599 | fie$0ld: () |
1614 | } | 1600 | } |
1615 | "#, | 1601 | "#, |
1616 | expect![[r#" | 1602 | expect![[r#" |
@@ -1639,7 +1625,7 @@ pub mod foo { | |||
1639 | pub struct Foo; | 1625 | pub struct Foo; |
1640 | } | 1626 | } |
1641 | /// [Foo](foo::Foo) | 1627 | /// [Foo](foo::Foo) |
1642 | pub struct B<|>ar | 1628 | pub struct B$0ar |
1643 | "#, | 1629 | "#, |
1644 | expect![[r#" | 1630 | expect![[r#" |
1645 | *Bar* | 1631 | *Bar* |
@@ -1669,7 +1655,7 @@ pub mod foo { | |||
1669 | pub struct Foo; | 1655 | pub struct Foo; |
1670 | } | 1656 | } |
1671 | /// [Foo](foo::Foo) | 1657 | /// [Foo](foo::Foo) |
1672 | pub struct B<|>ar | 1658 | pub struct B$0ar |
1673 | "#, | 1659 | "#, |
1674 | expect![[r#" | 1660 | expect![[r#" |
1675 | *Bar* | 1661 | *Bar* |
@@ -1695,7 +1681,7 @@ pub struct B<|>ar | |||
1695 | r#" | 1681 | r#" |
1696 | pub struct Foo; | 1682 | pub struct Foo; |
1697 | /// [Foo] | 1683 | /// [Foo] |
1698 | pub struct B<|>ar | 1684 | pub struct B$0ar |
1699 | "#, | 1685 | "#, |
1700 | expect![[r#" | 1686 | expect![[r#" |
1701 | *Bar* | 1687 | *Bar* |
@@ -1721,7 +1707,7 @@ pub struct B<|>ar | |||
1721 | r#" | 1707 | r#" |
1722 | pub struct Foo; | 1708 | pub struct Foo; |
1723 | /// [`Foo`] | 1709 | /// [`Foo`] |
1724 | pub struct B<|>ar | 1710 | pub struct B$0ar |
1725 | "#, | 1711 | "#, |
1726 | expect![[r#" | 1712 | expect![[r#" |
1727 | *Bar* | 1713 | *Bar* |
@@ -1748,7 +1734,7 @@ pub struct B<|>ar | |||
1748 | pub struct Foo; | 1734 | pub struct Foo; |
1749 | fn Foo() {} | 1735 | fn Foo() {} |
1750 | /// [Foo()] | 1736 | /// [Foo()] |
1751 | pub struct B<|>ar | 1737 | pub struct B$0ar |
1752 | "#, | 1738 | "#, |
1753 | expect![[r#" | 1739 | expect![[r#" |
1754 | *Bar* | 1740 | *Bar* |
@@ -1774,7 +1760,7 @@ pub struct B<|>ar | |||
1774 | r#" | 1760 | r#" |
1775 | pub struct Foo; | 1761 | pub struct Foo; |
1776 | /// [`struct Foo`] | 1762 | /// [`struct Foo`] |
1777 | pub struct B<|>ar | 1763 | pub struct B$0ar |
1778 | "#, | 1764 | "#, |
1779 | expect![[r#" | 1765 | expect![[r#" |
1780 | *Bar* | 1766 | *Bar* |
@@ -1800,7 +1786,7 @@ pub struct B<|>ar | |||
1800 | r#" | 1786 | r#" |
1801 | pub struct Foo; | 1787 | pub struct Foo; |
1802 | /// [`struct@Foo`] | 1788 | /// [`struct@Foo`] |
1803 | pub struct B<|>ar | 1789 | pub struct B$0ar |
1804 | "#, | 1790 | "#, |
1805 | expect![[r#" | 1791 | expect![[r#" |
1806 | *Bar* | 1792 | *Bar* |
@@ -1828,7 +1814,7 @@ pub struct Foo; | |||
1828 | /// [my Foo][foo] | 1814 | /// [my Foo][foo] |
1829 | /// | 1815 | /// |
1830 | /// [foo]: Foo | 1816 | /// [foo]: Foo |
1831 | pub struct B<|>ar | 1817 | pub struct B$0ar |
1832 | "#, | 1818 | "#, |
1833 | expect![[r#" | 1819 | expect![[r#" |
1834 | *Bar* | 1820 | *Bar* |
@@ -1854,7 +1840,7 @@ pub struct B<|>ar | |||
1854 | r#" | 1840 | r#" |
1855 | pub struct Foo; | 1841 | pub struct Foo; |
1856 | /// [external](https://www.google.com) | 1842 | /// [external](https://www.google.com) |
1857 | pub struct B<|>ar | 1843 | pub struct B$0ar |
1858 | "#, | 1844 | "#, |
1859 | expect![[r#" | 1845 | expect![[r#" |
1860 | *Bar* | 1846 | *Bar* |
@@ -1881,7 +1867,7 @@ pub struct B<|>ar | |||
1881 | r#" | 1867 | r#" |
1882 | pub struct Foo; | 1868 | pub struct Foo; |
1883 | /// [baz](Baz) | 1869 | /// [baz](Baz) |
1884 | pub struct B<|>ar | 1870 | pub struct B$0ar |
1885 | "#, | 1871 | "#, |
1886 | expect![[r#" | 1872 | expect![[r#" |
1887 | *Bar* | 1873 | *Bar* |
@@ -1907,7 +1893,7 @@ pub struct B<|>ar | |||
1907 | r#" | 1893 | r#" |
1908 | enum E { | 1894 | enum E { |
1909 | /// [E] | 1895 | /// [E] |
1910 | V<|> { field: i32 } | 1896 | V$0 { field: i32 } |
1911 | } | 1897 | } |
1912 | "#, | 1898 | "#, |
1913 | expect![[r#" | 1899 | expect![[r#" |
@@ -1934,7 +1920,7 @@ enum E { | |||
1934 | r#" | 1920 | r#" |
1935 | struct S { | 1921 | struct S { |
1936 | /// [`S`] | 1922 | /// [`S`] |
1937 | field<|>: i32 | 1923 | field$0: i32 |
1938 | } | 1924 | } |
1939 | "#, | 1925 | "#, |
1940 | expect![[r#" | 1926 | expect![[r#" |
@@ -1962,16 +1948,16 @@ struct S { | |||
1962 | /// Test cases: | 1948 | /// Test cases: |
1963 | /// case 1. bare URL: https://www.example.com/ | 1949 | /// case 1. bare URL: https://www.example.com/ |
1964 | /// case 2. inline URL with title: [example](https://www.example.com/) | 1950 | /// case 2. inline URL with title: [example](https://www.example.com/) |
1965 | /// case 3. code refrence: [`Result`] | 1951 | /// case 3. code reference: [`Result`] |
1966 | /// case 4. code refrence but miss footnote: [`String`] | 1952 | /// case 4. code reference but miss footnote: [`String`] |
1967 | /// case 5. autolink: <http://www.example.com/> | 1953 | /// case 5. autolink: <http://www.example.com/> |
1968 | /// case 6. email address: <[email protected]> | 1954 | /// case 6. email address: <[email protected]> |
1969 | /// case 7. refrence: [example][example] | 1955 | /// case 7. reference: [example][example] |
1970 | /// case 8. collapsed link: [example][] | 1956 | /// case 8. collapsed link: [example][] |
1971 | /// case 9. shortcut link: [example] | 1957 | /// case 9. shortcut link: [example] |
1972 | /// case 10. inline without URL: [example]() | 1958 | /// case 10. inline without URL: [example]() |
1973 | /// case 11. refrence: [foo][foo] | 1959 | /// case 11. reference: [foo][foo] |
1974 | /// case 12. refrence: [foo][bar] | 1960 | /// case 12. reference: [foo][bar] |
1975 | /// case 13. collapsed link: [foo][] | 1961 | /// case 13. collapsed link: [foo][] |
1976 | /// case 14. shortcut link: [foo] | 1962 | /// case 14. shortcut link: [foo] |
1977 | /// case 15. inline without URL: [foo]() | 1963 | /// case 15. inline without URL: [foo]() |
@@ -1980,7 +1966,7 @@ struct S { | |||
1980 | /// | 1966 | /// |
1981 | /// [`Result`]: ../../std/result/enum.Result.html | 1967 | /// [`Result`]: ../../std/result/enum.Result.html |
1982 | /// [^example]: https://www.example.com/ | 1968 | /// [^example]: https://www.example.com/ |
1983 | pub fn fo<|>o() {} | 1969 | pub fn fo$0o() {} |
1984 | "#, | 1970 | "#, |
1985 | expect![[r#" | 1971 | expect![[r#" |
1986 | *foo* | 1972 | *foo* |
@@ -1998,16 +1984,16 @@ pub fn fo<|>o() {} | |||
1998 | Test cases: | 1984 | Test cases: |
1999 | case 1. bare URL: https://www.example.com/ | 1985 | case 1. bare URL: https://www.example.com/ |
2000 | case 2. inline URL with title: [example](https://www.example.com/) | 1986 | case 2. inline URL with title: [example](https://www.example.com/) |
2001 | case 3. code refrence: `Result` | 1987 | case 3. code reference: `Result` |
2002 | case 4. code refrence but miss footnote: `String` | 1988 | case 4. code reference but miss footnote: `String` |
2003 | case 5. autolink: http://www.example.com/ | 1989 | case 5. autolink: http://www.example.com/ |
2004 | case 6. email address: [email protected] | 1990 | case 6. email address: [email protected] |
2005 | case 7. refrence: example | 1991 | case 7. reference: example |
2006 | case 8. collapsed link: example | 1992 | case 8. collapsed link: example |
2007 | case 9. shortcut link: example | 1993 | case 9. shortcut link: example |
2008 | case 10. inline without URL: example | 1994 | case 10. inline without URL: example |
2009 | case 11. refrence: foo | 1995 | case 11. reference: foo |
2010 | case 12. refrence: foo | 1996 | case 12. reference: foo |
2011 | case 13. collapsed link: foo | 1997 | case 13. collapsed link: foo |
2012 | case 14. shortcut link: foo | 1998 | case 14. shortcut link: foo |
2013 | case 15. inline without URL: foo | 1999 | case 15. inline without URL: foo |
@@ -2037,7 +2023,7 @@ macro_rules! bar { | |||
2037 | 2023 | ||
2038 | bar!(); | 2024 | bar!(); |
2039 | 2025 | ||
2040 | fn foo() { let bar = Bar; bar.fo<|>o(); } | 2026 | fn foo() { let bar = Bar; bar.fo$0o(); } |
2041 | "#, | 2027 | "#, |
2042 | expect![[r#" | 2028 | expect![[r#" |
2043 | *foo* | 2029 | *foo* |
@@ -2075,7 +2061,7 @@ macro_rules! bar { | |||
2075 | 2061 | ||
2076 | bar!(); | 2062 | bar!(); |
2077 | 2063 | ||
2078 | fn foo() { let bar = Bar; bar.fo<|>o(); } | 2064 | fn foo() { let bar = Bar; bar.fo$0o(); } |
2079 | "#, | 2065 | "#, |
2080 | expect![[r#" | 2066 | expect![[r#" |
2081 | *foo* | 2067 | *foo* |
@@ -2098,10 +2084,10 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2098 | #[test] | 2084 | #[test] |
2099 | fn test_hover_trait_has_impl_action() { | 2085 | fn test_hover_trait_has_impl_action() { |
2100 | check_actions( | 2086 | check_actions( |
2101 | r#"trait foo<|>() {}"#, | 2087 | r#"trait foo$0() {}"#, |
2102 | expect![[r#" | 2088 | expect![[r#" |
2103 | [ | 2089 | [ |
2104 | Implementaion( | 2090 | Implementation( |
2105 | FilePosition { | 2091 | FilePosition { |
2106 | file_id: FileId( | 2092 | file_id: FileId( |
2107 | 0, | 2093 | 0, |
@@ -2117,10 +2103,10 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2117 | #[test] | 2103 | #[test] |
2118 | fn test_hover_struct_has_impl_action() { | 2104 | fn test_hover_struct_has_impl_action() { |
2119 | check_actions( | 2105 | check_actions( |
2120 | r"struct foo<|>() {}", | 2106 | r"struct foo$0() {}", |
2121 | expect![[r#" | 2107 | expect![[r#" |
2122 | [ | 2108 | [ |
2123 | Implementaion( | 2109 | Implementation( |
2124 | FilePosition { | 2110 | FilePosition { |
2125 | file_id: FileId( | 2111 | file_id: FileId( |
2126 | 0, | 2112 | 0, |
@@ -2136,10 +2122,10 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2136 | #[test] | 2122 | #[test] |
2137 | fn test_hover_union_has_impl_action() { | 2123 | fn test_hover_union_has_impl_action() { |
2138 | check_actions( | 2124 | check_actions( |
2139 | r#"union foo<|>() {}"#, | 2125 | r#"union foo$0() {}"#, |
2140 | expect![[r#" | 2126 | expect![[r#" |
2141 | [ | 2127 | [ |
2142 | Implementaion( | 2128 | Implementation( |
2143 | FilePosition { | 2129 | FilePosition { |
2144 | file_id: FileId( | 2130 | file_id: FileId( |
2145 | 0, | 2131 | 0, |
@@ -2155,10 +2141,10 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2155 | #[test] | 2141 | #[test] |
2156 | fn test_hover_enum_has_impl_action() { | 2142 | fn test_hover_enum_has_impl_action() { |
2157 | check_actions( | 2143 | check_actions( |
2158 | r"enum foo<|>() { A, B }", | 2144 | r"enum foo$0() { A, B }", |
2159 | expect![[r#" | 2145 | expect![[r#" |
2160 | [ | 2146 | [ |
2161 | Implementaion( | 2147 | Implementation( |
2162 | FilePosition { | 2148 | FilePosition { |
2163 | file_id: FileId( | 2149 | file_id: FileId( |
2164 | 0, | 2150 | 0, |
@@ -2172,11 +2158,30 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2172 | } | 2158 | } |
2173 | 2159 | ||
2174 | #[test] | 2160 | #[test] |
2161 | fn test_hover_self_has_impl_action() { | ||
2162 | check_actions( | ||
2163 | r#"struct foo where Self$0:;"#, | ||
2164 | expect![[r#" | ||
2165 | [ | ||
2166 | Implementation( | ||
2167 | FilePosition { | ||
2168 | file_id: FileId( | ||
2169 | 0, | ||
2170 | ), | ||
2171 | offset: 7, | ||
2172 | }, | ||
2173 | ), | ||
2174 | ] | ||
2175 | "#]], | ||
2176 | ); | ||
2177 | } | ||
2178 | |||
2179 | #[test] | ||
2175 | fn test_hover_test_has_action() { | 2180 | fn test_hover_test_has_action() { |
2176 | check_actions( | 2181 | check_actions( |
2177 | r#" | 2182 | r#" |
2178 | #[test] | 2183 | #[test] |
2179 | fn foo_<|>test() {} | 2184 | fn foo_$0test() {} |
2180 | "#, | 2185 | "#, |
2181 | expect![[r#" | 2186 | expect![[r#" |
2182 | [ | 2187 | [ |
@@ -2211,7 +2216,7 @@ fn foo_<|>test() {} | |||
2211 | fn test_hover_test_mod_has_action() { | 2216 | fn test_hover_test_mod_has_action() { |
2212 | check_actions( | 2217 | check_actions( |
2213 | r#" | 2218 | r#" |
2214 | mod tests<|> { | 2219 | mod tests$0 { |
2215 | #[test] | 2220 | #[test] |
2216 | fn foo_test() {} | 2221 | fn foo_test() {} |
2217 | } | 2222 | } |
@@ -2246,7 +2251,7 @@ mod tests<|> { | |||
2246 | r#" | 2251 | r#" |
2247 | struct S{ f1: u32 } | 2252 | struct S{ f1: u32 } |
2248 | 2253 | ||
2249 | fn main() { let s<|>t = S{ f1:0 }; } | 2254 | fn main() { let s$0t = S{ f1:0 }; } |
2250 | "#, | 2255 | "#, |
2251 | expect![[r#" | 2256 | expect![[r#" |
2252 | [ | 2257 | [ |
@@ -2279,7 +2284,7 @@ fn main() { let s<|>t = S{ f1:0 }; } | |||
2279 | struct Arg(u32); | 2284 | struct Arg(u32); |
2280 | struct S<T>{ f1: T } | 2285 | struct S<T>{ f1: T } |
2281 | 2286 | ||
2282 | fn main() { let s<|>t = S{ f1:Arg(0) }; } | 2287 | fn main() { let s$0t = S{ f1:Arg(0) }; } |
2283 | "#, | 2288 | "#, |
2284 | expect![[r#" | 2289 | expect![[r#" |
2285 | [ | 2290 | [ |
@@ -2325,7 +2330,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } | |||
2325 | struct Arg(u32); | 2330 | struct Arg(u32); |
2326 | struct S<T>{ f1: T } | 2331 | struct S<T>{ f1: T } |
2327 | 2332 | ||
2328 | fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } | 2333 | fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } |
2329 | "#, | 2334 | "#, |
2330 | expect![[r#" | 2335 | expect![[r#" |
2331 | [ | 2336 | [ |
@@ -2374,7 +2379,7 @@ mod M { | |||
2374 | pub struct C(u32); | 2379 | pub struct C(u32); |
2375 | } | 2380 | } |
2376 | 2381 | ||
2377 | fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | 2382 | fn main() { let s$0t = (A(1), B(2), M::C(3) ); } |
2378 | "#, | 2383 | "#, |
2379 | expect![[r#" | 2384 | expect![[r#" |
2380 | [ | 2385 | [ |
@@ -2433,7 +2438,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
2433 | trait Foo {} | 2438 | trait Foo {} |
2434 | fn foo() -> impl Foo {} | 2439 | fn foo() -> impl Foo {} |
2435 | 2440 | ||
2436 | fn main() { let s<|>t = foo(); } | 2441 | fn main() { let s$0t = foo(); } |
2437 | "#, | 2442 | "#, |
2438 | expect![[r#" | 2443 | expect![[r#" |
2439 | [ | 2444 | [ |
@@ -2467,7 +2472,7 @@ trait Foo<T> {} | |||
2467 | struct S; | 2472 | struct S; |
2468 | fn foo() -> impl Foo<S> {} | 2473 | fn foo() -> impl Foo<S> {} |
2469 | 2474 | ||
2470 | fn main() { let s<|>t = foo(); } | 2475 | fn main() { let s$0t = foo(); } |
2471 | "#, | 2476 | "#, |
2472 | expect![[r#" | 2477 | expect![[r#" |
2473 | [ | 2478 | [ |
@@ -2514,7 +2519,7 @@ trait Foo {} | |||
2514 | trait Bar {} | 2519 | trait Bar {} |
2515 | fn foo() -> impl Foo + Bar {} | 2520 | fn foo() -> impl Foo + Bar {} |
2516 | 2521 | ||
2517 | fn main() { let s<|>t = foo(); } | 2522 | fn main() { let s$0t = foo(); } |
2518 | "#, | 2523 | "#, |
2519 | expect![[r#" | 2524 | expect![[r#" |
2520 | [ | 2525 | [ |
@@ -2564,7 +2569,7 @@ struct S2 {} | |||
2564 | 2569 | ||
2565 | fn foo() -> impl Foo<S1> + Bar<S2> {} | 2570 | fn foo() -> impl Foo<S1> + Bar<S2> {} |
2566 | 2571 | ||
2567 | fn main() { let s<|>t = foo(); } | 2572 | fn main() { let s$0t = foo(); } |
2568 | "#, | 2573 | "#, |
2569 | expect![[r#" | 2574 | expect![[r#" |
2570 | [ | 2575 | [ |
@@ -2634,7 +2639,7 @@ fn main() { let s<|>t = foo(); } | |||
2634 | check_actions( | 2639 | check_actions( |
2635 | r#" | 2640 | r#" |
2636 | trait Foo {} | 2641 | trait Foo {} |
2637 | fn foo(ar<|>g: &impl Foo) {} | 2642 | fn foo(ar$0g: &impl Foo) {} |
2638 | "#, | 2643 | "#, |
2639 | expect![[r#" | 2644 | expect![[r#" |
2640 | [ | 2645 | [ |
@@ -2668,7 +2673,7 @@ trait Foo {} | |||
2668 | trait Bar<T> {} | 2673 | trait Bar<T> {} |
2669 | struct S{} | 2674 | struct S{} |
2670 | 2675 | ||
2671 | fn foo(ar<|>g: &impl Foo + Bar<S>) {} | 2676 | fn foo(ar$0g: &impl Foo + Bar<S>) {} |
2672 | "#, | 2677 | "#, |
2673 | expect![[r#" | 2678 | expect![[r#" |
2674 | [ | 2679 | [ |
@@ -2726,7 +2731,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
2726 | r#" | 2731 | r#" |
2727 | struct S; | 2732 | struct S; |
2728 | fn foo() { | 2733 | fn foo() { |
2729 | let fo<|>o = async { S }; | 2734 | let fo$0o = async { S }; |
2730 | } | 2735 | } |
2731 | 2736 | ||
2732 | #[prelude_import] use future::*; | 2737 | #[prelude_import] use future::*; |
@@ -2778,7 +2783,7 @@ mod future { | |||
2778 | r#" | 2783 | r#" |
2779 | trait Foo<T> {} | 2784 | trait Foo<T> {} |
2780 | struct S {} | 2785 | struct S {} |
2781 | fn foo(ar<|>g: &impl Foo<S>) {} | 2786 | fn foo(ar$0g: &impl Foo<S>) {} |
2782 | "#, | 2787 | "#, |
2783 | expect![[r#" | 2788 | expect![[r#" |
2784 | [ | 2789 | [ |
@@ -2828,7 +2833,7 @@ impl Foo for S {} | |||
2828 | struct B<T>{} | 2833 | struct B<T>{} |
2829 | fn foo() -> B<dyn Foo> {} | 2834 | fn foo() -> B<dyn Foo> {} |
2830 | 2835 | ||
2831 | fn main() { let s<|>t = foo(); } | 2836 | fn main() { let s$0t = foo(); } |
2832 | "#, | 2837 | "#, |
2833 | expect![[r#" | 2838 | expect![[r#" |
2834 | [ | 2839 | [ |
@@ -2872,7 +2877,7 @@ fn main() { let s<|>t = foo(); } | |||
2872 | check_actions( | 2877 | check_actions( |
2873 | r#" | 2878 | r#" |
2874 | trait Foo {} | 2879 | trait Foo {} |
2875 | fn foo(ar<|>g: &dyn Foo) {} | 2880 | fn foo(ar$0g: &dyn Foo) {} |
2876 | "#, | 2881 | "#, |
2877 | expect![[r#" | 2882 | expect![[r#" |
2878 | [ | 2883 | [ |
@@ -2904,7 +2909,7 @@ fn foo(ar<|>g: &dyn Foo) {} | |||
2904 | r#" | 2909 | r#" |
2905 | trait Foo<T> {} | 2910 | trait Foo<T> {} |
2906 | struct S {} | 2911 | struct S {} |
2907 | fn foo(ar<|>g: &dyn Foo<S>) {} | 2912 | fn foo(ar$0g: &dyn Foo<S>) {} |
2908 | "#, | 2913 | "#, |
2909 | expect![[r#" | 2914 | expect![[r#" |
2910 | [ | 2915 | [ |
@@ -2952,7 +2957,7 @@ trait DynTrait<T> {} | |||
2952 | struct B<T> {} | 2957 | struct B<T> {} |
2953 | struct S {} | 2958 | struct S {} |
2954 | 2959 | ||
2955 | fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | 2960 | fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} |
2956 | "#, | 2961 | "#, |
2957 | expect![[r#" | 2962 | expect![[r#" |
2958 | [ | 2963 | [ |
@@ -3033,7 +3038,7 @@ impl Foo for S { type Item = Bar; } | |||
3033 | 3038 | ||
3034 | fn test() -> impl Foo { S {} } | 3039 | fn test() -> impl Foo { S {} } |
3035 | 3040 | ||
3036 | fn main() { let s<|>t = test().get(); } | 3041 | fn main() { let s$0t = test().get(); } |
3037 | "#, | 3042 | "#, |
3038 | expect![[r#" | 3043 | expect![[r#" |
3039 | [ | 3044 | [ |
@@ -3060,6 +3065,71 @@ fn main() { let s<|>t = test().get(); } | |||
3060 | } | 3065 | } |
3061 | 3066 | ||
3062 | #[test] | 3067 | #[test] |
3068 | fn test_hover_const_param_has_goto_type_action() { | ||
3069 | check_actions( | ||
3070 | r#" | ||
3071 | struct Bar; | ||
3072 | struct Foo<const BAR: Bar>; | ||
3073 | |||
3074 | impl<const BAR: Bar> Foo<BAR$0> {} | ||
3075 | "#, | ||
3076 | expect![[r#" | ||
3077 | [ | ||
3078 | GoToType( | ||
3079 | [ | ||
3080 | HoverGotoTypeData { | ||
3081 | mod_path: "test::Bar", | ||
3082 | nav: NavigationTarget { | ||
3083 | file_id: FileId( | ||
3084 | 0, | ||
3085 | ), | ||
3086 | full_range: 0..11, | ||
3087 | focus_range: 7..10, | ||
3088 | name: "Bar", | ||
3089 | kind: Struct, | ||
3090 | description: "struct Bar", | ||
3091 | }, | ||
3092 | }, | ||
3093 | ], | ||
3094 | ), | ||
3095 | ] | ||
3096 | "#]], | ||
3097 | ); | ||
3098 | } | ||
3099 | |||
3100 | #[test] | ||
3101 | fn test_hover_type_param_has_goto_type_action() { | ||
3102 | check_actions( | ||
3103 | r#" | ||
3104 | trait Foo {} | ||
3105 | |||
3106 | fn foo<T: Foo>(t: T$0){} | ||
3107 | "#, | ||
3108 | expect![[r#" | ||
3109 | [ | ||
3110 | GoToType( | ||
3111 | [ | ||
3112 | HoverGotoTypeData { | ||
3113 | mod_path: "test::Foo", | ||
3114 | nav: NavigationTarget { | ||
3115 | file_id: FileId( | ||
3116 | 0, | ||
3117 | ), | ||
3118 | full_range: 0..12, | ||
3119 | focus_range: 6..9, | ||
3120 | name: "Foo", | ||
3121 | kind: Trait, | ||
3122 | description: "trait Foo", | ||
3123 | }, | ||
3124 | }, | ||
3125 | ], | ||
3126 | ), | ||
3127 | ] | ||
3128 | "#]], | ||
3129 | ); | ||
3130 | } | ||
3131 | |||
3132 | #[test] | ||
3063 | fn hover_displays_normalized_crate_names() { | 3133 | fn hover_displays_normalized_crate_names() { |
3064 | check( | 3134 | check( |
3065 | r#" | 3135 | r#" |
@@ -3073,7 +3143,7 @@ pub mod wrapper { | |||
3073 | } | 3143 | } |
3074 | 3144 | ||
3075 | //- /main.rs crate:main deps:name-with-dashes | 3145 | //- /main.rs crate:main deps:name-with-dashes |
3076 | fn main() { let foo_test = name_with_dashes::wrapper::Thing::new<|>(); } | 3146 | fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); } |
3077 | "#, | 3147 | "#, |
3078 | expect![[r#" | 3148 | expect![[r#" |
3079 | *new* | 3149 | *new* |
@@ -3099,7 +3169,7 @@ struct S { | |||
3099 | 3169 | ||
3100 | fn main() { | 3170 | fn main() { |
3101 | let s = S { f: 0 }; | 3171 | let s = S { f: 0 }; |
3102 | let S { f<|> } = &s; | 3172 | let S { f$0 } = &s; |
3103 | } | 3173 | } |
3104 | "#, | 3174 | "#, |
3105 | expect![[r#" | 3175 | expect![[r#" |
@@ -3118,7 +3188,7 @@ fn main() { | |||
3118 | r#" | 3188 | r#" |
3119 | struct Foo {} | 3189 | struct Foo {} |
3120 | impl Foo { | 3190 | impl Foo { |
3121 | fn bar(&sel<|>f) {} | 3191 | fn bar(&sel$0f) {} |
3122 | } | 3192 | } |
3123 | "#, | 3193 | "#, |
3124 | expect![[r#" | 3194 | expect![[r#" |
@@ -3137,7 +3207,7 @@ impl Foo { | |||
3137 | struct Arc<T>(T); | 3207 | struct Arc<T>(T); |
3138 | struct Foo {} | 3208 | struct Foo {} |
3139 | impl Foo { | 3209 | impl Foo { |
3140 | fn bar(sel<|>f: Arc<Foo>) {} | 3210 | fn bar(sel$0f: Arc<Foo>) {} |
3141 | } | 3211 | } |
3142 | "#, | 3212 | "#, |
3143 | expect![[r#" | 3213 | expect![[r#" |
@@ -3154,7 +3224,7 @@ impl Foo { | |||
3154 | check( | 3224 | check( |
3155 | r#" | 3225 | r#" |
3156 | /// Be quick; | 3226 | /// Be quick; |
3157 | mod Foo<|> { | 3227 | mod Foo$0 { |
3158 | //! time is mana | 3228 | //! time is mana |
3159 | 3229 | ||
3160 | /// This comment belongs to the function | 3230 | /// This comment belongs to the function |
@@ -3185,7 +3255,7 @@ mod Foo<|> { | |||
3185 | check( | 3255 | check( |
3186 | r#" | 3256 | r#" |
3187 | #[doc = "Be quick;"] | 3257 | #[doc = "Be quick;"] |
3188 | mod Foo<|> { | 3258 | mod Foo$0 { |
3189 | #![doc = "time is mana"] | 3259 | #![doc = "time is mana"] |
3190 | 3260 | ||
3191 | #[doc = "This comment belongs to the function"] | 3261 | #[doc = "This comment belongs to the function"] |
@@ -3216,9 +3286,105 @@ mod Foo<|> { | |||
3216 | check_hover_no_result( | 3286 | check_hover_no_result( |
3217 | r#" | 3287 | r#" |
3218 | fn no_hover() { | 3288 | fn no_hover() { |
3219 | // no<|>hover | 3289 | // no$0hover |
3220 | } | 3290 | } |
3221 | "#, | 3291 | "#, |
3222 | ); | 3292 | ); |
3223 | } | 3293 | } |
3294 | |||
3295 | #[test] | ||
3296 | fn hover_label() { | ||
3297 | check( | ||
3298 | r#" | ||
3299 | fn foo() { | ||
3300 | 'label$0: loop {} | ||
3301 | } | ||
3302 | "#, | ||
3303 | expect![[r#" | ||
3304 | *'label* | ||
3305 | |||
3306 | ```rust | ||
3307 | 'label | ||
3308 | ``` | ||
3309 | "#]], | ||
3310 | ); | ||
3311 | } | ||
3312 | |||
3313 | #[test] | ||
3314 | fn hover_lifetime() { | ||
3315 | check( | ||
3316 | r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#, | ||
3317 | expect![[r#" | ||
3318 | *'lifetime* | ||
3319 | |||
3320 | ```rust | ||
3321 | 'lifetime | ||
3322 | ``` | ||
3323 | "#]], | ||
3324 | ); | ||
3325 | } | ||
3326 | |||
3327 | #[test] | ||
3328 | fn hover_type_param() { | ||
3329 | check( | ||
3330 | r#" | ||
3331 | struct Foo<T>(T); | ||
3332 | trait Copy {} | ||
3333 | trait Clone {} | ||
3334 | trait Sized {} | ||
3335 | impl<T: Copy + Clone> Foo<T$0> where T: Sized {} | ||
3336 | "#, | ||
3337 | expect![[r#" | ||
3338 | *T* | ||
3339 | |||
3340 | ```rust | ||
3341 | T: Copy + Clone + Sized | ||
3342 | ``` | ||
3343 | "#]], | ||
3344 | ); | ||
3345 | check( | ||
3346 | r#" | ||
3347 | struct Foo<T>(T); | ||
3348 | impl<T> Foo<T$0> {} | ||
3349 | "#, | ||
3350 | expect![[r#" | ||
3351 | *T* | ||
3352 | |||
3353 | ```rust | ||
3354 | T | ||
3355 | ``` | ||
3356 | "#]], | ||
3357 | ); | ||
3358 | // lifetimes aren't being substituted yet | ||
3359 | check( | ||
3360 | r#" | ||
3361 | struct Foo<T>(T); | ||
3362 | impl<T: 'static> Foo<T$0> {} | ||
3363 | "#, | ||
3364 | expect![[r#" | ||
3365 | *T* | ||
3366 | |||
3367 | ```rust | ||
3368 | T: {error} | ||
3369 | ``` | ||
3370 | "#]], | ||
3371 | ); | ||
3372 | } | ||
3373 | |||
3374 | #[test] | ||
3375 | fn hover_const_param() { | ||
3376 | check( | ||
3377 | r#" | ||
3378 | struct Foo<const LEN: usize>; | ||
3379 | impl<const LEN: usize> Foo<LEN$0> {} | ||
3380 | "#, | ||
3381 | expect![[r#" | ||
3382 | *LEN* | ||
3383 | |||
3384 | ```rust | ||
3385 | const LEN: usize | ||
3386 | ``` | ||
3387 | "#]], | ||
3388 | ); | ||
3389 | } | ||
3224 | } | 3390 | } |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 65df7979c..a2039fcc7 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -18,12 +18,6 @@ pub struct InlayHintsConfig { | |||
18 | pub max_length: Option<usize>, | 18 | pub max_length: Option<usize>, |
19 | } | 19 | } |
20 | 20 | ||
21 | impl Default for InlayHintsConfig { | ||
22 | fn default() -> Self { | ||
23 | Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None } | ||
24 | } | ||
25 | } | ||
26 | |||
27 | #[derive(Clone, Debug, PartialEq, Eq)] | 21 | #[derive(Clone, Debug, PartialEq, Eq)] |
28 | pub enum InlayKind { | 22 | pub enum InlayKind { |
29 | TypeHint, | 23 | TypeHint, |
@@ -359,9 +353,25 @@ fn is_argument_similar_to_param_name( | |||
359 | } | 353 | } |
360 | match get_string_representation(argument) { | 354 | match get_string_representation(argument) { |
361 | None => false, | 355 | None => false, |
362 | Some(repr) => { | 356 | Some(argument_string) => { |
363 | let argument_string = repr.trim_start_matches('_'); | 357 | let num_leading_underscores = |
364 | argument_string.starts_with(param_name) || argument_string.ends_with(param_name) | 358 | argument_string.bytes().take_while(|&c| c == b'_').count(); |
359 | |||
360 | // Does the argument name begin with the parameter name? Ignore leading underscores. | ||
361 | let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores); | ||
362 | let starts_with_pattern = param_name.bytes().all( | ||
363 | |expected| matches!(arg_bytes.next(), Some(actual) if expected.eq_ignore_ascii_case(&actual)), | ||
364 | ); | ||
365 | |||
366 | if starts_with_pattern { | ||
367 | return true; | ||
368 | } | ||
369 | |||
370 | // Does the argument name end with the parameter name? | ||
371 | let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores); | ||
372 | param_name.bytes().rev().all( | ||
373 | |expected| matches!(arg_bytes.next_back(), Some(actual) if expected.eq_ignore_ascii_case(&actual)), | ||
374 | ) | ||
365 | } | 375 | } |
366 | } | 376 | } |
367 | } | 377 | } |
@@ -433,8 +443,15 @@ mod tests { | |||
433 | 443 | ||
434 | use crate::{fixture, inlay_hints::InlayHintsConfig}; | 444 | use crate::{fixture, inlay_hints::InlayHintsConfig}; |
435 | 445 | ||
446 | const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig { | ||
447 | type_hints: true, | ||
448 | parameter_hints: true, | ||
449 | chaining_hints: true, | ||
450 | max_length: None, | ||
451 | }; | ||
452 | |||
436 | fn check(ra_fixture: &str) { | 453 | fn check(ra_fixture: &str) { |
437 | check_with_config(InlayHintsConfig::default(), ra_fixture); | 454 | check_with_config(TEST_CONFIG, ra_fixture); |
438 | } | 455 | } |
439 | 456 | ||
440 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { | 457 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { |
@@ -748,7 +765,7 @@ fn main() { | |||
748 | #[test] | 765 | #[test] |
749 | fn hint_truncation() { | 766 | fn hint_truncation() { |
750 | check_with_config( | 767 | check_with_config( |
751 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, | 768 | InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, |
752 | r#" | 769 | r#" |
753 | struct Smol<T>(T); | 770 | struct Smol<T>(T); |
754 | 771 | ||
@@ -831,7 +848,7 @@ fn main() { | |||
831 | #[test] | 848 | #[test] |
832 | fn omitted_parameters_hints_heuristics() { | 849 | fn omitted_parameters_hints_heuristics() { |
833 | check_with_config( | 850 | check_with_config( |
834 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, | 851 | InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, |
835 | r#" | 852 | r#" |
836 | fn map(f: i32) {} | 853 | fn map(f: i32) {} |
837 | fn filter(predicate: i32) {} | 854 | fn filter(predicate: i32) {} |
@@ -900,6 +917,9 @@ fn main() { | |||
900 | twiddle(true); | 917 | twiddle(true); |
901 | doo(true); | 918 | doo(true); |
902 | 919 | ||
920 | const TWIDDLE_UPPERCASE: bool = true; | ||
921 | twiddle(TWIDDLE_UPPERCASE); | ||
922 | |||
903 | let mut param_begin: Param = Param {}; | 923 | let mut param_begin: Param = Param {}; |
904 | different_order(¶m_begin); | 924 | different_order(¶m_begin); |
905 | different_order(&mut param_begin); | 925 | different_order(&mut param_begin); |
@@ -924,7 +944,7 @@ fn main() { | |||
924 | #[test] | 944 | #[test] |
925 | fn unit_structs_have_no_type_hints() { | 945 | fn unit_structs_have_no_type_hints() { |
926 | check_with_config( | 946 | check_with_config( |
927 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, | 947 | InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, |
928 | r#" | 948 | r#" |
929 | enum Result<T, E> { Ok(T), Err(E) } | 949 | enum Result<T, E> { Ok(T), Err(E) } |
930 | use Result::*; | 950 | use Result::*; |
@@ -1381,4 +1401,41 @@ fn main() { | |||
1381 | "#, | 1401 | "#, |
1382 | ) | 1402 | ) |
1383 | } | 1403 | } |
1404 | |||
1405 | #[test] | ||
1406 | fn fn_hints() { | ||
1407 | check( | ||
1408 | r#" | ||
1409 | trait Sized {} | ||
1410 | |||
1411 | fn foo() -> impl Fn() { loop {} } | ||
1412 | fn foo1() -> impl Fn(f64) { loop {} } | ||
1413 | fn foo2() -> impl Fn(f64, f64) { loop {} } | ||
1414 | fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } | ||
1415 | fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } | ||
1416 | fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } | ||
1417 | fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } | ||
1418 | fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } | ||
1419 | |||
1420 | fn main() { | ||
1421 | let foo = foo(); | ||
1422 | // ^^^ impl Fn() | ||
1423 | let foo = foo1(); | ||
1424 | // ^^^ impl Fn(f64) | ||
1425 | let foo = foo2(); | ||
1426 | // ^^^ impl Fn(f64, f64) | ||
1427 | let foo = foo3(); | ||
1428 | // ^^^ impl Fn(f64, f64) -> u32 | ||
1429 | let foo = foo4(); | ||
1430 | // ^^^ &dyn Fn(f64, f64) -> u32 | ||
1431 | let foo = foo5(); | ||
1432 | // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 | ||
1433 | let foo = foo6(); | ||
1434 | // ^^^ impl Fn(f64, f64) -> u32 + Sized | ||
1435 | let foo = foo7(); | ||
1436 | // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized) | ||
1437 | } | ||
1438 | "#, | ||
1439 | ) | ||
1440 | } | ||
1384 | } | 1441 | } |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index b5a6f66fd..05380f2a1 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -104,7 +104,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
104 | // Special case that turns something like: | 104 | // Special case that turns something like: |
105 | // | 105 | // |
106 | // ``` | 106 | // ``` |
107 | // my_function({<|> | 107 | // my_function({$0 |
108 | // <some-expr> | 108 | // <some-expr> |
109 | // }) | 109 | // }) |
110 | // ``` | 110 | // ``` |
@@ -116,7 +116,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
116 | // ditto for | 116 | // ditto for |
117 | // | 117 | // |
118 | // ``` | 118 | // ``` |
119 | // use foo::{<|> | 119 | // use foo::{$0 |
120 | // bar | 120 | // bar |
121 | // }; | 121 | // }; |
122 | // ``` | 122 | // ``` |
@@ -198,8 +198,8 @@ mod tests { | |||
198 | 198 | ||
199 | use super::*; | 199 | use super::*; |
200 | 200 | ||
201 | fn check_join_lines(before: &str, after: &str) { | 201 | fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) { |
202 | let (before_cursor_pos, before) = extract_offset(before); | 202 | let (before_cursor_pos, before) = extract_offset(ra_fixture_before); |
203 | let file = SourceFile::parse(&before).ok().unwrap(); | 203 | let file = SourceFile::parse(&before).ok().unwrap(); |
204 | 204 | ||
205 | let range = TextRange::empty(before_cursor_pos); | 205 | let range = TextRange::empty(before_cursor_pos); |
@@ -214,7 +214,7 @@ mod tests { | |||
214 | .apply_to_offset(before_cursor_pos) | 214 | .apply_to_offset(before_cursor_pos) |
215 | .expect("cursor position is affected by the edit"); | 215 | .expect("cursor position is affected by the edit"); |
216 | let actual = add_cursor(&actual, actual_cursor_pos); | 216 | let actual = add_cursor(&actual, actual_cursor_pos); |
217 | assert_eq_text!(after, &actual); | 217 | assert_eq_text!(ra_fixture_after, &actual); |
218 | } | 218 | } |
219 | 219 | ||
220 | #[test] | 220 | #[test] |
@@ -222,13 +222,13 @@ mod tests { | |||
222 | check_join_lines( | 222 | check_join_lines( |
223 | r" | 223 | r" |
224 | fn foo() { | 224 | fn foo() { |
225 | <|>foo(1, | 225 | $0foo(1, |
226 | ) | 226 | ) |
227 | } | 227 | } |
228 | ", | 228 | ", |
229 | r" | 229 | r" |
230 | fn foo() { | 230 | fn foo() { |
231 | <|>foo(1) | 231 | $0foo(1) |
232 | } | 232 | } |
233 | ", | 233 | ", |
234 | ); | 234 | ); |
@@ -239,14 +239,14 @@ fn foo() { | |||
239 | check_join_lines( | 239 | check_join_lines( |
240 | r" | 240 | r" |
241 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { | 241 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { |
242 | <|>self.incremental_reparse(edit).unwrap_or_else(|| { | 242 | $0self.incremental_reparse(edit).unwrap_or_else(|| { |
243 | self.full_reparse(edit) | 243 | self.full_reparse(edit) |
244 | }) | 244 | }) |
245 | } | 245 | } |
246 | ", | 246 | ", |
247 | r" | 247 | r" |
248 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { | 248 | pub fn reparse(&self, edit: &AtomTextEdit) -> File { |
249 | <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | 249 | $0self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) |
250 | } | 250 | } |
251 | ", | 251 | ", |
252 | ); | 252 | ); |
@@ -257,13 +257,13 @@ pub fn reparse(&self, edit: &AtomTextEdit) -> File { | |||
257 | check_join_lines( | 257 | check_join_lines( |
258 | r" | 258 | r" |
259 | fn foo() { | 259 | fn foo() { |
260 | foo(<|>{ | 260 | foo($0{ |
261 | 92 | 261 | 92 |
262 | }) | 262 | }) |
263 | }", | 263 | }", |
264 | r" | 264 | r" |
265 | fn foo() { | 265 | fn foo() { |
266 | foo(<|>92) | 266 | foo($092) |
267 | }", | 267 | }", |
268 | ); | 268 | ); |
269 | } | 269 | } |
@@ -274,7 +274,7 @@ fn foo() { | |||
274 | fn foo() { | 274 | fn foo() { |
275 | loop { | 275 | loop { |
276 | match x { | 276 | match x { |
277 | 92 => <|>{ | 277 | 92 => $0{ |
278 | continue; | 278 | continue; |
279 | } | 279 | } |
280 | } | 280 | } |
@@ -285,7 +285,7 @@ fn foo() { | |||
285 | fn foo() { | 285 | fn foo() { |
286 | loop { | 286 | loop { |
287 | match x { | 287 | match x { |
288 | 92 => <|>continue, | 288 | 92 => $0continue, |
289 | } | 289 | } |
290 | } | 290 | } |
291 | } | 291 | } |
@@ -299,7 +299,7 @@ fn foo() { | |||
299 | r" | 299 | r" |
300 | fn foo(e: Result<U, V>) { | 300 | fn foo(e: Result<U, V>) { |
301 | match e { | 301 | match e { |
302 | Ok(u) => <|>{ | 302 | Ok(u) => $0{ |
303 | u.foo() | 303 | u.foo() |
304 | } | 304 | } |
305 | Err(v) => v, | 305 | Err(v) => v, |
@@ -308,7 +308,7 @@ fn foo(e: Result<U, V>) { | |||
308 | r" | 308 | r" |
309 | fn foo(e: Result<U, V>) { | 309 | fn foo(e: Result<U, V>) { |
310 | match e { | 310 | match e { |
311 | Ok(u) => <|>u.foo(), | 311 | Ok(u) => $0u.foo(), |
312 | Err(v) => v, | 312 | Err(v) => v, |
313 | } | 313 | } |
314 | }", | 314 | }", |
@@ -321,7 +321,7 @@ fn foo(e: Result<U, V>) { | |||
321 | r" | 321 | r" |
322 | fn foo() { | 322 | fn foo() { |
323 | match ty { | 323 | match ty { |
324 | <|> Some(ty) => { | 324 | $0 Some(ty) => { |
325 | match ty { | 325 | match ty { |
326 | _ => false, | 326 | _ => false, |
327 | } | 327 | } |
@@ -333,7 +333,7 @@ fn foo() { | |||
333 | r" | 333 | r" |
334 | fn foo() { | 334 | fn foo() { |
335 | match ty { | 335 | match ty { |
336 | <|> Some(ty) => match ty { | 336 | $0 Some(ty) => match ty { |
337 | _ => false, | 337 | _ => false, |
338 | }, | 338 | }, |
339 | _ => true, | 339 | _ => true, |
@@ -350,7 +350,7 @@ fn foo() { | |||
350 | r" | 350 | r" |
351 | fn foo(e: Result<U, V>) { | 351 | fn foo(e: Result<U, V>) { |
352 | match e { | 352 | match e { |
353 | Ok(u) => <|>{ | 353 | Ok(u) => $0{ |
354 | u.foo() | 354 | u.foo() |
355 | }, | 355 | }, |
356 | Err(v) => v, | 356 | Err(v) => v, |
@@ -359,7 +359,7 @@ fn foo(e: Result<U, V>) { | |||
359 | r" | 359 | r" |
360 | fn foo(e: Result<U, V>) { | 360 | fn foo(e: Result<U, V>) { |
361 | match e { | 361 | match e { |
362 | Ok(u) => <|>u.foo(), | 362 | Ok(u) => $0u.foo(), |
363 | Err(v) => v, | 363 | Err(v) => v, |
364 | } | 364 | } |
365 | }", | 365 | }", |
@@ -370,7 +370,7 @@ fn foo(e: Result<U, V>) { | |||
370 | r" | 370 | r" |
371 | fn foo(e: Result<U, V>) { | 371 | fn foo(e: Result<U, V>) { |
372 | match e { | 372 | match e { |
373 | Ok(u) => <|>{ | 373 | Ok(u) => $0{ |
374 | u.foo() | 374 | u.foo() |
375 | } , | 375 | } , |
376 | Err(v) => v, | 376 | Err(v) => v, |
@@ -379,7 +379,7 @@ fn foo(e: Result<U, V>) { | |||
379 | r" | 379 | r" |
380 | fn foo(e: Result<U, V>) { | 380 | fn foo(e: Result<U, V>) { |
381 | match e { | 381 | match e { |
382 | Ok(u) => <|>u.foo() , | 382 | Ok(u) => $0u.foo() , |
383 | Err(v) => v, | 383 | Err(v) => v, |
384 | } | 384 | } |
385 | }", | 385 | }", |
@@ -390,7 +390,7 @@ fn foo(e: Result<U, V>) { | |||
390 | r" | 390 | r" |
391 | fn foo(e: Result<U, V>) { | 391 | fn foo(e: Result<U, V>) { |
392 | match e { | 392 | match e { |
393 | Ok(u) => <|>{ | 393 | Ok(u) => $0{ |
394 | u.foo() | 394 | u.foo() |
395 | } | 395 | } |
396 | , | 396 | , |
@@ -400,7 +400,7 @@ fn foo(e: Result<U, V>) { | |||
400 | r" | 400 | r" |
401 | fn foo(e: Result<U, V>) { | 401 | fn foo(e: Result<U, V>) { |
402 | match e { | 402 | match e { |
403 | Ok(u) => <|>u.foo() | 403 | Ok(u) => $0u.foo() |
404 | , | 404 | , |
405 | Err(v) => v, | 405 | Err(v) => v, |
406 | } | 406 | } |
@@ -414,13 +414,13 @@ fn foo(e: Result<U, V>) { | |||
414 | check_join_lines( | 414 | check_join_lines( |
415 | r" | 415 | r" |
416 | fn foo() { | 416 | fn foo() { |
417 | let x = (<|>{ | 417 | let x = ($0{ |
418 | 4 | 418 | 4 |
419 | },); | 419 | },); |
420 | }", | 420 | }", |
421 | r" | 421 | r" |
422 | fn foo() { | 422 | fn foo() { |
423 | let x = (<|>4,); | 423 | let x = ($04,); |
424 | }", | 424 | }", |
425 | ); | 425 | ); |
426 | 426 | ||
@@ -428,13 +428,13 @@ fn foo() { | |||
428 | check_join_lines( | 428 | check_join_lines( |
429 | r" | 429 | r" |
430 | fn foo() { | 430 | fn foo() { |
431 | let x = (<|>{ | 431 | let x = ($0{ |
432 | 4 | 432 | 4 |
433 | } ,); | 433 | } ,); |
434 | }", | 434 | }", |
435 | r" | 435 | r" |
436 | fn foo() { | 436 | fn foo() { |
437 | let x = (<|>4 ,); | 437 | let x = ($04 ,); |
438 | }", | 438 | }", |
439 | ); | 439 | ); |
440 | 440 | ||
@@ -442,14 +442,14 @@ fn foo() { | |||
442 | check_join_lines( | 442 | check_join_lines( |
443 | r" | 443 | r" |
444 | fn foo() { | 444 | fn foo() { |
445 | let x = (<|>{ | 445 | let x = ($0{ |
446 | 4 | 446 | 4 |
447 | } | 447 | } |
448 | ,); | 448 | ,); |
449 | }", | 449 | }", |
450 | r" | 450 | r" |
451 | fn foo() { | 451 | fn foo() { |
452 | let x = (<|>4 | 452 | let x = ($04 |
453 | ,); | 453 | ,); |
454 | }", | 454 | }", |
455 | ); | 455 | ); |
@@ -460,11 +460,11 @@ fn foo() { | |||
460 | // No space after the '{' | 460 | // No space after the '{' |
461 | check_join_lines( | 461 | check_join_lines( |
462 | r" | 462 | r" |
463 | <|>use syntax::{ | 463 | $0use syntax::{ |
464 | TextSize, TextRange, | 464 | TextSize, TextRange, |
465 | };", | 465 | };", |
466 | r" | 466 | r" |
467 | <|>use syntax::{TextSize, TextRange, | 467 | $0use syntax::{TextSize, TextRange, |
468 | };", | 468 | };", |
469 | ); | 469 | ); |
470 | } | 470 | } |
@@ -475,11 +475,11 @@ fn foo() { | |||
475 | check_join_lines( | 475 | check_join_lines( |
476 | r" | 476 | r" |
477 | use syntax::{ | 477 | use syntax::{ |
478 | <|> TextSize, TextRange | 478 | $0 TextSize, TextRange |
479 | };", | 479 | };", |
480 | r" | 480 | r" |
481 | use syntax::{ | 481 | use syntax::{ |
482 | <|> TextSize, TextRange};", | 482 | $0 TextSize, TextRange};", |
483 | ); | 483 | ); |
484 | } | 484 | } |
485 | 485 | ||
@@ -489,11 +489,11 @@ use syntax::{ | |||
489 | check_join_lines( | 489 | check_join_lines( |
490 | r" | 490 | r" |
491 | use syntax::{ | 491 | use syntax::{ |
492 | <|> TextSize, TextRange, | 492 | $0 TextSize, TextRange, |
493 | };", | 493 | };", |
494 | r" | 494 | r" |
495 | use syntax::{ | 495 | use syntax::{ |
496 | <|> TextSize, TextRange};", | 496 | $0 TextSize, TextRange};", |
497 | ); | 497 | ); |
498 | } | 498 | } |
499 | 499 | ||
@@ -502,14 +502,14 @@ use syntax::{ | |||
502 | check_join_lines( | 502 | check_join_lines( |
503 | r" | 503 | r" |
504 | use syntax::{ | 504 | use syntax::{ |
505 | algo::<|>{ | 505 | algo::$0{ |
506 | find_token_at_offset, | 506 | find_token_at_offset, |
507 | }, | 507 | }, |
508 | ast, | 508 | ast, |
509 | };", | 509 | };", |
510 | r" | 510 | r" |
511 | use syntax::{ | 511 | use syntax::{ |
512 | algo::<|>find_token_at_offset, | 512 | algo::$0find_token_at_offset, |
513 | ast, | 513 | ast, |
514 | };", | 514 | };", |
515 | ); | 515 | ); |
@@ -520,13 +520,13 @@ use syntax::{ | |||
520 | check_join_lines( | 520 | check_join_lines( |
521 | r" | 521 | r" |
522 | fn foo() { | 522 | fn foo() { |
523 | // Hello<|> | 523 | // Hello$0 |
524 | // world! | 524 | // world! |
525 | } | 525 | } |
526 | ", | 526 | ", |
527 | r" | 527 | r" |
528 | fn foo() { | 528 | fn foo() { |
529 | // Hello<|> world! | 529 | // Hello$0 world! |
530 | } | 530 | } |
531 | ", | 531 | ", |
532 | ); | 532 | ); |
@@ -537,13 +537,13 @@ fn foo() { | |||
537 | check_join_lines( | 537 | check_join_lines( |
538 | r" | 538 | r" |
539 | fn foo() { | 539 | fn foo() { |
540 | /// Hello<|> | 540 | /// Hello$0 |
541 | /// world! | 541 | /// world! |
542 | } | 542 | } |
543 | ", | 543 | ", |
544 | r" | 544 | r" |
545 | fn foo() { | 545 | fn foo() { |
546 | /// Hello<|> world! | 546 | /// Hello$0 world! |
547 | } | 547 | } |
548 | ", | 548 | ", |
549 | ); | 549 | ); |
@@ -554,13 +554,13 @@ fn foo() { | |||
554 | check_join_lines( | 554 | check_join_lines( |
555 | r" | 555 | r" |
556 | fn foo() { | 556 | fn foo() { |
557 | //! Hello<|> | 557 | //! Hello$0 |
558 | //! world! | 558 | //! world! |
559 | } | 559 | } |
560 | ", | 560 | ", |
561 | r" | 561 | r" |
562 | fn foo() { | 562 | fn foo() { |
563 | //! Hello<|> world! | 563 | //! Hello$0 world! |
564 | } | 564 | } |
565 | ", | 565 | ", |
566 | ); | 566 | ); |
@@ -571,13 +571,13 @@ fn foo() { | |||
571 | check_join_lines( | 571 | check_join_lines( |
572 | r" | 572 | r" |
573 | fn foo() { | 573 | fn foo() { |
574 | // Hello<|> | 574 | // Hello$0 |
575 | /* world! */ | 575 | /* world! */ |
576 | } | 576 | } |
577 | ", | 577 | ", |
578 | r" | 578 | r" |
579 | fn foo() { | 579 | fn foo() { |
580 | // Hello<|> world! */ | 580 | // Hello$0 world! */ |
581 | } | 581 | } |
582 | ", | 582 | ", |
583 | ); | 583 | ); |
@@ -588,7 +588,7 @@ fn foo() { | |||
588 | check_join_lines( | 588 | check_join_lines( |
589 | r" | 589 | r" |
590 | fn foo() { | 590 | fn foo() { |
591 | // The<|> | 591 | // The$0 |
592 | /* quick | 592 | /* quick |
593 | brown | 593 | brown |
594 | fox! */ | 594 | fox! */ |
@@ -596,7 +596,7 @@ fn foo() { | |||
596 | ", | 596 | ", |
597 | r" | 597 | r" |
598 | fn foo() { | 598 | fn foo() { |
599 | // The<|> quick | 599 | // The$0 quick |
600 | brown | 600 | brown |
601 | fox! */ | 601 | fox! */ |
602 | } | 602 | } |
@@ -604,8 +604,8 @@ fn foo() { | |||
604 | ); | 604 | ); |
605 | } | 605 | } |
606 | 606 | ||
607 | fn check_join_lines_sel(before: &str, after: &str) { | 607 | fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) { |
608 | let (sel, before) = extract_range(before); | 608 | let (sel, before) = extract_range(ra_fixture_before); |
609 | let parse = SourceFile::parse(&before); | 609 | let parse = SourceFile::parse(&before); |
610 | let result = join_lines(&parse.tree(), sel); | 610 | let result = join_lines(&parse.tree(), sel); |
611 | let actual = { | 611 | let actual = { |
@@ -613,7 +613,7 @@ fn foo() { | |||
613 | result.apply(&mut actual); | 613 | result.apply(&mut actual); |
614 | actual | 614 | actual |
615 | }; | 615 | }; |
616 | assert_eq_text!(after, &actual); | 616 | assert_eq_text!(ra_fixture_after, &actual); |
617 | } | 617 | } |
618 | 618 | ||
619 | #[test] | 619 | #[test] |
@@ -621,10 +621,10 @@ fn foo() { | |||
621 | check_join_lines_sel( | 621 | check_join_lines_sel( |
622 | r" | 622 | r" |
623 | fn foo() { | 623 | fn foo() { |
624 | <|>foo(1, | 624 | $0foo(1, |
625 | 2, | 625 | 2, |
626 | 3, | 626 | 3, |
627 | <|>) | 627 | $0) |
628 | } | 628 | } |
629 | ", | 629 | ", |
630 | r" | 630 | r" |
@@ -639,9 +639,9 @@ fn foo() { | |||
639 | fn test_join_lines_selection_struct() { | 639 | fn test_join_lines_selection_struct() { |
640 | check_join_lines_sel( | 640 | check_join_lines_sel( |
641 | r" | 641 | r" |
642 | struct Foo <|>{ | 642 | struct Foo $0{ |
643 | f: u32, | 643 | f: u32, |
644 | }<|> | 644 | }$0 |
645 | ", | 645 | ", |
646 | r" | 646 | r" |
647 | struct Foo { f: u32 } | 647 | struct Foo { f: u32 } |
@@ -654,9 +654,9 @@ struct Foo { f: u32 } | |||
654 | check_join_lines_sel( | 654 | check_join_lines_sel( |
655 | r" | 655 | r" |
656 | fn foo() { | 656 | fn foo() { |
657 | join(<|>type_params.type_params() | 657 | join($0type_params.type_params() |
658 | .filter_map(|it| it.name()) | 658 | .filter_map(|it| it.name()) |
659 | .map(|it| it.text())<|>) | 659 | .map(|it| it.text())$0) |
660 | }", | 660 | }", |
661 | r" | 661 | r" |
662 | fn foo() { | 662 | fn foo() { |
@@ -671,9 +671,9 @@ fn foo() { | |||
671 | r" | 671 | r" |
672 | pub fn handle_find_matching_brace() { | 672 | pub fn handle_find_matching_brace() { |
673 | params.offsets | 673 | params.offsets |
674 | .map(|offset| <|>{ | 674 | .map(|offset| $0{ |
675 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) | 675 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) |
676 | }<|>) | 676 | }$0) |
677 | .collect(); | 677 | .collect(); |
678 | }", | 678 | }", |
679 | r" | 679 | r" |
@@ -691,7 +691,7 @@ pub fn handle_find_matching_brace() { | |||
691 | r" | 691 | r" |
692 | fn main() { | 692 | fn main() { |
693 | let _ = { | 693 | let _ = { |
694 | // <|>foo | 694 | // $0foo |
695 | // bar | 695 | // bar |
696 | 92 | 696 | 92 |
697 | }; | 697 | }; |
@@ -700,7 +700,7 @@ fn main() { | |||
700 | r" | 700 | r" |
701 | fn main() { | 701 | fn main() { |
702 | let _ = { | 702 | let _ = { |
703 | // <|>foo bar | 703 | // $0foo bar |
704 | 92 | 704 | 92 |
705 | }; | 705 | }; |
706 | } | 706 | } |
@@ -712,12 +712,12 @@ fn main() { | |||
712 | fn join_lines_mandatory_blocks_block() { | 712 | fn join_lines_mandatory_blocks_block() { |
713 | check_join_lines( | 713 | check_join_lines( |
714 | r" | 714 | r" |
715 | <|>fn foo() { | 715 | $0fn foo() { |
716 | 92 | 716 | 92 |
717 | } | 717 | } |
718 | ", | 718 | ", |
719 | r" | 719 | r" |
720 | <|>fn foo() { 92 | 720 | $0fn foo() { 92 |
721 | } | 721 | } |
722 | ", | 722 | ", |
723 | ); | 723 | ); |
@@ -725,14 +725,14 @@ fn main() { | |||
725 | check_join_lines( | 725 | check_join_lines( |
726 | r" | 726 | r" |
727 | fn foo() { | 727 | fn foo() { |
728 | <|>if true { | 728 | $0if true { |
729 | 92 | 729 | 92 |
730 | } | 730 | } |
731 | } | 731 | } |
732 | ", | 732 | ", |
733 | r" | 733 | r" |
734 | fn foo() { | 734 | fn foo() { |
735 | <|>if true { 92 | 735 | $0if true { 92 |
736 | } | 736 | } |
737 | } | 737 | } |
738 | ", | 738 | ", |
@@ -741,14 +741,14 @@ fn foo() { | |||
741 | check_join_lines( | 741 | check_join_lines( |
742 | r" | 742 | r" |
743 | fn foo() { | 743 | fn foo() { |
744 | <|>loop { | 744 | $0loop { |
745 | 92 | 745 | 92 |
746 | } | 746 | } |
747 | } | 747 | } |
748 | ", | 748 | ", |
749 | r" | 749 | r" |
750 | fn foo() { | 750 | fn foo() { |
751 | <|>loop { 92 | 751 | $0loop { 92 |
752 | } | 752 | } |
753 | } | 753 | } |
754 | ", | 754 | ", |
@@ -757,14 +757,14 @@ fn foo() { | |||
757 | check_join_lines( | 757 | check_join_lines( |
758 | r" | 758 | r" |
759 | fn foo() { | 759 | fn foo() { |
760 | <|>unsafe { | 760 | $0unsafe { |
761 | 92 | 761 | 92 |
762 | } | 762 | } |
763 | } | 763 | } |
764 | ", | 764 | ", |
765 | r" | 765 | r" |
766 | fn foo() { | 766 | fn foo() { |
767 | <|>unsafe { 92 | 767 | $0unsafe { 92 |
768 | } | 768 | } |
769 | } | 769 | } |
770 | ", | 770 | ", |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index b3331f03f..1e03832ec 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -31,6 +31,7 @@ mod folding_ranges; | |||
31 | mod goto_definition; | 31 | mod goto_definition; |
32 | mod goto_implementation; | 32 | mod goto_implementation; |
33 | mod goto_type_definition; | 33 | mod goto_type_definition; |
34 | mod view_hir; | ||
34 | mod hover; | 35 | mod hover; |
35 | mod inlay_hints; | 36 | mod inlay_hints; |
36 | mod join_lines; | 37 | mod join_lines; |
@@ -75,14 +76,14 @@ pub use crate::{ | |||
75 | references::{rename::RenameError, Declaration, ReferenceSearchResult}, | 76 | references::{rename::RenameError, Declaration, ReferenceSearchResult}, |
76 | runnables::{Runnable, RunnableKind, TestId}, | 77 | runnables::{Runnable, RunnableKind, TestId}, |
77 | syntax_highlighting::{ | 78 | syntax_highlighting::{ |
78 | tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}, | 79 | tags::{Highlight, HlMod, HlMods, HlPunct, HlTag}, |
79 | HighlightedRange, | 80 | HlRange, |
80 | }, | 81 | }, |
81 | }; | 82 | }; |
82 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind}; | 83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig}; |
83 | pub use completion::{ | 84 | pub use completion::{ |
84 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionResolveCapability, | 85 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, |
85 | CompletionScore, ImportEdit, InsertTextFormat, | 86 | InsertTextFormat, |
86 | }; | 87 | }; |
87 | pub use hir::{Documentation, Semantics}; | 88 | pub use hir::{Documentation, Semantics}; |
88 | pub use ide_db::base_db::{ | 89 | pub use ide_db::base_db::{ |
@@ -91,7 +92,7 @@ pub use ide_db::base_db::{ | |||
91 | }; | 92 | }; |
92 | pub use ide_db::{ | 93 | pub use ide_db::{ |
93 | call_info::CallInfo, | 94 | call_info::CallInfo, |
94 | search::{Reference, ReferenceAccess, ReferenceKind}, | 95 | search::{FileReference, ReferenceAccess, ReferenceKind}, |
95 | }; | 96 | }; |
96 | pub use ide_db::{ | 97 | pub use ide_db::{ |
97 | label::Label, | 98 | label::Label, |
@@ -271,6 +272,10 @@ impl Analysis { | |||
271 | self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) | 272 | self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) |
272 | } | 273 | } |
273 | 274 | ||
275 | pub fn view_hir(&self, position: FilePosition) -> Cancelable<String> { | ||
276 | self.with_db(|db| view_hir::view_hir(&db, position)) | ||
277 | } | ||
278 | |||
274 | pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> { | 279 | pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> { |
275 | self.with_db(|db| expand_macro::expand_macro(db, position)) | 280 | self.with_db(|db| expand_macro::expand_macro(db, position)) |
276 | } | 281 | } |
@@ -444,12 +449,12 @@ impl Analysis { | |||
444 | } | 449 | } |
445 | 450 | ||
446 | /// Computes syntax highlighting for the given file | 451 | /// Computes syntax highlighting for the given file |
447 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 452 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HlRange>> { |
448 | self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) | 453 | self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) |
449 | } | 454 | } |
450 | 455 | ||
451 | /// Computes syntax highlighting for the given file range. | 456 | /// Computes syntax highlighting for the given file range. |
452 | pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HighlightedRange>> { | 457 | pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HlRange>> { |
453 | self.with_db(|db| { | 458 | self.with_db(|db| { |
454 | syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) | 459 | syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) |
455 | }) | 460 | }) |
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index d70248afe..1bfa1439d 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs | |||
@@ -58,15 +58,15 @@ mod tests { | |||
58 | assert_eq_text!(after, &actual); | 58 | assert_eq_text!(after, &actual); |
59 | } | 59 | } |
60 | 60 | ||
61 | do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); | 61 | do_check("struct Foo { a: i32, }$0", "struct Foo $0{ a: i32, }"); |
62 | do_check("fn main() { |x: i32|<|> x * 2;}", "fn main() { <|>|x: i32| x * 2;}"); | 62 | do_check("fn main() { |x: i32|$0 x * 2;}", "fn main() { $0|x: i32| x * 2;}"); |
63 | do_check("fn main() { <|>|x: i32| x * 2;}", "fn main() { |x: i32<|>| x * 2;}"); | 63 | do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}"); |
64 | 64 | ||
65 | { | 65 | { |
66 | mark::check!(pipes_not_braces); | 66 | mark::check!(pipes_not_braces); |
67 | do_check( | 67 | do_check( |
68 | "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", | 68 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", |
69 | "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", | 69 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", |
70 | ); | 70 | ); |
71 | } | 71 | } |
72 | } | 72 | } |
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index be344a09b..d343638fb 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs | |||
@@ -74,7 +74,7 @@ mod tests { | |||
74 | //- /lib.rs | 74 | //- /lib.rs |
75 | mod foo; | 75 | mod foo; |
76 | //- /foo.rs | 76 | //- /foo.rs |
77 | <|>// empty | 77 | $0// empty |
78 | ", | 78 | ", |
79 | ); | 79 | ); |
80 | let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); | 80 | let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); |
@@ -90,7 +90,7 @@ mod tests { | |||
90 | mod foo; | 90 | mod foo; |
91 | 91 | ||
92 | //- /foo.rs | 92 | //- /foo.rs |
93 | mod <|>bar; | 93 | mod $0bar; |
94 | 94 | ||
95 | //- /foo/bar.rs | 95 | //- /foo/bar.rs |
96 | // empty | 96 | // empty |
@@ -107,7 +107,7 @@ mod tests { | |||
107 | //- /lib.rs | 107 | //- /lib.rs |
108 | mod foo { | 108 | mod foo { |
109 | mod bar { | 109 | mod bar { |
110 | mod baz { <|> } | 110 | mod baz { $0 } |
111 | } | 111 | } |
112 | } | 112 | } |
113 | ", | 113 | ", |
@@ -123,7 +123,7 @@ mod tests { | |||
123 | //- /main.rs | 123 | //- /main.rs |
124 | mod foo; | 124 | mod foo; |
125 | //- /foo.rs | 125 | //- /foo.rs |
126 | <|> | 126 | $0 |
127 | "#, | 127 | "#, |
128 | ); | 128 | ); |
129 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); | 129 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 21b2d7ca1..7d4757e02 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | //! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we | 3 | //! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we |
4 | //! try to resolve the direct tree parent of this element, otherwise we | 4 | //! try to resolve the direct tree parent of this element, otherwise we |
5 | //! already have a definition and just need to get its HIR together with | 5 | //! already have a definition and just need to get its HIR together with |
6 | //! some information that is needed for futher steps of searching. | 6 | //! some information that is needed for further steps of searching. |
7 | //! After that, we collect files that might contain references and look | 7 | //! After that, we collect files that might contain references and look |
8 | //! for text occurrences of the identifier. If there's an `ast::NameRef` | 8 | //! for text occurrences of the identifier. If there's an `ast::NameRef` |
9 | //! at the index that the match starts at and its tree parent is | 9 | //! at the index that the match starts at and its tree parent is |
@@ -13,15 +13,15 @@ pub(crate) mod rename; | |||
13 | 13 | ||
14 | use hir::Semantics; | 14 | use hir::Semantics; |
15 | use ide_db::{ | 15 | use ide_db::{ |
16 | base_db::FileId, | ||
16 | defs::{Definition, NameClass, NameRefClass}, | 17 | defs::{Definition, NameClass, NameRefClass}, |
17 | search::Reference, | 18 | search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult}, |
18 | search::{ReferenceAccess, ReferenceKind, SearchScope}, | ||
19 | RootDatabase, | 19 | RootDatabase, |
20 | }; | 20 | }; |
21 | use syntax::{ | 21 | use syntax::{ |
22 | algo::find_node_at_offset, | 22 | algo::find_node_at_offset, |
23 | ast::{self, NameOwner}, | 23 | ast::{self, NameOwner}, |
24 | match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset, | 24 | match_ast, AstNode, SyntaxNode, TextRange, TokenAtOffset, T, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; | 27 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; |
@@ -29,7 +29,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI | |||
29 | #[derive(Debug, Clone)] | 29 | #[derive(Debug, Clone)] |
30 | pub struct ReferenceSearchResult { | 30 | pub struct ReferenceSearchResult { |
31 | declaration: Declaration, | 31 | declaration: Declaration, |
32 | references: Vec<Reference>, | 32 | references: UsageSearchResult, |
33 | } | 33 | } |
34 | 34 | ||
35 | #[derive(Debug, Clone)] | 35 | #[derive(Debug, Clone)] |
@@ -48,10 +48,21 @@ impl ReferenceSearchResult { | |||
48 | &self.declaration.nav | 48 | &self.declaration.nav |
49 | } | 49 | } |
50 | 50 | ||
51 | pub fn references(&self) -> &[Reference] { | 51 | pub fn references(&self) -> &UsageSearchResult { |
52 | &self.references | 52 | &self.references |
53 | } | 53 | } |
54 | 54 | ||
55 | pub fn references_with_declaration(mut self) -> UsageSearchResult { | ||
56 | let decl_ref = FileReference { | ||
57 | range: self.declaration.nav.focus_or_full_range(), | ||
58 | kind: self.declaration.kind, | ||
59 | access: self.declaration.access, | ||
60 | }; | ||
61 | let file_id = self.declaration.nav.file_id; | ||
62 | self.references.references.entry(file_id).or_default().push(decl_ref); | ||
63 | self.references | ||
64 | } | ||
65 | |||
55 | /// Total number of references | 66 | /// Total number of references |
56 | /// At least 1 since all valid references should | 67 | /// At least 1 since all valid references should |
57 | /// Have a declaration | 68 | /// Have a declaration |
@@ -63,21 +74,11 @@ impl ReferenceSearchResult { | |||
63 | // allow turning ReferenceSearchResult into an iterator | 74 | // allow turning ReferenceSearchResult into an iterator |
64 | // over References | 75 | // over References |
65 | impl IntoIterator for ReferenceSearchResult { | 76 | impl IntoIterator for ReferenceSearchResult { |
66 | type Item = Reference; | 77 | type Item = (FileId, Vec<FileReference>); |
67 | type IntoIter = std::vec::IntoIter<Reference>; | 78 | type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>; |
68 | 79 | ||
69 | fn into_iter(mut self) -> Self::IntoIter { | 80 | fn into_iter(self) -> Self::IntoIter { |
70 | let mut v = Vec::with_capacity(self.len()); | 81 | self.references_with_declaration().into_iter() |
71 | v.push(Reference { | ||
72 | file_range: FileRange { | ||
73 | file_id: self.declaration.nav.file_id, | ||
74 | range: self.declaration.nav.focus_or_full_range(), | ||
75 | }, | ||
76 | kind: self.declaration.kind, | ||
77 | access: self.declaration.access, | ||
78 | }); | ||
79 | v.append(&mut self.references); | ||
80 | v.into_iter() | ||
81 | } | 82 | } |
82 | } | 83 | } |
83 | 84 | ||
@@ -109,13 +110,12 @@ pub(crate) fn find_all_refs( | |||
109 | 110 | ||
110 | let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; | 111 | let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; |
111 | 112 | ||
112 | let references = def | 113 | let mut usages = def.usages(sema).set_scope(search_scope).all(); |
113 | .usages(sema) | 114 | usages |
114 | .set_scope(search_scope) | 115 | .references |
115 | .all() | 116 | .values_mut() |
116 | .into_iter() | 117 | .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)); |
117 | .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) | 118 | usages.references.retain(|_, it| !it.is_empty()); |
118 | .collect(); | ||
119 | 119 | ||
120 | let nav = def.try_to_nav(sema.db)?; | 120 | let nav = def.try_to_nav(sema.db)?; |
121 | let decl_range = nav.focus_or_full_range(); | 121 | let decl_range = nav.focus_or_full_range(); |
@@ -130,13 +130,16 @@ pub(crate) fn find_all_refs( | |||
130 | kind = ReferenceKind::FieldShorthandForLocal; | 130 | kind = ReferenceKind::FieldShorthandForLocal; |
131 | } | 131 | } |
132 | } | 132 | } |
133 | } else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) { | 133 | } else if matches!( |
134 | def, | ||
135 | Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) | ||
136 | ) { | ||
134 | kind = ReferenceKind::Lifetime; | 137 | kind = ReferenceKind::Lifetime; |
135 | }; | 138 | }; |
136 | 139 | ||
137 | let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; | 140 | let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; |
138 | 141 | ||
139 | Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) | 142 | Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages })) |
140 | } | 143 | } |
141 | 144 | ||
142 | fn find_name( | 145 | fn find_name( |
@@ -200,7 +203,7 @@ fn get_struct_def_name_for_struct_literal_search( | |||
200 | position: FilePosition, | 203 | position: FilePosition, |
201 | ) -> Option<ast::Name> { | 204 | ) -> Option<ast::Name> { |
202 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { | 205 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { |
203 | if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { | 206 | if right.kind() != T!['{'] && right.kind() != T!['('] { |
204 | return None; | 207 | return None; |
205 | } | 208 | } |
206 | if let Some(name) = | 209 | if let Some(name) = |
@@ -227,7 +230,7 @@ fn get_enum_def_name_for_struct_literal_search( | |||
227 | position: FilePosition, | 230 | position: FilePosition, |
228 | ) -> Option<ast::Name> { | 231 | ) -> Option<ast::Name> { |
229 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { | 232 | if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { |
230 | if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { | 233 | if right.kind() != T!['{'] && right.kind() != T!['('] { |
231 | return None; | 234 | return None; |
232 | } | 235 | } |
233 | if let Some(name) = | 236 | if let Some(name) = |
@@ -252,8 +255,8 @@ fn try_find_self_references( | |||
252 | syntax: &SyntaxNode, | 255 | syntax: &SyntaxNode, |
253 | position: FilePosition, | 256 | position: FilePosition, |
254 | ) -> Option<RangeInfo<ReferenceSearchResult>> { | 257 | ) -> Option<RangeInfo<ReferenceSearchResult>> { |
255 | let self_token = | 258 | let FilePosition { file_id, offset } = position; |
256 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)?; | 259 | let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?; |
257 | let parent = self_token.parent(); | 260 | let parent = self_token.parent(); |
258 | match_ast! { | 261 | match_ast! { |
259 | match parent { | 262 | match parent { |
@@ -274,7 +277,7 @@ fn try_find_self_references( | |||
274 | 277 | ||
275 | let declaration = Declaration { | 278 | let declaration = Declaration { |
276 | nav: NavigationTarget { | 279 | nav: NavigationTarget { |
277 | file_id: position.file_id, | 280 | file_id, |
278 | full_range: self_param.syntax().text_range(), | 281 | full_range: self_param.syntax().text_range(), |
279 | focus_range: Some(param_self_token.text_range()), | 282 | focus_range: Some(param_self_token.text_range()), |
280 | name: param_self_token.text().clone(), | 283 | name: param_self_token.text().clone(), |
@@ -290,7 +293,7 @@ fn try_find_self_references( | |||
290 | ReferenceAccess::Read | 293 | ReferenceAccess::Read |
291 | }), | 294 | }), |
292 | }; | 295 | }; |
293 | let references = function | 296 | let refs = function |
294 | .body() | 297 | .body() |
295 | .map(|body| { | 298 | .map(|body| { |
296 | body.syntax() | 299 | body.syntax() |
@@ -304,14 +307,16 @@ fn try_find_self_references( | |||
304 | None | 307 | None |
305 | } | 308 | } |
306 | }) | 309 | }) |
307 | .map(|token| Reference { | 310 | .map(|token| FileReference { |
308 | file_range: FileRange { file_id: position.file_id, range: token.text_range() }, | 311 | range: token.text_range(), |
309 | kind: ReferenceKind::SelfKw, | 312 | kind: ReferenceKind::SelfKw, |
310 | access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration | 313 | access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration |
311 | }) | 314 | }) |
312 | .collect() | 315 | .collect() |
313 | }) | 316 | }) |
314 | .unwrap_or_default(); | 317 | .unwrap_or_default(); |
318 | let mut references = UsageSearchResult::default(); | ||
319 | references.references.insert(file_id, refs); | ||
315 | 320 | ||
316 | Some(RangeInfo::new( | 321 | Some(RangeInfo::new( |
317 | param_self_token.text_range(), | 322 | param_self_token.text_range(), |
@@ -331,7 +336,7 @@ mod tests { | |||
331 | fn test_struct_literal_after_space() { | 336 | fn test_struct_literal_after_space() { |
332 | check( | 337 | check( |
333 | r#" | 338 | r#" |
334 | struct Foo <|>{ | 339 | struct Foo $0{ |
335 | a: i32, | 340 | a: i32, |
336 | } | 341 | } |
337 | impl Foo { | 342 | impl Foo { |
@@ -354,7 +359,7 @@ fn main() { | |||
354 | fn test_struct_literal_before_space() { | 359 | fn test_struct_literal_before_space() { |
355 | check( | 360 | check( |
356 | r#" | 361 | r#" |
357 | struct Foo<|> {} | 362 | struct Foo$0 {} |
358 | fn main() { | 363 | fn main() { |
359 | let f: Foo; | 364 | let f: Foo; |
360 | f = Foo {}; | 365 | f = Foo {}; |
@@ -373,7 +378,7 @@ struct Foo<|> {} | |||
373 | fn test_struct_literal_with_generic_type() { | 378 | fn test_struct_literal_with_generic_type() { |
374 | check( | 379 | check( |
375 | r#" | 380 | r#" |
376 | struct Foo<T> <|>{} | 381 | struct Foo<T> $0{} |
377 | fn main() { | 382 | fn main() { |
378 | let f: Foo::<i32>; | 383 | let f: Foo::<i32>; |
379 | f = Foo {}; | 384 | f = Foo {}; |
@@ -391,7 +396,7 @@ struct Foo<T> <|>{} | |||
391 | fn test_struct_literal_for_tuple() { | 396 | fn test_struct_literal_for_tuple() { |
392 | check( | 397 | check( |
393 | r#" | 398 | r#" |
394 | struct Foo<|>(i32); | 399 | struct Foo$0(i32); |
395 | 400 | ||
396 | fn main() { | 401 | fn main() { |
397 | let f: Foo; | 402 | let f: Foo; |
@@ -410,7 +415,7 @@ fn main() { | |||
410 | fn test_enum_after_space() { | 415 | fn test_enum_after_space() { |
411 | check( | 416 | check( |
412 | r#" | 417 | r#" |
413 | enum Foo <|>{ | 418 | enum Foo $0{ |
414 | A, | 419 | A, |
415 | B, | 420 | B, |
416 | } | 421 | } |
@@ -431,7 +436,7 @@ fn main() { | |||
431 | fn test_enum_before_space() { | 436 | fn test_enum_before_space() { |
432 | check( | 437 | check( |
433 | r#" | 438 | r#" |
434 | enum Foo<|> { | 439 | enum Foo$0 { |
435 | A, | 440 | A, |
436 | B, | 441 | B, |
437 | } | 442 | } |
@@ -453,7 +458,7 @@ fn main() { | |||
453 | fn test_enum_with_generic_type() { | 458 | fn test_enum_with_generic_type() { |
454 | check( | 459 | check( |
455 | r#" | 460 | r#" |
456 | enum Foo<T> <|>{ | 461 | enum Foo<T> $0{ |
457 | A(T), | 462 | A(T), |
458 | B, | 463 | B, |
459 | } | 464 | } |
@@ -474,7 +479,7 @@ fn main() { | |||
474 | fn test_enum_for_tuple() { | 479 | fn test_enum_for_tuple() { |
475 | check( | 480 | check( |
476 | r#" | 481 | r#" |
477 | enum Foo<|>{ | 482 | enum Foo$0{ |
478 | A(i8), | 483 | A(i8), |
479 | B(i8), | 484 | B(i8), |
480 | } | 485 | } |
@@ -498,7 +503,7 @@ fn main() { | |||
498 | fn main() { | 503 | fn main() { |
499 | let mut i = 1; | 504 | let mut i = 1; |
500 | let j = 1; | 505 | let j = 1; |
501 | i = i<|> + j; | 506 | i = i$0 + j; |
502 | 507 | ||
503 | { | 508 | { |
504 | i = 0; | 509 | i = 0; |
@@ -522,7 +527,7 @@ fn main() { | |||
522 | check( | 527 | check( |
523 | r#" | 528 | r#" |
524 | fn foo() { | 529 | fn foo() { |
525 | let spam<|> = 92; | 530 | let spam$0 = 92; |
526 | spam + spam | 531 | spam + spam |
527 | } | 532 | } |
528 | fn bar() { | 533 | fn bar() { |
@@ -543,7 +548,7 @@ fn bar() { | |||
543 | fn test_find_all_refs_for_param_inside() { | 548 | fn test_find_all_refs_for_param_inside() { |
544 | check( | 549 | check( |
545 | r#" | 550 | r#" |
546 | fn foo(i : u32) -> u32 { i<|> } | 551 | fn foo(i : u32) -> u32 { i$0 } |
547 | "#, | 552 | "#, |
548 | expect![[r#" | 553 | expect![[r#" |
549 | i ValueParam FileId(0) 7..8 Other | 554 | i ValueParam FileId(0) 7..8 Other |
@@ -557,7 +562,7 @@ fn foo(i : u32) -> u32 { i<|> } | |||
557 | fn test_find_all_refs_for_fn_param() { | 562 | fn test_find_all_refs_for_fn_param() { |
558 | check( | 563 | check( |
559 | r#" | 564 | r#" |
560 | fn foo(i<|> : u32) -> u32 { i } | 565 | fn foo(i$0 : u32) -> u32 { i } |
561 | "#, | 566 | "#, |
562 | expect![[r#" | 567 | expect![[r#" |
563 | i ValueParam FileId(0) 7..8 Other | 568 | i ValueParam FileId(0) 7..8 Other |
@@ -573,7 +578,7 @@ fn foo(i<|> : u32) -> u32 { i } | |||
573 | r#" | 578 | r#" |
574 | //- /lib.rs | 579 | //- /lib.rs |
575 | struct Foo { | 580 | struct Foo { |
576 | pub spam<|>: u32, | 581 | pub spam$0: u32, |
577 | } | 582 | } |
578 | 583 | ||
579 | fn main(s: Foo) { | 584 | fn main(s: Foo) { |
@@ -594,7 +599,7 @@ fn main(s: Foo) { | |||
594 | r#" | 599 | r#" |
595 | struct Foo; | 600 | struct Foo; |
596 | impl Foo { | 601 | impl Foo { |
597 | fn f<|>(&self) { } | 602 | fn f$0(&self) { } |
598 | } | 603 | } |
599 | "#, | 604 | "#, |
600 | expect![[r#" | 605 | expect![[r#" |
@@ -610,7 +615,7 @@ impl Foo { | |||
610 | r#" | 615 | r#" |
611 | enum Foo { | 616 | enum Foo { |
612 | A, | 617 | A, |
613 | B<|>, | 618 | B$0, |
614 | C, | 619 | C, |
615 | } | 620 | } |
616 | "#, | 621 | "#, |
@@ -627,7 +632,7 @@ enum Foo { | |||
627 | r#" | 632 | r#" |
628 | enum Foo { | 633 | enum Foo { |
629 | A, | 634 | A, |
630 | B { field<|>: u8 }, | 635 | B { field$0: u8 }, |
631 | C, | 636 | C, |
632 | } | 637 | } |
633 | "#, | 638 | "#, |
@@ -669,7 +674,7 @@ pub struct Bar { | |||
669 | } | 674 | } |
670 | 675 | ||
671 | fn f() { | 676 | fn f() { |
672 | let i = foo::Foo<|> { n: 5 }; | 677 | let i = foo::Foo$0 { n: 5 }; |
673 | } | 678 | } |
674 | "#, | 679 | "#, |
675 | expect![[r#" | 680 | expect![[r#" |
@@ -689,7 +694,7 @@ fn f() { | |||
689 | check( | 694 | check( |
690 | r#" | 695 | r#" |
691 | //- /lib.rs | 696 | //- /lib.rs |
692 | mod foo<|>; | 697 | mod foo$0; |
693 | 698 | ||
694 | use foo::Foo; | 699 | use foo::Foo; |
695 | 700 | ||
@@ -726,7 +731,7 @@ fn f() { | |||
726 | } | 731 | } |
727 | 732 | ||
728 | //- /foo/some.rs | 733 | //- /foo/some.rs |
729 | pub(super) struct Foo<|> { | 734 | pub(super) struct Foo$0 { |
730 | pub n: u32, | 735 | pub n: u32, |
731 | } | 736 | } |
732 | "#, | 737 | "#, |
@@ -746,7 +751,7 @@ pub(super) struct Foo<|> { | |||
746 | mod foo; | 751 | mod foo; |
747 | mod bar; | 752 | mod bar; |
748 | 753 | ||
749 | pub fn quux<|>() {} | 754 | pub fn quux$0() {} |
750 | 755 | ||
751 | //- /foo.rs | 756 | //- /foo.rs |
752 | fn f() { super::quux(); } | 757 | fn f() { super::quux(); } |
@@ -782,7 +787,7 @@ pub(super) struct Foo<|> { | |||
782 | check( | 787 | check( |
783 | r#" | 788 | r#" |
784 | #[macro_export] | 789 | #[macro_export] |
785 | macro_rules! m1<|> { () => (()) } | 790 | macro_rules! m1$0 { () => (()) } |
786 | 791 | ||
787 | fn foo() { | 792 | fn foo() { |
788 | m1(); | 793 | m1(); |
@@ -803,7 +808,7 @@ fn foo() { | |||
803 | check( | 808 | check( |
804 | r#" | 809 | r#" |
805 | fn foo() { | 810 | fn foo() { |
806 | let mut i<|> = 0; | 811 | let mut i$0 = 0; |
807 | i = i + 1; | 812 | i = i + 1; |
808 | } | 813 | } |
809 | "#, | 814 | "#, |
@@ -826,7 +831,7 @@ struct S { | |||
826 | 831 | ||
827 | fn foo() { | 832 | fn foo() { |
828 | let mut s = S{f: 0}; | 833 | let mut s = S{f: 0}; |
829 | s.f<|> = 0; | 834 | s.f$0 = 0; |
830 | } | 835 | } |
831 | "#, | 836 | "#, |
832 | expect![[r#" | 837 | expect![[r#" |
@@ -843,7 +848,7 @@ fn foo() { | |||
843 | check( | 848 | check( |
844 | r#" | 849 | r#" |
845 | fn foo() { | 850 | fn foo() { |
846 | let i<|>; | 851 | let i$0; |
847 | i = 1; | 852 | i = 1; |
848 | } | 853 | } |
849 | "#, | 854 | "#, |
@@ -863,7 +868,7 @@ mod foo { | |||
863 | pub struct Foo; | 868 | pub struct Foo; |
864 | 869 | ||
865 | impl Foo { | 870 | impl Foo { |
866 | pub fn new<|>() -> Foo { Foo } | 871 | pub fn new$0() -> Foo { Foo } |
867 | } | 872 | } |
868 | } | 873 | } |
869 | 874 | ||
@@ -886,7 +891,7 @@ fn main() { | |||
886 | //- /lib.rs | 891 | //- /lib.rs |
887 | mod foo { mod bar; } | 892 | mod foo { mod bar; } |
888 | 893 | ||
889 | fn f<|>() {} | 894 | fn f$0() {} |
890 | 895 | ||
891 | //- /foo/bar.rs | 896 | //- /foo/bar.rs |
892 | use crate::f; | 897 | use crate::f; |
@@ -907,7 +912,7 @@ fn g() { f(); } | |||
907 | check( | 912 | check( |
908 | r#" | 913 | r#" |
909 | struct S { | 914 | struct S { |
910 | field<|>: u8, | 915 | field$0: u8, |
911 | } | 916 | } |
912 | 917 | ||
913 | fn f(s: S) { | 918 | fn f(s: S) { |
@@ -930,7 +935,7 @@ fn f(s: S) { | |||
930 | r#" | 935 | r#" |
931 | enum En { | 936 | enum En { |
932 | Variant { | 937 | Variant { |
933 | field<|>: u8, | 938 | field$0: u8, |
934 | } | 939 | } |
935 | } | 940 | } |
936 | 941 | ||
@@ -955,7 +960,7 @@ fn f(e: En) { | |||
955 | mod m { | 960 | mod m { |
956 | pub enum En { | 961 | pub enum En { |
957 | Variant { | 962 | Variant { |
958 | field<|>: u8, | 963 | field$0: u8, |
959 | } | 964 | } |
960 | } | 965 | } |
961 | } | 966 | } |
@@ -980,7 +985,7 @@ struct Foo { bar: i32 } | |||
980 | 985 | ||
981 | impl Foo { | 986 | impl Foo { |
982 | fn foo(self) { | 987 | fn foo(self) { |
983 | let x = self<|>.bar; | 988 | let x = self$0.bar; |
984 | if true { | 989 | if true { |
985 | let _ = match () { | 990 | let _ = match () { |
986 | () => self, | 991 | () => self, |
@@ -1016,12 +1021,14 @@ impl Foo { | |||
1016 | actual += "\n\n"; | 1021 | actual += "\n\n"; |
1017 | } | 1022 | } |
1018 | 1023 | ||
1019 | for r in &refs.references { | 1024 | for (file_id, references) in refs.references { |
1020 | format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); | 1025 | for r in references { |
1021 | if let Some(access) = r.access { | 1026 | format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind); |
1022 | format_to!(actual, " {:?}", access); | 1027 | if let Some(access) = r.access { |
1028 | format_to!(actual, " {:?}", access); | ||
1029 | } | ||
1030 | actual += "\n"; | ||
1023 | } | 1031 | } |
1024 | actual += "\n"; | ||
1025 | } | 1032 | } |
1026 | expect.assert_eq(&actual) | 1033 | expect.assert_eq(&actual) |
1027 | } | 1034 | } |
@@ -1032,7 +1039,7 @@ impl Foo { | |||
1032 | r#" | 1039 | r#" |
1033 | trait Foo<'a> {} | 1040 | trait Foo<'a> {} |
1034 | impl<'a> Foo<'a> for &'a () {} | 1041 | impl<'a> Foo<'a> for &'a () {} |
1035 | fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> { | 1042 | fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> { |
1036 | fn bar<'a>(_: &'a ()) {} | 1043 | fn bar<'a>(_: &'a ()) {} |
1037 | x | 1044 | x |
1038 | } | 1045 | } |
@@ -1053,7 +1060,7 @@ fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> { | |||
1053 | fn test_find_lifetimes_type_alias() { | 1060 | fn test_find_lifetimes_type_alias() { |
1054 | check( | 1061 | check( |
1055 | r#" | 1062 | r#" |
1056 | type Foo<'a, T> where T: 'a<|> = &'a T; | 1063 | type Foo<'a, T> where T: 'a$0 = &'a T; |
1057 | "#, | 1064 | "#, |
1058 | expect![[r#" | 1065 | expect![[r#" |
1059 | 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime | 1066 | 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime |
@@ -1072,7 +1079,7 @@ trait Foo<'a> { | |||
1072 | fn foo() -> &'a (); | 1079 | fn foo() -> &'a (); |
1073 | } | 1080 | } |
1074 | impl<'a> Foo<'a> for &'a () { | 1081 | impl<'a> Foo<'a> for &'a () { |
1075 | fn foo() -> &'a<|> () { | 1082 | fn foo() -> &'a$0 () { |
1076 | unimplemented!() | 1083 | unimplemented!() |
1077 | } | 1084 | } |
1078 | } | 1085 | } |
@@ -1093,7 +1100,7 @@ impl<'a> Foo<'a> for &'a () { | |||
1093 | r#" | 1100 | r#" |
1094 | macro_rules! foo {($i:ident) => {$i} } | 1101 | macro_rules! foo {($i:ident) => {$i} } |
1095 | fn main() { | 1102 | fn main() { |
1096 | let a<|> = "test"; | 1103 | let a$0 = "test"; |
1097 | foo!(a); | 1104 | foo!(a); |
1098 | } | 1105 | } |
1099 | "#, | 1106 | "#, |
@@ -1112,7 +1119,7 @@ fn main() { | |||
1112 | macro_rules! foo {($i:ident) => {$i} } | 1119 | macro_rules! foo {($i:ident) => {$i} } |
1113 | fn main() { | 1120 | fn main() { |
1114 | let a = "test"; | 1121 | let a = "test"; |
1115 | foo!(a<|>); | 1122 | foo!(a$0); |
1116 | } | 1123 | } |
1117 | "#, | 1124 | "#, |
1118 | expect![[r#" | 1125 | expect![[r#" |
@@ -1130,7 +1137,7 @@ fn main() { | |||
1130 | fn foo<'a>() -> &'a () { | 1137 | fn foo<'a>() -> &'a () { |
1131 | 'a: loop { | 1138 | 'a: loop { |
1132 | 'b: loop { | 1139 | 'b: loop { |
1133 | continue 'a<|>; | 1140 | continue 'a$0; |
1134 | } | 1141 | } |
1135 | break 'a; | 1142 | break 'a; |
1136 | } | 1143 | } |
@@ -1144,4 +1151,20 @@ fn foo<'a>() -> &'a () { | |||
1144 | "#]], | 1151 | "#]], |
1145 | ); | 1152 | ); |
1146 | } | 1153 | } |
1154 | |||
1155 | #[test] | ||
1156 | fn test_find_const_param() { | ||
1157 | check( | ||
1158 | r#" | ||
1159 | fn foo<const FOO$0: usize>() -> usize { | ||
1160 | FOO | ||
1161 | } | ||
1162 | "#, | ||
1163 | expect![[r#" | ||
1164 | FOO ConstParam FileId(0) 7..23 13..16 Other | ||
1165 | |||
1166 | FileId(0) 42..45 Other | ||
1167 | "#]], | ||
1168 | ); | ||
1169 | } | ||
1147 | } | 1170 | } |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 854bf194e..c3ae568c2 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -1,29 +1,30 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::{ | 2 | use std::{ |
3 | convert::TryInto, | 3 | convert::TryInto, |
4 | error::Error, | ||
5 | fmt::{self, Display}, | 4 | fmt::{self, Display}, |
6 | }; | 5 | }; |
7 | 6 | ||
8 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; | 7 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; |
9 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}; | ||
10 | use ide_db::{ | 8 | use ide_db::{ |
9 | base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}, | ||
11 | defs::{Definition, NameClass, NameRefClass}, | 10 | defs::{Definition, NameClass, NameRefClass}, |
11 | search::FileReference, | ||
12 | RootDatabase, | 12 | RootDatabase, |
13 | }; | 13 | }; |
14 | use syntax::{ | 14 | use syntax::{ |
15 | algo::find_node_at_offset, | 15 | algo::find_node_at_offset, |
16 | ast::{self, NameOwner}, | 16 | ast::{self, NameOwner}, |
17 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, | 17 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, T, |
18 | }; | 18 | }; |
19 | use test_utils::mark; | 19 | use test_utils::mark; |
20 | use text_edit::TextEdit; | 20 | use text_edit::TextEdit; |
21 | 21 | ||
22 | use crate::{ | 22 | use crate::{ |
23 | references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, | 23 | FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange, |
24 | SourceChange, SourceFileEdit, TextRange, TextSize, | 24 | SourceFileEdit, TextRange, TextSize, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | type RenameResult<T> = Result<T, RenameError>; | ||
27 | #[derive(Debug)] | 28 | #[derive(Debug)] |
28 | pub struct RenameError(pub(crate) String); | 29 | pub struct RenameError(pub(crate) String); |
29 | 30 | ||
@@ -33,26 +34,30 @@ impl fmt::Display for RenameError { | |||
33 | } | 34 | } |
34 | } | 35 | } |
35 | 36 | ||
36 | impl Error for RenameError {} | 37 | macro_rules! format_err { |
38 | ($fmt:expr) => {RenameError(format!($fmt))}; | ||
39 | ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))} | ||
40 | } | ||
41 | |||
42 | macro_rules! bail { | ||
43 | ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))} | ||
44 | } | ||
37 | 45 | ||
38 | pub(crate) fn prepare_rename( | 46 | pub(crate) fn prepare_rename( |
39 | db: &RootDatabase, | 47 | db: &RootDatabase, |
40 | position: FilePosition, | 48 | position: FilePosition, |
41 | ) -> Result<RangeInfo<()>, RenameError> { | 49 | ) -> RenameResult<RangeInfo<()>> { |
42 | let sema = Semantics::new(db); | 50 | let sema = Semantics::new(db); |
43 | let source_file = sema.parse(position.file_id); | 51 | let source_file = sema.parse(position.file_id); |
44 | let syntax = source_file.syntax(); | 52 | let syntax = source_file.syntax(); |
45 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { | 53 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { |
46 | rename_mod(&sema, position, module, "dummy") | 54 | rename_mod(&sema, position, module, "dummy") |
47 | } else if let Some(self_token) = | 55 | } else if let Some(self_token) = |
48 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | 56 | syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self]) |
49 | { | 57 | { |
50 | rename_self_to_param(&sema, position, self_token, "dummy") | 58 | rename_self_to_param(&sema, position, self_token, "dummy") |
51 | } else { | 59 | } else { |
52 | let range = match find_all_refs(&sema, position, None) { | 60 | let RangeInfo { range, .. } = find_all_refs(&sema, position)?; |
53 | Some(RangeInfo { range, .. }) => range, | ||
54 | None => return Err(RenameError("No references found at position".to_string())), | ||
55 | }; | ||
56 | Ok(RangeInfo::new(range, SourceChange::from(vec![]))) | 61 | Ok(RangeInfo::new(range, SourceChange::from(vec![]))) |
57 | } | 62 | } |
58 | .map(|info| RangeInfo::new(info.range, ())) | 63 | .map(|info| RangeInfo::new(info.range, ())) |
@@ -62,7 +67,7 @@ pub(crate) fn rename( | |||
62 | db: &RootDatabase, | 67 | db: &RootDatabase, |
63 | position: FilePosition, | 68 | position: FilePosition, |
64 | new_name: &str, | 69 | new_name: &str, |
65 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 70 | ) -> RenameResult<RangeInfo<SourceChange>> { |
66 | let sema = Semantics::new(db); | 71 | let sema = Semantics::new(db); |
67 | rename_with_semantics(&sema, position, new_name) | 72 | rename_with_semantics(&sema, position, new_name) |
68 | } | 73 | } |
@@ -71,42 +76,18 @@ pub(crate) fn rename_with_semantics( | |||
71 | sema: &Semantics<RootDatabase>, | 76 | sema: &Semantics<RootDatabase>, |
72 | position: FilePosition, | 77 | position: FilePosition, |
73 | new_name: &str, | 78 | new_name: &str, |
74 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 79 | ) -> RenameResult<RangeInfo<SourceChange>> { |
75 | let is_lifetime_name = match lex_single_syntax_kind(new_name) { | ||
76 | Some(res) => match res { | ||
77 | (SyntaxKind::IDENT, _) => false, | ||
78 | (SyntaxKind::UNDERSCORE, _) => false, | ||
79 | (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position), | ||
80 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => true, | ||
81 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
82 | return Err(RenameError(format!( | ||
83 | "Invalid name `{0}`: Cannot rename lifetime to {0}", | ||
84 | new_name | ||
85 | ))) | ||
86 | } | ||
87 | (_, Some(syntax_error)) => { | ||
88 | return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error))) | ||
89 | } | ||
90 | (_, None) => { | ||
91 | return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) | ||
92 | } | ||
93 | }, | ||
94 | None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))), | ||
95 | }; | ||
96 | |||
97 | let source_file = sema.parse(position.file_id); | 80 | let source_file = sema.parse(position.file_id); |
98 | let syntax = source_file.syntax(); | 81 | let syntax = source_file.syntax(); |
99 | // this is here to prevent lifetime renames from happening on modules and self | 82 | |
100 | if is_lifetime_name { | 83 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { |
101 | rename_reference(&sema, position, new_name, is_lifetime_name) | ||
102 | } else if let Some(module) = find_module_at_offset(&sema, position, syntax) { | ||
103 | rename_mod(&sema, position, module, new_name) | 84 | rename_mod(&sema, position, module, new_name) |
104 | } else if let Some(self_token) = | 85 | } else if let Some(self_token) = |
105 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | 86 | syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self]) |
106 | { | 87 | { |
107 | rename_self_to_param(&sema, position, self_token, new_name) | 88 | rename_self_to_param(&sema, position, self_token, new_name) |
108 | } else { | 89 | } else { |
109 | rename_reference(&sema, position, new_name, is_lifetime_name) | 90 | rename_reference(&sema, position, new_name) |
110 | } | 91 | } |
111 | } | 92 | } |
112 | 93 | ||
@@ -127,6 +108,33 @@ pub(crate) fn will_rename_file( | |||
127 | Some(change) | 108 | Some(change) |
128 | } | 109 | } |
129 | 110 | ||
111 | #[derive(Debug, PartialEq)] | ||
112 | enum IdentifierKind { | ||
113 | Ident, | ||
114 | Lifetime, | ||
115 | ToSelf, | ||
116 | Underscore, | ||
117 | } | ||
118 | |||
119 | fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> { | ||
120 | match lex_single_syntax_kind(new_name) { | ||
121 | Some(res) => match res { | ||
122 | (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident), | ||
123 | (T![_], _) => Ok(IdentifierKind::Underscore), | ||
124 | (T![self], _) => Ok(IdentifierKind::ToSelf), | ||
125 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { | ||
126 | Ok(IdentifierKind::Lifetime) | ||
127 | } | ||
128 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
129 | bail!("Invalid name `{0}`: Cannot rename lifetime to {0}", new_name) | ||
130 | } | ||
131 | (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), | ||
132 | (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
133 | }, | ||
134 | None => bail!("Invalid name `{}`: not an identifier", new_name), | ||
135 | } | ||
136 | } | ||
137 | |||
130 | fn find_module_at_offset( | 138 | fn find_module_at_offset( |
131 | sema: &Semantics<RootDatabase>, | 139 | sema: &Semantics<RootDatabase>, |
132 | position: FilePosition, | 140 | position: FilePosition, |
@@ -155,39 +163,54 @@ fn find_module_at_offset( | |||
155 | Some(module) | 163 | Some(module) |
156 | } | 164 | } |
157 | 165 | ||
158 | fn source_edit_from_reference( | 166 | fn find_all_refs( |
167 | sema: &Semantics<RootDatabase>, | ||
168 | position: FilePosition, | ||
169 | ) -> RenameResult<RangeInfo<ReferenceSearchResult>> { | ||
170 | crate::references::find_all_refs(sema, position, None) | ||
171 | .ok_or_else(|| format_err!("No references found at position")) | ||
172 | } | ||
173 | |||
174 | fn source_edit_from_references( | ||
159 | sema: &Semantics<RootDatabase>, | 175 | sema: &Semantics<RootDatabase>, |
160 | reference: Reference, | 176 | file_id: FileId, |
177 | references: &[FileReference], | ||
161 | new_name: &str, | 178 | new_name: &str, |
162 | ) -> SourceFileEdit { | 179 | ) -> SourceFileEdit { |
163 | let mut replacement_text = String::new(); | 180 | let mut edit = TextEdit::builder(); |
164 | let range = match reference.kind { | 181 | for reference in references { |
165 | ReferenceKind::FieldShorthandForField => { | 182 | let mut replacement_text = String::new(); |
166 | mark::hit!(test_rename_struct_field_for_shorthand); | 183 | let range = match reference.kind { |
167 | replacement_text.push_str(new_name); | 184 | ReferenceKind::FieldShorthandForField => { |
168 | replacement_text.push_str(": "); | 185 | mark::hit!(test_rename_struct_field_for_shorthand); |
169 | TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) | 186 | replacement_text.push_str(new_name); |
170 | } | 187 | replacement_text.push_str(": "); |
171 | ReferenceKind::FieldShorthandForLocal => { | 188 | TextRange::new(reference.range.start(), reference.range.start()) |
172 | mark::hit!(test_rename_local_for_field_shorthand); | 189 | } |
173 | replacement_text.push_str(": "); | 190 | ReferenceKind::FieldShorthandForLocal => { |
174 | replacement_text.push_str(new_name); | 191 | mark::hit!(test_rename_local_for_field_shorthand); |
175 | TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) | 192 | replacement_text.push_str(": "); |
176 | } | 193 | replacement_text.push_str(new_name); |
177 | ReferenceKind::RecordFieldExprOrPat => { | 194 | TextRange::new(reference.range.end(), reference.range.end()) |
178 | mark::hit!(test_rename_field_expr_pat); | 195 | } |
179 | replacement_text.push_str(new_name); | 196 | ReferenceKind::RecordFieldExprOrPat => { |
180 | edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) | 197 | mark::hit!(test_rename_field_expr_pat); |
181 | } | 198 | replacement_text.push_str(new_name); |
182 | _ => { | 199 | edit_text_range_for_record_field_expr_or_pat( |
183 | replacement_text.push_str(new_name); | 200 | sema, |
184 | reference.file_range.range | 201 | FileRange { file_id, range: reference.range }, |
185 | } | 202 | new_name, |
186 | }; | 203 | ) |
187 | SourceFileEdit { | 204 | } |
188 | file_id: reference.file_range.file_id, | 205 | _ => { |
189 | edit: TextEdit::replace(range, replacement_text), | 206 | replacement_text.push_str(new_name); |
207 | reference.range | ||
208 | } | ||
209 | }; | ||
210 | edit.replace(range, replacement_text); | ||
190 | } | 211 | } |
212 | |||
213 | SourceFileEdit { file_id, edit: edit.finish() } | ||
191 | } | 214 | } |
192 | 215 | ||
193 | fn edit_text_range_for_record_field_expr_or_pat( | 216 | fn edit_text_range_for_record_field_expr_or_pat( |
@@ -223,7 +246,10 @@ fn rename_mod( | |||
223 | position: FilePosition, | 246 | position: FilePosition, |
224 | module: Module, | 247 | module: Module, |
225 | new_name: &str, | 248 | new_name: &str, |
226 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 249 | ) -> RenameResult<RangeInfo<SourceChange>> { |
250 | if IdentifierKind::Ident != check_identifier(new_name)? { | ||
251 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); | ||
252 | } | ||
227 | let mut source_file_edits = Vec::new(); | 253 | let mut source_file_edits = Vec::new(); |
228 | let mut file_system_edits = Vec::new(); | 254 | let mut file_system_edits = Vec::new(); |
229 | 255 | ||
@@ -254,12 +280,10 @@ fn rename_mod( | |||
254 | source_file_edits.push(edit); | 280 | source_file_edits.push(edit); |
255 | } | 281 | } |
256 | 282 | ||
257 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) | 283 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
258 | .ok_or_else(|| RenameError("No references found at position".to_string()))?; | 284 | let ref_edits = refs.references().iter().map(|(&file_id, references)| { |
259 | let ref_edits = refs | 285 | source_edit_from_references(sema, file_id, references, new_name) |
260 | .references | 286 | }); |
261 | .into_iter() | ||
262 | .map(|reference| source_edit_from_reference(sema, reference, new_name)); | ||
263 | source_file_edits.extend(ref_edits); | 287 | source_file_edits.extend(ref_edits); |
264 | 288 | ||
265 | Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) | 289 | Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) |
@@ -274,27 +298,26 @@ fn rename_to_self( | |||
274 | 298 | ||
275 | let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) | 299 | let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) |
276 | .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) | 300 | .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) |
277 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; | 301 | .ok_or_else(|| format_err!("No surrounding method declaration found"))?; |
278 | let param_range = fn_ast | 302 | let param_range = fn_ast |
279 | .param_list() | 303 | .param_list() |
280 | .and_then(|p| p.params().next()) | 304 | .and_then(|p| p.params().next()) |
281 | .ok_or_else(|| RenameError("Method has no parameters".to_string()))? | 305 | .ok_or_else(|| format_err!("Method has no parameters"))? |
282 | .syntax() | 306 | .syntax() |
283 | .text_range(); | 307 | .text_range(); |
284 | if !param_range.contains(position.offset) { | 308 | if !param_range.contains(position.offset) { |
285 | return Err(RenameError("Only the first parameter can be self".to_string())); | 309 | bail!("Only the first parameter can be self"); |
286 | } | 310 | } |
287 | 311 | ||
288 | let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) | 312 | let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) |
289 | .and_then(|def| sema.to_def(&def)) | 313 | .and_then(|def| sema.to_def(&def)) |
290 | .ok_or_else(|| RenameError("No impl block found for function".to_string()))?; | 314 | .ok_or_else(|| format_err!("No impl block found for function"))?; |
291 | if fn_def.self_param(sema.db).is_some() { | 315 | if fn_def.self_param(sema.db).is_some() { |
292 | return Err(RenameError("Method already has a self parameter".to_string())); | 316 | bail!("Method already has a self parameter"); |
293 | } | 317 | } |
294 | 318 | ||
295 | let params = fn_def.assoc_fn_params(sema.db); | 319 | let params = fn_def.assoc_fn_params(sema.db); |
296 | let first_param = | 320 | let first_param = params.first().ok_or_else(|| format_err!("Method has no parameters"))?; |
297 | params.first().ok_or_else(|| RenameError("Method has no parameters".into()))?; | ||
298 | let first_param_ty = first_param.ty(); | 321 | let first_param_ty = first_param.ty(); |
299 | let impl_ty = impl_block.target_ty(sema.db); | 322 | let impl_ty = impl_block.target_ty(sema.db); |
300 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { | 323 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { |
@@ -307,23 +330,17 @@ fn rename_to_self( | |||
307 | }; | 330 | }; |
308 | 331 | ||
309 | if ty != impl_ty { | 332 | if ty != impl_ty { |
310 | return Err(RenameError("Parameter type differs from impl block type".to_string())); | 333 | bail!("Parameter type differs from impl block type"); |
311 | } | 334 | } |
312 | 335 | ||
313 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) | 336 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
314 | .ok_or_else(|| RenameError("No reference found at position".to_string()))?; | ||
315 | |||
316 | let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs | ||
317 | .into_iter() | ||
318 | .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); | ||
319 | |||
320 | if param_ref.is_empty() { | ||
321 | return Err(RenameError("Parameter to rename not found".to_string())); | ||
322 | } | ||
323 | 337 | ||
324 | let mut edits = usages | 338 | let mut edits = refs |
325 | .into_iter() | 339 | .references() |
326 | .map(|reference| source_edit_from_reference(sema, reference, "self")) | 340 | .iter() |
341 | .map(|(&file_id, references)| { | ||
342 | source_edit_from_references(sema, file_id, references, "self") | ||
343 | }) | ||
327 | .collect::<Vec<_>>(); | 344 | .collect::<Vec<_>>(); |
328 | 345 | ||
329 | edits.push(SourceFileEdit { | 346 | edits.push(SourceFileEdit { |
@@ -367,12 +384,22 @@ fn rename_self_to_param( | |||
367 | self_token: SyntaxToken, | 384 | self_token: SyntaxToken, |
368 | new_name: &str, | 385 | new_name: &str, |
369 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 386 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
387 | let ident_kind = check_identifier(new_name)?; | ||
388 | match ident_kind { | ||
389 | IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name), | ||
390 | IdentifierKind::ToSelf => { | ||
391 | // no-op | ||
392 | mark::hit!(rename_self_to_self); | ||
393 | return Ok(RangeInfo::new(self_token.text_range(), SourceChange::default())); | ||
394 | } | ||
395 | _ => (), | ||
396 | } | ||
370 | let source_file = sema.parse(position.file_id); | 397 | let source_file = sema.parse(position.file_id); |
371 | let syn = source_file.syntax(); | 398 | let syn = source_file.syntax(); |
372 | 399 | ||
373 | let text = sema.db.file_text(position.file_id); | 400 | let text = sema.db.file_text(position.file_id); |
374 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) | 401 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) |
375 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; | 402 | .ok_or_else(|| format_err!("No surrounding method declaration found"))?; |
376 | let search_range = fn_def.syntax().text_range(); | 403 | let search_range = fn_def.syntax().text_range(); |
377 | 404 | ||
378 | let mut edits: Vec<SourceFileEdit> = vec![]; | 405 | let mut edits: Vec<SourceFileEdit> = vec![]; |
@@ -382,12 +409,10 @@ fn rename_self_to_param( | |||
382 | if !search_range.contains_inclusive(offset) { | 409 | if !search_range.contains_inclusive(offset) { |
383 | continue; | 410 | continue; |
384 | } | 411 | } |
385 | if let Some(ref usage) = | 412 | if let Some(ref usage) = syn.token_at_offset(offset).find(|t| t.kind() == T![self]) { |
386 | syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | ||
387 | { | ||
388 | let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { | 413 | let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { |
389 | text_edit_from_self_param(syn, self_param, new_name) | 414 | text_edit_from_self_param(syn, self_param, new_name) |
390 | .ok_or_else(|| RenameError("No target type found".to_string()))? | 415 | .ok_or_else(|| format_err!("No target type found"))? |
391 | } else { | 416 | } else { |
392 | TextEdit::replace(usage.text_range(), String::from(new_name)) | 417 | TextEdit::replace(usage.text_range(), String::from(new_name)) |
393 | }; | 418 | }; |
@@ -395,6 +420,10 @@ fn rename_self_to_param( | |||
395 | } | 420 | } |
396 | } | 421 | } |
397 | 422 | ||
423 | if edits.len() > 1 && ident_kind == IdentifierKind::Underscore { | ||
424 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | ||
425 | } | ||
426 | |||
398 | let range = ast::SelfParam::cast(self_token.parent()) | 427 | let range = ast::SelfParam::cast(self_token.parent()) |
399 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); | 428 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); |
400 | 429 | ||
@@ -405,35 +434,43 @@ fn rename_reference( | |||
405 | sema: &Semantics<RootDatabase>, | 434 | sema: &Semantics<RootDatabase>, |
406 | position: FilePosition, | 435 | position: FilePosition, |
407 | new_name: &str, | 436 | new_name: &str, |
408 | is_lifetime_name: bool, | ||
409 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 437 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
410 | let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) { | 438 | let ident_kind = check_identifier(new_name)?; |
411 | Some(range_info) => range_info, | 439 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
412 | None => return Err(RenameError("No references found at position".to_string())), | 440 | |
413 | }; | 441 | match (ident_kind, &refs.declaration.kind) { |
414 | 442 | (IdentifierKind::ToSelf, ReferenceKind::Lifetime) | |
415 | match (refs.declaration.kind == ReferenceKind::Lifetime, is_lifetime_name) { | 443 | | (IdentifierKind::Underscore, ReferenceKind::Lifetime) |
416 | (true, false) => { | 444 | | (IdentifierKind::Ident, ReferenceKind::Lifetime) => { |
417 | return Err(RenameError(format!( | 445 | mark::hit!(rename_not_a_lifetime_ident_ref); |
418 | "Invalid name `{}`: not a lifetime identifier", | 446 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) |
419 | new_name | ||
420 | ))) | ||
421 | } | 447 | } |
422 | (false, true) => { | 448 | (IdentifierKind::Lifetime, ReferenceKind::Lifetime) => mark::hit!(rename_lifetime), |
423 | return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) | 449 | (IdentifierKind::Lifetime, _) => { |
450 | mark::hit!(rename_not_an_ident_ref); | ||
451 | bail!("Invalid name `{}`: not an identifier", new_name) | ||
424 | } | 452 | } |
425 | _ => (), | 453 | (IdentifierKind::ToSelf, ReferenceKind::SelfKw) => { |
454 | unreachable!("rename_self_to_param should've been called instead") | ||
455 | } | ||
456 | (IdentifierKind::ToSelf, _) => { | ||
457 | mark::hit!(rename_to_self); | ||
458 | return rename_to_self(sema, position); | ||
459 | } | ||
460 | (IdentifierKind::Underscore, _) if !refs.references.is_empty() => { | ||
461 | mark::hit!(rename_underscore_multiple); | ||
462 | bail!("Cannot rename reference to `_` as it is being referenced multiple times") | ||
463 | } | ||
464 | (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident), | ||
426 | } | 465 | } |
427 | 466 | ||
428 | let edit = refs | 467 | let edit = refs |
429 | .into_iter() | 468 | .into_iter() |
430 | .map(|reference| source_edit_from_reference(sema, reference, new_name)) | 469 | .map(|(file_id, references)| { |
470 | source_edit_from_references(sema, file_id, &references, new_name) | ||
471 | }) | ||
431 | .collect::<Vec<_>>(); | 472 | .collect::<Vec<_>>(); |
432 | 473 | ||
433 | if edit.is_empty() { | ||
434 | return Err(RenameError("No references found at position".to_string())); | ||
435 | } | ||
436 | |||
437 | Ok(RangeInfo::new(range, SourceChange::from(edit))) | 474 | Ok(RangeInfo::new(range, SourceChange::from(edit))) |
438 | } | 475 | } |
439 | 476 | ||
@@ -462,9 +499,11 @@ mod tests { | |||
462 | text_edit_builder.replace(indel.delete, indel.insert); | 499 | text_edit_builder.replace(indel.delete, indel.insert); |
463 | } | 500 | } |
464 | } | 501 | } |
465 | let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string(); | 502 | if let Some(file_id) = file_id { |
466 | text_edit_builder.finish().apply(&mut result); | 503 | let mut result = analysis.file_text(file_id).unwrap().to_string(); |
467 | assert_eq_text!(ra_fixture_after, &*result); | 504 | text_edit_builder.finish().apply(&mut result); |
505 | assert_eq_text!(ra_fixture_after, &*result); | ||
506 | } | ||
468 | } | 507 | } |
469 | Err(err) => { | 508 | Err(err) => { |
470 | if ra_fixture_after.starts_with("error:") { | 509 | if ra_fixture_after.starts_with("error:") { |
@@ -493,19 +532,19 @@ mod tests { | |||
493 | 532 | ||
494 | #[test] | 533 | #[test] |
495 | fn test_rename_to_underscore() { | 534 | fn test_rename_to_underscore() { |
496 | check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#); | 535 | check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); |
497 | } | 536 | } |
498 | 537 | ||
499 | #[test] | 538 | #[test] |
500 | fn test_rename_to_raw_identifier() { | 539 | fn test_rename_to_raw_identifier() { |
501 | check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#); | 540 | check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#); |
502 | } | 541 | } |
503 | 542 | ||
504 | #[test] | 543 | #[test] |
505 | fn test_rename_to_invalid_identifier1() { | 544 | fn test_rename_to_invalid_identifier1() { |
506 | check( | 545 | check( |
507 | "invalid!", | 546 | "invalid!", |
508 | r#"fn main() { let i<|> = 1; }"#, | 547 | r#"fn main() { let i$0 = 1; }"#, |
509 | "error: Invalid name `invalid!`: not an identifier", | 548 | "error: Invalid name `invalid!`: not an identifier", |
510 | ); | 549 | ); |
511 | } | 550 | } |
@@ -514,7 +553,7 @@ mod tests { | |||
514 | fn test_rename_to_invalid_identifier2() { | 553 | fn test_rename_to_invalid_identifier2() { |
515 | check( | 554 | check( |
516 | "multiple tokens", | 555 | "multiple tokens", |
517 | r#"fn main() { let i<|> = 1; }"#, | 556 | r#"fn main() { let i$0 = 1; }"#, |
518 | "error: Invalid name `multiple tokens`: not an identifier", | 557 | "error: Invalid name `multiple tokens`: not an identifier", |
519 | ); | 558 | ); |
520 | } | 559 | } |
@@ -523,38 +562,60 @@ mod tests { | |||
523 | fn test_rename_to_invalid_identifier3() { | 562 | fn test_rename_to_invalid_identifier3() { |
524 | check( | 563 | check( |
525 | "let", | 564 | "let", |
526 | r#"fn main() { let i<|> = 1; }"#, | 565 | r#"fn main() { let i$0 = 1; }"#, |
527 | "error: Invalid name `let`: not an identifier", | 566 | "error: Invalid name `let`: not an identifier", |
528 | ); | 567 | ); |
529 | } | 568 | } |
530 | 569 | ||
531 | #[test] | 570 | #[test] |
532 | fn test_rename_to_invalid_identifier_lifetime() { | 571 | fn test_rename_to_invalid_identifier_lifetime() { |
572 | mark::check!(rename_not_an_ident_ref); | ||
533 | check( | 573 | check( |
534 | "'foo", | 574 | "'foo", |
535 | r#"fn main() { let i<|> = 1; }"#, | 575 | r#"fn main() { let i$0 = 1; }"#, |
536 | "error: Invalid name `'foo`: not an identifier", | 576 | "error: Invalid name `'foo`: not an identifier", |
537 | ); | 577 | ); |
538 | } | 578 | } |
539 | 579 | ||
540 | #[test] | 580 | #[test] |
541 | fn test_rename_to_invalid_identifier_lifetime2() { | 581 | fn test_rename_to_invalid_identifier_lifetime2() { |
582 | mark::check!(rename_not_a_lifetime_ident_ref); | ||
542 | check( | 583 | check( |
543 | "foo", | 584 | "foo", |
544 | r#"fn main<'a>(_: &'a<|> ()) {}"#, | 585 | r#"fn main<'a>(_: &'a$0 ()) {}"#, |
545 | "error: Invalid name `foo`: not a lifetime identifier", | 586 | "error: Invalid name `foo`: not a lifetime identifier", |
546 | ); | 587 | ); |
547 | } | 588 | } |
548 | 589 | ||
549 | #[test] | 590 | #[test] |
591 | fn test_rename_to_underscore_invalid() { | ||
592 | mark::check!(rename_underscore_multiple); | ||
593 | check( | ||
594 | "_", | ||
595 | r#"fn main(foo$0: ()) {foo;}"#, | ||
596 | "error: Cannot rename reference to `_` as it is being referenced multiple times", | ||
597 | ); | ||
598 | } | ||
599 | |||
600 | #[test] | ||
601 | fn test_rename_mod_invalid() { | ||
602 | check( | ||
603 | "'foo", | ||
604 | r#"mod foo$0 {}"#, | ||
605 | "error: Invalid name `'foo`: cannot rename module to 'foo", | ||
606 | ); | ||
607 | } | ||
608 | |||
609 | #[test] | ||
550 | fn test_rename_for_local() { | 610 | fn test_rename_for_local() { |
611 | mark::check!(rename_ident); | ||
551 | check( | 612 | check( |
552 | "k", | 613 | "k", |
553 | r#" | 614 | r#" |
554 | fn main() { | 615 | fn main() { |
555 | let mut i = 1; | 616 | let mut i = 1; |
556 | let j = 1; | 617 | let j = 1; |
557 | i = i<|> + j; | 618 | i = i$0 + j; |
558 | 619 | ||
559 | { i = 0; } | 620 | { i = 0; } |
560 | 621 | ||
@@ -579,7 +640,7 @@ fn main() { | |||
579 | fn test_rename_unresolved_reference() { | 640 | fn test_rename_unresolved_reference() { |
580 | check( | 641 | check( |
581 | "new_name", | 642 | "new_name", |
582 | r#"fn main() { let _ = unresolved_ref<|>; }"#, | 643 | r#"fn main() { let _ = unresolved_ref$0; }"#, |
583 | "error: No references found at position", | 644 | "error: No references found at position", |
584 | ); | 645 | ); |
585 | } | 646 | } |
@@ -591,7 +652,7 @@ fn main() { | |||
591 | r#" | 652 | r#" |
592 | macro_rules! foo {($i:ident) => {$i} } | 653 | macro_rules! foo {($i:ident) => {$i} } |
593 | fn main() { | 654 | fn main() { |
594 | let a<|> = "test"; | 655 | let a$0 = "test"; |
595 | foo!(a); | 656 | foo!(a); |
596 | } | 657 | } |
597 | "#, | 658 | "#, |
@@ -613,7 +674,7 @@ fn main() { | |||
613 | macro_rules! foo {($i:ident) => {$i} } | 674 | macro_rules! foo {($i:ident) => {$i} } |
614 | fn main() { | 675 | fn main() { |
615 | let a = "test"; | 676 | let a = "test"; |
616 | foo!(a<|>); | 677 | foo!(a$0); |
617 | } | 678 | } |
618 | "#, | 679 | "#, |
619 | r#" | 680 | r#" |
@@ -634,7 +695,7 @@ fn main() { | |||
634 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | 695 | macro_rules! define_fn {($id:ident) => { fn $id{} }} |
635 | define_fn!(foo); | 696 | define_fn!(foo); |
636 | fn main() { | 697 | fn main() { |
637 | fo<|>o(); | 698 | fo$0o(); |
638 | } | 699 | } |
639 | "#, | 700 | "#, |
640 | r#" | 701 | r#" |
@@ -653,7 +714,7 @@ fn main() { | |||
653 | "bar", | 714 | "bar", |
654 | r#" | 715 | r#" |
655 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | 716 | macro_rules! define_fn {($id:ident) => { fn $id{} }} |
656 | define_fn!(fo<|>o); | 717 | define_fn!(fo$0o); |
657 | fn main() { | 718 | fn main() { |
658 | foo(); | 719 | foo(); |
659 | } | 720 | } |
@@ -670,17 +731,17 @@ fn main() { | |||
670 | 731 | ||
671 | #[test] | 732 | #[test] |
672 | fn test_rename_for_param_inside() { | 733 | fn test_rename_for_param_inside() { |
673 | check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#); | 734 | check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#); |
674 | } | 735 | } |
675 | 736 | ||
676 | #[test] | 737 | #[test] |
677 | fn test_rename_refs_for_fn_param() { | 738 | fn test_rename_refs_for_fn_param() { |
678 | check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); | 739 | check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); |
679 | } | 740 | } |
680 | 741 | ||
681 | #[test] | 742 | #[test] |
682 | fn test_rename_for_mut_param() { | 743 | fn test_rename_for_mut_param() { |
683 | check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); | 744 | check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); |
684 | } | 745 | } |
685 | 746 | ||
686 | #[test] | 747 | #[test] |
@@ -688,7 +749,7 @@ fn main() { | |||
688 | check( | 749 | check( |
689 | "j", | 750 | "j", |
690 | r#" | 751 | r#" |
691 | struct Foo { i<|>: i32 } | 752 | struct Foo { i$0: i32 } |
692 | 753 | ||
693 | impl Foo { | 754 | impl Foo { |
694 | fn new(i: i32) -> Self { | 755 | fn new(i: i32) -> Self { |
@@ -714,7 +775,7 @@ impl Foo { | |||
714 | check( | 775 | check( |
715 | "j", | 776 | "j", |
716 | r#" | 777 | r#" |
717 | struct Foo { i<|>: i32 } | 778 | struct Foo { i$0: i32 } |
718 | 779 | ||
719 | impl Foo { | 780 | impl Foo { |
720 | fn new(i: i32) -> Self { | 781 | fn new(i: i32) -> Self { |
@@ -743,7 +804,7 @@ impl Foo { | |||
743 | struct Foo { i: i32 } | 804 | struct Foo { i: i32 } |
744 | 805 | ||
745 | impl Foo { | 806 | impl Foo { |
746 | fn new(i<|>: i32) -> Self { | 807 | fn new(i$0: i32) -> Self { |
747 | Self { i } | 808 | Self { i } |
748 | } | 809 | } |
749 | } | 810 | } |
@@ -765,7 +826,7 @@ impl Foo { | |||
765 | check( | 826 | check( |
766 | "j", | 827 | "j", |
767 | r#" | 828 | r#" |
768 | struct Foo { i<|>: i32 } | 829 | struct Foo { i$0: i32 } |
769 | struct Bar { i: i32 } | 830 | struct Bar { i: i32 } |
770 | 831 | ||
771 | impl Bar { | 832 | impl Bar { |
@@ -794,7 +855,7 @@ impl Bar { | |||
794 | r#" | 855 | r#" |
795 | struct Foo { i: i32 } | 856 | struct Foo { i: i32 } |
796 | 857 | ||
797 | fn baz(i<|>: i32) -> Self { | 858 | fn baz(i$0: i32) -> Self { |
798 | let x = Foo { i }; | 859 | let x = Foo { i }; |
799 | { | 860 | { |
800 | let i = 0; | 861 | let i = 0; |
@@ -825,7 +886,7 @@ fn baz(j: i32) -> Self { | |||
825 | mod bar; | 886 | mod bar; |
826 | 887 | ||
827 | //- /bar.rs | 888 | //- /bar.rs |
828 | mod foo<|>; | 889 | mod foo$0; |
829 | 890 | ||
830 | //- /bar/foo.rs | 891 | //- /bar/foo.rs |
831 | // empty | 892 | // empty |
@@ -883,7 +944,7 @@ fn main() {} | |||
883 | pub struct FooContent; | 944 | pub struct FooContent; |
884 | 945 | ||
885 | //- /bar.rs | 946 | //- /bar.rs |
886 | use crate::foo<|>::FooContent; | 947 | use crate::foo$0::FooContent; |
887 | "#, | 948 | "#, |
888 | expect![[r#" | 949 | expect![[r#" |
889 | RangeInfo { | 950 | RangeInfo { |
@@ -943,9 +1004,9 @@ use crate::foo<|>::FooContent; | |||
943 | "foo2", | 1004 | "foo2", |
944 | r#" | 1005 | r#" |
945 | //- /lib.rs | 1006 | //- /lib.rs |
946 | mod fo<|>o; | 1007 | mod fo$0o; |
947 | //- /foo/mod.rs | 1008 | //- /foo/mod.rs |
948 | // emtpy | 1009 | // empty |
949 | "#, | 1010 | "#, |
950 | expect![[r#" | 1011 | expect![[r#" |
951 | RangeInfo { | 1012 | RangeInfo { |
@@ -992,10 +1053,10 @@ mod fo<|>o; | |||
992 | "bar", | 1053 | "bar", |
993 | r#" | 1054 | r#" |
994 | //- /lib.rs | 1055 | //- /lib.rs |
995 | mod outer { mod fo<|>o; } | 1056 | mod outer { mod fo$0o; } |
996 | 1057 | ||
997 | //- /outer/foo.rs | 1058 | //- /outer/foo.rs |
998 | // emtpy | 1059 | // empty |
999 | "#, | 1060 | "#, |
1000 | expect![[r#" | 1061 | expect![[r#" |
1001 | RangeInfo { | 1062 | RangeInfo { |
@@ -1041,7 +1102,7 @@ mod outer { mod fo<|>o; } | |||
1041 | check( | 1102 | check( |
1042 | "baz", | 1103 | "baz", |
1043 | r#" | 1104 | r#" |
1044 | mod <|>foo { pub fn bar() {} } | 1105 | mod $0foo { pub fn bar() {} } |
1045 | 1106 | ||
1046 | fn main() { foo::bar(); } | 1107 | fn main() { foo::bar(); } |
1047 | "#, | 1108 | "#, |
@@ -1065,7 +1126,7 @@ fn f() { | |||
1065 | } | 1126 | } |
1066 | 1127 | ||
1067 | //- /bar.rs | 1128 | //- /bar.rs |
1068 | pub mod foo<|>; | 1129 | pub mod foo$0; |
1069 | 1130 | ||
1070 | //- /bar/foo.rs | 1131 | //- /bar/foo.rs |
1071 | // pub fn fun() {} | 1132 | // pub fn fun() {} |
@@ -1128,7 +1189,7 @@ pub mod foo<|>; | |||
1128 | "Baz", | 1189 | "Baz", |
1129 | r#" | 1190 | r#" |
1130 | mod foo { | 1191 | mod foo { |
1131 | pub enum Foo { Bar<|> } | 1192 | pub enum Foo { Bar$0 } |
1132 | } | 1193 | } |
1133 | 1194 | ||
1134 | fn func(f: foo::Foo) { | 1195 | fn func(f: foo::Foo) { |
@@ -1157,7 +1218,7 @@ fn func(f: foo::Foo) { | |||
1157 | "baz", | 1218 | "baz", |
1158 | r#" | 1219 | r#" |
1159 | mod foo { | 1220 | mod foo { |
1160 | pub struct Foo { pub bar<|>: uint } | 1221 | pub struct Foo { pub bar$0: uint } |
1161 | } | 1222 | } |
1162 | 1223 | ||
1163 | fn foo(f: foo::Foo) { | 1224 | fn foo(f: foo::Foo) { |
@@ -1178,13 +1239,14 @@ fn foo(f: foo::Foo) { | |||
1178 | 1239 | ||
1179 | #[test] | 1240 | #[test] |
1180 | fn test_parameter_to_self() { | 1241 | fn test_parameter_to_self() { |
1242 | mark::check!(rename_to_self); | ||
1181 | check( | 1243 | check( |
1182 | "self", | 1244 | "self", |
1183 | r#" | 1245 | r#" |
1184 | struct Foo { i: i32 } | 1246 | struct Foo { i: i32 } |
1185 | 1247 | ||
1186 | impl Foo { | 1248 | impl Foo { |
1187 | fn f(foo<|>: &mut Foo) -> i32 { | 1249 | fn f(foo$0: &mut Foo) -> i32 { |
1188 | foo.i | 1250 | foo.i |
1189 | } | 1251 | } |
1190 | } | 1252 | } |
@@ -1205,7 +1267,7 @@ impl Foo { | |||
1205 | struct Foo { i: i32 } | 1267 | struct Foo { i: i32 } |
1206 | 1268 | ||
1207 | impl Foo { | 1269 | impl Foo { |
1208 | fn f(foo<|>: Foo) -> i32 { | 1270 | fn f(foo$0: Foo) -> i32 { |
1209 | foo.i | 1271 | foo.i |
1210 | } | 1272 | } |
1211 | } | 1273 | } |
@@ -1229,7 +1291,7 @@ impl Foo { | |||
1229 | r#" | 1291 | r#" |
1230 | struct Foo { i: i32 } | 1292 | struct Foo { i: i32 } |
1231 | 1293 | ||
1232 | fn f(foo<|>: &mut Foo) -> i32 { | 1294 | fn f(foo$0: &mut Foo) -> i32 { |
1233 | foo.i | 1295 | foo.i |
1234 | } | 1296 | } |
1235 | "#, | 1297 | "#, |
@@ -1242,7 +1304,7 @@ struct Foo { i: i32 } | |||
1242 | struct Bar; | 1304 | struct Bar; |
1243 | 1305 | ||
1244 | impl Bar { | 1306 | impl Bar { |
1245 | fn f(foo<|>: &mut Foo) -> i32 { | 1307 | fn f(foo$0: &mut Foo) -> i32 { |
1246 | foo.i | 1308 | foo.i |
1247 | } | 1309 | } |
1248 | } | 1310 | } |
@@ -1258,7 +1320,7 @@ impl Bar { | |||
1258 | r#" | 1320 | r#" |
1259 | struct Foo { i: i32 } | 1321 | struct Foo { i: i32 } |
1260 | impl Foo { | 1322 | impl Foo { |
1261 | fn f(x: (), foo<|>: &mut Foo) -> i32 { | 1323 | fn f(x: (), foo$0: &mut Foo) -> i32 { |
1262 | foo.i | 1324 | foo.i |
1263 | } | 1325 | } |
1264 | } | 1326 | } |
@@ -1274,7 +1336,7 @@ impl Foo { | |||
1274 | r#" | 1336 | r#" |
1275 | struct Foo { i: i32 } | 1337 | struct Foo { i: i32 } |
1276 | impl &Foo { | 1338 | impl &Foo { |
1277 | fn f(foo<|>: &Foo) -> i32 { | 1339 | fn f(foo$0: &Foo) -> i32 { |
1278 | foo.i | 1340 | foo.i |
1279 | } | 1341 | } |
1280 | } | 1342 | } |
@@ -1298,7 +1360,7 @@ impl &Foo { | |||
1298 | struct Foo { i: i32 } | 1360 | struct Foo { i: i32 } |
1299 | 1361 | ||
1300 | impl Foo { | 1362 | impl Foo { |
1301 | fn f(&mut <|>self) -> i32 { | 1363 | fn f(&mut $0self) -> i32 { |
1302 | self.i | 1364 | self.i |
1303 | } | 1365 | } |
1304 | } | 1366 | } |
@@ -1323,7 +1385,7 @@ impl Foo { | |||
1323 | struct Foo { i: i32 } | 1385 | struct Foo { i: i32 } |
1324 | 1386 | ||
1325 | impl Foo { | 1387 | impl Foo { |
1326 | fn f(<|>self) -> i32 { | 1388 | fn f($0self) -> i32 { |
1327 | self.i | 1389 | self.i |
1328 | } | 1390 | } |
1329 | } | 1391 | } |
@@ -1350,7 +1412,7 @@ struct Foo { i: i32 } | |||
1350 | impl Foo { | 1412 | impl Foo { |
1351 | fn f(&self) -> i32 { | 1413 | fn f(&self) -> i32 { |
1352 | let self_var = 1; | 1414 | let self_var = 1; |
1353 | self<|>.i | 1415 | self$0.i |
1354 | } | 1416 | } |
1355 | } | 1417 | } |
1356 | "#, | 1418 | "#, |
@@ -1373,7 +1435,7 @@ impl Foo { | |||
1373 | check( | 1435 | check( |
1374 | "bar", | 1436 | "bar", |
1375 | r#" | 1437 | r#" |
1376 | struct Foo { i<|>: i32 } | 1438 | struct Foo { i$0: i32 } |
1377 | 1439 | ||
1378 | fn foo(bar: i32) -> Foo { | 1440 | fn foo(bar: i32) -> Foo { |
1379 | Foo { i: bar } | 1441 | Foo { i: bar } |
@@ -1394,7 +1456,7 @@ fn foo(bar: i32) -> Foo { | |||
1394 | check( | 1456 | check( |
1395 | "baz", | 1457 | "baz", |
1396 | r#" | 1458 | r#" |
1397 | struct Foo { i<|>: i32 } | 1459 | struct Foo { i$0: i32 } |
1398 | 1460 | ||
1399 | fn foo(foo: Foo) { | 1461 | fn foo(foo: Foo) { |
1400 | let Foo { i: baz } = foo; | 1462 | let Foo { i: baz } = foo; |
@@ -1433,7 +1495,7 @@ struct Foo { | |||
1433 | 1495 | ||
1434 | fn foo(foo: Foo) { | 1496 | fn foo(foo: Foo) { |
1435 | let Foo { i: b } = foo; | 1497 | let Foo { i: b } = foo; |
1436 | let _ = b<|>; | 1498 | let _ = b$0; |
1437 | } | 1499 | } |
1438 | "#, | 1500 | "#, |
1439 | expected_fixture, | 1501 | expected_fixture, |
@@ -1447,7 +1509,7 @@ struct Foo { | |||
1447 | 1509 | ||
1448 | fn foo(foo: Foo) { | 1510 | fn foo(foo: Foo) { |
1449 | let Foo { i } = foo; | 1511 | let Foo { i } = foo; |
1450 | let _ = i<|>; | 1512 | let _ = i$0; |
1451 | } | 1513 | } |
1452 | "#, | 1514 | "#, |
1453 | expected_fixture, | 1515 | expected_fixture, |
@@ -1464,7 +1526,7 @@ struct Foo { | |||
1464 | } | 1526 | } |
1465 | 1527 | ||
1466 | fn foo(Foo { i }: foo) -> i32 { | 1528 | fn foo(Foo { i }: foo) -> i32 { |
1467 | i<|> | 1529 | i$0 |
1468 | } | 1530 | } |
1469 | "#, | 1531 | "#, |
1470 | r#" | 1532 | r#" |
@@ -1481,6 +1543,7 @@ fn foo(Foo { i: bar }: foo) -> i32 { | |||
1481 | 1543 | ||
1482 | #[test] | 1544 | #[test] |
1483 | fn test_rename_lifetimes() { | 1545 | fn test_rename_lifetimes() { |
1546 | mark::check!(rename_lifetime); | ||
1484 | check( | 1547 | check( |
1485 | "'yeeee", | 1548 | "'yeeee", |
1486 | r#" | 1549 | r#" |
@@ -1488,7 +1551,7 @@ trait Foo<'a> { | |||
1488 | fn foo() -> &'a (); | 1551 | fn foo() -> &'a (); |
1489 | } | 1552 | } |
1490 | impl<'a> Foo<'a> for &'a () { | 1553 | impl<'a> Foo<'a> for &'a () { |
1491 | fn foo() -> &'a<|> () { | 1554 | fn foo() -> &'a$0 () { |
1492 | unimplemented!() | 1555 | unimplemented!() |
1493 | } | 1556 | } |
1494 | } | 1557 | } |
@@ -1520,7 +1583,7 @@ fn main() { | |||
1520 | let test_variable = CustomOption::Some(22); | 1583 | let test_variable = CustomOption::Some(22); |
1521 | 1584 | ||
1522 | match test_variable { | 1585 | match test_variable { |
1523 | CustomOption::Some(foo<|>) if foo == 11 => {} | 1586 | CustomOption::Some(foo$0) if foo == 11 => {} |
1524 | _ => (), | 1587 | _ => (), |
1525 | } | 1588 | } |
1526 | }"#, | 1589 | }"#, |
@@ -1549,7 +1612,7 @@ fn main() { | |||
1549 | fn foo<'a>() -> &'a () { | 1612 | fn foo<'a>() -> &'a () { |
1550 | 'a: { | 1613 | 'a: { |
1551 | 'b: loop { | 1614 | 'b: loop { |
1552 | break 'a<|>; | 1615 | break 'a$0; |
1553 | } | 1616 | } |
1554 | } | 1617 | } |
1555 | } | 1618 | } |
@@ -1565,4 +1628,24 @@ fn foo<'a>() -> &'a () { | |||
1565 | "#, | 1628 | "#, |
1566 | ) | 1629 | ) |
1567 | } | 1630 | } |
1631 | |||
1632 | #[test] | ||
1633 | fn test_self_to_self() { | ||
1634 | mark::check!(rename_self_to_self); | ||
1635 | check( | ||
1636 | "self", | ||
1637 | r#" | ||
1638 | struct Foo; | ||
1639 | impl Foo { | ||
1640 | fn foo(self$0) {} | ||
1641 | } | ||
1642 | "#, | ||
1643 | r#" | ||
1644 | struct Foo; | ||
1645 | impl Foo { | ||
1646 | fn foo(self) {} | ||
1647 | } | ||
1648 | "#, | ||
1649 | ) | ||
1650 | } | ||
1568 | } | 1651 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 891183266..f5ee7de86 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -2,11 +2,11 @@ use std::fmt; | |||
2 | 2 | ||
3 | use assists::utils::test_related_attribute; | 3 | use assists::utils::test_related_attribute; |
4 | use cfg::CfgExpr; | 4 | use cfg::CfgExpr; |
5 | use hir::{AsAssocItem, HasAttrs, InFile, Semantics}; | 5 | use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; |
6 | use ide_db::RootDatabase; | 6 | use ide_db::{defs::Definition, RootDatabase}; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, | 9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, |
10 | match_ast, SyntaxNode, | 10 | match_ast, SyntaxNode, |
11 | }; | 11 | }; |
12 | 12 | ||
@@ -96,41 +96,45 @@ impl Runnable { | |||
96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
97 | let sema = Semantics::new(db); | 97 | let sema = Semantics::new(db); |
98 | let source_file = sema.parse(file_id); | 98 | let source_file = sema.parse(file_id); |
99 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() | 99 | source_file |
100 | } | 100 | .syntax() |
101 | 101 | .descendants() | |
102 | pub(crate) fn runnable( | 102 | .filter_map(|item| { |
103 | sema: &Semantics<RootDatabase>, | 103 | let runnable = match_ast! { |
104 | item: SyntaxNode, | 104 | match item { |
105 | file_id: FileId, | 105 | ast::Fn(func) => { |
106 | ) -> Option<Runnable> { | 106 | let def = sema.to_def(&func)?; |
107 | let runnable_item = match_ast! { | 107 | runnable_fn(&sema, def) |
108 | match (item.clone()) { | 108 | }, |
109 | ast::Fn(it) => runnable_fn(sema, it, file_id), | 109 | ast::Module(it) => runnable_mod(&sema, it), |
110 | ast::Module(it) => runnable_mod(sema, it), | 110 | _ => None, |
111 | _ => None, | 111 | } |
112 | } | 112 | }; |
113 | }; | 113 | runnable.or_else(|| match doc_owner_to_def(&sema, item)? { |
114 | runnable_item.or_else(|| runnable_doctest(sema, item)) | 114 | Definition::ModuleDef(def) => module_def_doctest(&sema, def), |
115 | _ => None, | ||
116 | }) | ||
117 | }) | ||
118 | .collect() | ||
115 | } | 119 | } |
116 | 120 | ||
117 | fn runnable_fn(sema: &Semantics<RootDatabase>, func: ast::Fn, file_id: FileId) -> Option<Runnable> { | 121 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { |
118 | let def = sema.to_def(&func)?; | 122 | let func = def.source(sema.db)?; |
119 | let name_string = func.name()?.text().to_string(); | 123 | let name_string = def.name(sema.db).to_string(); |
120 | 124 | ||
121 | let kind = if name_string == "main" { | 125 | let kind = if name_string == "main" { |
122 | RunnableKind::Bin | 126 | RunnableKind::Bin |
123 | } else { | 127 | } else { |
124 | let canonical_path = sema.to_def(&func).and_then(|def| { | 128 | let canonical_path = { |
125 | let def: hir::ModuleDef = def.into(); | 129 | let def: hir::ModuleDef = def.into(); |
126 | def.canonical_path(sema.db) | 130 | def.canonical_path(sema.db) |
127 | }); | 131 | }; |
128 | let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string)); | 132 | let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string)); |
129 | 133 | ||
130 | if test_related_attribute(&func).is_some() { | 134 | if test_related_attribute(&func.value).is_some() { |
131 | let attr = TestAttr::from_fn(&func); | 135 | let attr = TestAttr::from_fn(&func.value); |
132 | RunnableKind::Test { test_id, attr } | 136 | RunnableKind::Test { test_id, attr } |
133 | } else if func.has_atom_attr("bench") { | 137 | } else if func.value.has_atom_attr("bench") { |
134 | RunnableKind::Bench { test_id } | 138 | RunnableKind::Bench { test_id } |
135 | } else { | 139 | } else { |
136 | return None; | 140 | return None; |
@@ -139,27 +143,56 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, func: ast::Fn, file_id: FileId) - | |||
139 | 143 | ||
140 | let nav = NavigationTarget::from_named( | 144 | let nav = NavigationTarget::from_named( |
141 | sema.db, | 145 | sema.db, |
142 | InFile::new(file_id.into(), &func), | 146 | func.as_ref().map(|it| it as &dyn ast::NameOwner), |
143 | SymbolKind::Function, | 147 | SymbolKind::Function, |
144 | ); | 148 | ); |
145 | let cfg = def.attrs(sema.db).cfg(); | 149 | let cfg = def.attrs(sema.db).cfg(); |
146 | Some(Runnable { nav, kind, cfg }) | 150 | Some(Runnable { nav, kind, cfg }) |
147 | } | 151 | } |
148 | 152 | ||
149 | fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { | 153 | pub(crate) fn runnable_mod( |
150 | match_ast! { | 154 | sema: &Semantics<RootDatabase>, |
155 | module: ast::Module, | ||
156 | ) -> Option<Runnable> { | ||
157 | if !has_test_function_or_multiple_test_submodules(&module) { | ||
158 | return None; | ||
159 | } | ||
160 | let module_def = sema.to_def(&module)?; | ||
161 | |||
162 | let path = module_def | ||
163 | .path_to_root(sema.db) | ||
164 | .into_iter() | ||
165 | .rev() | ||
166 | .filter_map(|it| it.name(sema.db)) | ||
167 | .join("::"); | ||
168 | |||
169 | let def = sema.to_def(&module)?; | ||
170 | let attrs = def.attrs(sema.db); | ||
171 | let cfg = attrs.cfg(); | ||
172 | let nav = module_def.to_nav(sema.db); | ||
173 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) | ||
174 | } | ||
175 | |||
176 | // FIXME: figure out a proper API here. | ||
177 | pub(crate) fn doc_owner_to_def( | ||
178 | sema: &Semantics<RootDatabase>, | ||
179 | item: SyntaxNode, | ||
180 | ) -> Option<Definition> { | ||
181 | let res: hir::ModuleDef = match_ast! { | ||
151 | match item { | 182 | match item { |
152 | ast::Fn(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 183 | ast::SourceFile(it) => sema.scope(&item).module()?.into(), |
153 | ast::Struct(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 184 | ast::Fn(it) => sema.to_def(&it)?.into(), |
154 | ast::Enum(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 185 | ast::Struct(it) => sema.to_def(&it)?.into(), |
155 | ast::Union(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 186 | ast::Enum(it) => sema.to_def(&it)?.into(), |
156 | ast::Trait(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 187 | ast::Union(it) => sema.to_def(&it)?.into(), |
157 | ast::Const(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 188 | ast::Trait(it) => sema.to_def(&it)?.into(), |
158 | ast::Static(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 189 | ast::Const(it) => sema.to_def(&it)?.into(), |
159 | ast::TypeAlias(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), | 190 | ast::Static(it) => sema.to_def(&it)?.into(), |
160 | _ => None, | 191 | ast::TypeAlias(it) => sema.to_def(&it)?.into(), |
192 | _ => return None, | ||
161 | } | 193 | } |
162 | } | 194 | }; |
195 | Some(Definition::ModuleDef(res)) | ||
163 | } | 196 | } |
164 | 197 | ||
165 | fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> { | 198 | fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> { |
@@ -230,7 +263,7 @@ impl TestAttr { | |||
230 | 263 | ||
231 | const RUSTDOC_FENCE: &str = "```"; | 264 | const RUSTDOC_FENCE: &str = "```"; |
232 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = | 265 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = |
233 | &["", "rust", "should_panic", "edition2015", "edition2018"]; | 266 | &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"]; |
234 | 267 | ||
235 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | 268 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { |
236 | attrs.docs().map_or(false, |doc| { | 269 | attrs.docs().map_or(false, |doc| { |
@@ -254,26 +287,6 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | |||
254 | }) | 287 | }) |
255 | } | 288 | } |
256 | 289 | ||
257 | fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { | ||
258 | if !has_test_function_or_multiple_test_submodules(&module) { | ||
259 | return None; | ||
260 | } | ||
261 | let module_def = sema.to_def(&module)?; | ||
262 | |||
263 | let path = module_def | ||
264 | .path_to_root(sema.db) | ||
265 | .into_iter() | ||
266 | .rev() | ||
267 | .filter_map(|it| it.name(sema.db)) | ||
268 | .join("::"); | ||
269 | |||
270 | let def = sema.to_def(&module)?; | ||
271 | let attrs = def.attrs(sema.db); | ||
272 | let cfg = attrs.cfg(); | ||
273 | let nav = module_def.to_nav(sema.db); | ||
274 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) | ||
275 | } | ||
276 | |||
277 | // We could create runnables for modules with number_of_test_submodules > 0, | 290 | // We could create runnables for modules with number_of_test_submodules > 0, |
278 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already | 291 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already |
279 | fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { | 292 | fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { |
@@ -330,7 +343,7 @@ mod tests { | |||
330 | check( | 343 | check( |
331 | r#" | 344 | r#" |
332 | //- /lib.rs | 345 | //- /lib.rs |
333 | <|> | 346 | $0 |
334 | fn main() {} | 347 | fn main() {} |
335 | 348 | ||
336 | #[test] | 349 | #[test] |
@@ -426,7 +439,7 @@ fn bench() {} | |||
426 | check( | 439 | check( |
427 | r#" | 440 | r#" |
428 | //- /lib.rs | 441 | //- /lib.rs |
429 | <|> | 442 | $0 |
430 | fn main() {} | 443 | fn main() {} |
431 | 444 | ||
432 | /// ``` | 445 | /// ``` |
@@ -574,7 +587,7 @@ struct StructWithRunnable(String); | |||
574 | check( | 587 | check( |
575 | r#" | 588 | r#" |
576 | //- /lib.rs | 589 | //- /lib.rs |
577 | <|> | 590 | $0 |
578 | fn main() {} | 591 | fn main() {} |
579 | 592 | ||
580 | struct Data; | 593 | struct Data; |
@@ -626,7 +639,7 @@ impl Data { | |||
626 | check( | 639 | check( |
627 | r#" | 640 | r#" |
628 | //- /lib.rs | 641 | //- /lib.rs |
629 | <|> | 642 | $0 |
630 | mod test_mod { | 643 | mod test_mod { |
631 | #[test] | 644 | #[test] |
632 | fn test_foo1() {} | 645 | fn test_foo1() {} |
@@ -680,7 +693,7 @@ mod test_mod { | |||
680 | check( | 693 | check( |
681 | r#" | 694 | r#" |
682 | //- /lib.rs | 695 | //- /lib.rs |
683 | <|> | 696 | $0 |
684 | mod root_tests { | 697 | mod root_tests { |
685 | mod nested_tests_0 { | 698 | mod nested_tests_0 { |
686 | mod nested_tests_1 { | 699 | mod nested_tests_1 { |
@@ -820,7 +833,7 @@ mod root_tests { | |||
820 | check( | 833 | check( |
821 | r#" | 834 | r#" |
822 | //- /lib.rs crate:foo cfg:feature=foo | 835 | //- /lib.rs crate:foo cfg:feature=foo |
823 | <|> | 836 | $0 |
824 | #[test] | 837 | #[test] |
825 | #[cfg(feature = "foo")] | 838 | #[cfg(feature = "foo")] |
826 | fn test_foo1() {} | 839 | fn test_foo1() {} |
@@ -865,7 +878,7 @@ fn test_foo1() {} | |||
865 | check( | 878 | check( |
866 | r#" | 879 | r#" |
867 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar | 880 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar |
868 | <|> | 881 | $0 |
869 | #[test] | 882 | #[test] |
870 | #[cfg(all(feature = "foo", feature = "bar"))] | 883 | #[cfg(all(feature = "foo", feature = "bar"))] |
871 | fn test_foo1() {} | 884 | fn test_foo1() {} |
@@ -920,7 +933,7 @@ fn test_foo1() {} | |||
920 | check( | 933 | check( |
921 | r#" | 934 | r#" |
922 | //- /lib.rs | 935 | //- /lib.rs |
923 | <|> | 936 | $0 |
924 | mod test_mod { | 937 | mod test_mod { |
925 | fn foo1() {} | 938 | fn foo1() {} |
926 | } | 939 | } |
@@ -939,7 +952,7 @@ mod test_mod { | |||
939 | //- /lib.rs | 952 | //- /lib.rs |
940 | mod foo; | 953 | mod foo; |
941 | //- /foo.rs | 954 | //- /foo.rs |
942 | struct Foo;<|> | 955 | struct Foo;$0 |
943 | impl Foo { | 956 | impl Foo { |
944 | /// ``` | 957 | /// ``` |
945 | /// let x = 5; | 958 | /// let x = 5; |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 5ad96581b..f2d4da78d 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -1,35 +1,39 @@ | |||
1 | pub(crate) mod tags; | ||
2 | |||
3 | mod highlights; | ||
4 | mod injector; | ||
5 | |||
6 | mod highlight; | ||
1 | mod format; | 7 | mod format; |
2 | mod html; | ||
3 | mod injection; | ||
4 | mod macro_rules; | 8 | mod macro_rules; |
5 | pub(crate) mod tags; | 9 | mod inject; |
10 | |||
11 | mod html; | ||
6 | #[cfg(test)] | 12 | #[cfg(test)] |
7 | mod tests; | 13 | mod tests; |
8 | 14 | ||
9 | use hir::{AsAssocItem, Local, Name, Semantics, VariantDef}; | 15 | use hir::{Name, Semantics}; |
10 | use ide_db::{ | 16 | use ide_db::RootDatabase; |
11 | defs::{Definition, NameClass, NameRefClass}, | ||
12 | RootDatabase, | ||
13 | }; | ||
14 | use rustc_hash::FxHashMap; | 17 | use rustc_hash::FxHashMap; |
15 | use syntax::{ | 18 | use syntax::{ |
16 | ast::{self, HasFormatSpecifier}, | 19 | ast::{self, HasFormatSpecifier}, |
17 | AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, | 20 | AstNode, AstToken, Direction, NodeOrToken, |
18 | SyntaxKind::{self, *}, | 21 | SyntaxKind::*, |
19 | SyntaxNode, SyntaxToken, TextRange, WalkEvent, T, | 22 | SyntaxNode, TextRange, WalkEvent, T, |
20 | }; | 23 | }; |
21 | 24 | ||
22 | use crate::{ | 25 | use crate::{ |
23 | syntax_highlighting::{ | 26 | syntax_highlighting::{ |
24 | format::FormatStringHighlighter, macro_rules::MacroRulesHighlighter, tags::Highlight, | 27 | format::highlight_format_string, highlights::Highlights, |
28 | macro_rules::MacroRulesHighlighter, tags::Highlight, | ||
25 | }, | 29 | }, |
26 | FileId, HighlightModifier, HighlightTag, SymbolKind, | 30 | FileId, HlMod, HlTag, SymbolKind, |
27 | }; | 31 | }; |
28 | 32 | ||
29 | pub(crate) use html::highlight_as_html; | 33 | pub(crate) use html::highlight_as_html; |
30 | 34 | ||
31 | #[derive(Debug, Clone)] | 35 | #[derive(Debug, Clone, Copy)] |
32 | pub struct HighlightedRange { | 36 | pub struct HlRange { |
33 | pub range: TextRange, | 37 | pub range: TextRange, |
34 | pub highlight: Highlight, | 38 | pub highlight: Highlight, |
35 | pub binding_hash: Option<u64>, | 39 | pub binding_hash: Option<u64>, |
@@ -49,7 +53,7 @@ pub(crate) fn highlight( | |||
49 | file_id: FileId, | 53 | file_id: FileId, |
50 | range_to_highlight: Option<TextRange>, | 54 | range_to_highlight: Option<TextRange>, |
51 | syntactic_name_ref_highlighting: bool, | 55 | syntactic_name_ref_highlighting: bool, |
52 | ) -> Vec<HighlightedRange> { | 56 | ) -> Vec<HlRange> { |
53 | let _p = profile::span("highlight"); | 57 | let _p = profile::span("highlight"); |
54 | let sema = Semantics::new(db); | 58 | let sema = Semantics::new(db); |
55 | 59 | ||
@@ -68,28 +72,30 @@ pub(crate) fn highlight( | |||
68 | } | 72 | } |
69 | }; | 73 | }; |
70 | 74 | ||
75 | let mut hl = highlights::Highlights::new(range_to_highlight); | ||
76 | traverse(&mut hl, &sema, &root, range_to_highlight, syntactic_name_ref_highlighting); | ||
77 | hl.to_vec() | ||
78 | } | ||
79 | |||
80 | fn traverse( | ||
81 | hl: &mut Highlights, | ||
82 | sema: &Semantics<RootDatabase>, | ||
83 | root: &SyntaxNode, | ||
84 | range_to_highlight: TextRange, | ||
85 | syntactic_name_ref_highlighting: bool, | ||
86 | ) { | ||
71 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); | 87 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); |
72 | // We use a stack for the DFS traversal below. | ||
73 | // When we leave a node, the we use it to flatten the highlighted ranges. | ||
74 | let mut stack = HighlightedRangeStack::new(); | ||
75 | 88 | ||
76 | let mut current_macro_call: Option<ast::MacroCall> = None; | 89 | let mut current_macro_call: Option<ast::MacroCall> = None; |
77 | let mut current_macro_rules: Option<ast::MacroRules> = None; | 90 | let mut current_macro_rules: Option<ast::MacroRules> = None; |
78 | let mut format_string_highlighter = FormatStringHighlighter::default(); | ||
79 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); | 91 | let mut macro_rules_highlighter = MacroRulesHighlighter::default(); |
80 | let mut inside_attribute = false; | 92 | let mut inside_attribute = false; |
81 | 93 | ||
82 | // Walk all nodes, keeping track of whether we are inside a macro or not. | 94 | // Walk all nodes, keeping track of whether we are inside a macro or not. |
83 | // If in macro, expand it first and highlight the expanded code. | 95 | // If in macro, expand it first and highlight the expanded code. |
84 | for event in root.preorder_with_tokens() { | 96 | for event in root.preorder_with_tokens() { |
85 | match &event { | ||
86 | WalkEvent::Enter(_) => stack.push(), | ||
87 | WalkEvent::Leave(_) => stack.pop(), | ||
88 | }; | ||
89 | |||
90 | let event_range = match &event { | 97 | let event_range = match &event { |
91 | WalkEvent::Enter(it) => it.text_range(), | 98 | WalkEvent::Enter(it) | WalkEvent::Leave(it) => it.text_range(), |
92 | WalkEvent::Leave(it) => it.text_range(), | ||
93 | }; | 99 | }; |
94 | 100 | ||
95 | // Element outside of the viewport, no need to highlight | 101 | // Element outside of the viewport, no need to highlight |
@@ -101,9 +107,9 @@ pub(crate) fn highlight( | |||
101 | match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) { | 107 | match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) { |
102 | WalkEvent::Enter(Some(mc)) => { | 108 | WalkEvent::Enter(Some(mc)) => { |
103 | if let Some(range) = macro_call_range(&mc) { | 109 | if let Some(range) = macro_call_range(&mc) { |
104 | stack.add(HighlightedRange { | 110 | hl.add(HlRange { |
105 | range, | 111 | range, |
106 | highlight: HighlightTag::Symbol(SymbolKind::Macro).into(), | 112 | highlight: HlTag::Symbol(SymbolKind::Macro).into(), |
107 | binding_hash: None, | 113 | binding_hash: None, |
108 | }); | 114 | }); |
109 | } | 115 | } |
@@ -113,7 +119,6 @@ pub(crate) fn highlight( | |||
113 | WalkEvent::Leave(Some(mc)) => { | 119 | WalkEvent::Leave(Some(mc)) => { |
114 | assert_eq!(current_macro_call, Some(mc)); | 120 | assert_eq!(current_macro_call, Some(mc)); |
115 | current_macro_call = None; | 121 | current_macro_call = None; |
116 | format_string_highlighter = FormatStringHighlighter::default(); | ||
117 | } | 122 | } |
118 | _ => (), | 123 | _ => (), |
119 | } | 124 | } |
@@ -131,33 +136,24 @@ pub(crate) fn highlight( | |||
131 | } | 136 | } |
132 | _ => (), | 137 | _ => (), |
133 | } | 138 | } |
134 | |||
135 | match &event { | 139 | match &event { |
136 | // Check for Rust code in documentation | ||
137 | WalkEvent::Leave(NodeOrToken::Node(node)) => { | ||
138 | if ast::Attr::can_cast(node.kind()) { | ||
139 | inside_attribute = false | ||
140 | } | ||
141 | if let Some((doctest, range_mapping, new_comments)) = | ||
142 | injection::extract_doc_comments(node) | ||
143 | { | ||
144 | injection::highlight_doc_comment( | ||
145 | doctest, | ||
146 | range_mapping, | ||
147 | new_comments, | ||
148 | &mut stack, | ||
149 | ); | ||
150 | } | ||
151 | } | ||
152 | WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { | 140 | WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { |
153 | inside_attribute = true | 141 | inside_attribute = true |
154 | } | 142 | } |
143 | WalkEvent::Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { | ||
144 | inside_attribute = false | ||
145 | } | ||
155 | _ => (), | 146 | _ => (), |
156 | } | 147 | } |
157 | 148 | ||
158 | let element = match event { | 149 | let element = match event { |
159 | WalkEvent::Enter(it) => it, | 150 | WalkEvent::Enter(it) => it, |
160 | WalkEvent::Leave(_) => continue, | 151 | WalkEvent::Leave(it) => { |
152 | if let Some(node) = it.as_node() { | ||
153 | inject::doc_comment(hl, node); | ||
154 | } | ||
155 | continue; | ||
156 | } | ||
161 | }; | 157 | }; |
162 | 158 | ||
163 | let range = element.text_range(); | 159 | let range = element.text_range(); |
@@ -177,8 +173,6 @@ pub(crate) fn highlight( | |||
177 | let token = sema.descend_into_macros(token.clone()); | 173 | let token = sema.descend_into_macros(token.clone()); |
178 | let parent = token.parent(); | 174 | let parent = token.parent(); |
179 | 175 | ||
180 | format_string_highlighter.check_for_format_string(&parent); | ||
181 | |||
182 | // We only care Name and Name_ref | 176 | // We only care Name and Name_ref |
183 | match (token.kind(), parent.kind()) { | 177 | match (token.kind(), parent.kind()) { |
184 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), | 178 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), |
@@ -191,213 +185,45 @@ pub(crate) fn highlight( | |||
191 | if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) { | 185 | if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) { |
192 | if token.is_raw() { | 186 | if token.is_raw() { |
193 | let expanded = element_to_highlight.as_token().unwrap().clone(); | 187 | let expanded = element_to_highlight.as_token().unwrap().clone(); |
194 | if injection::highlight_injection(&mut stack, &sema, token, expanded).is_some() { | 188 | if inject::ra_fixture(hl, &sema, token, expanded).is_some() { |
195 | continue; | 189 | continue; |
196 | } | 190 | } |
197 | } | 191 | } |
198 | } | 192 | } |
199 | 193 | ||
200 | if let Some((mut highlight, binding_hash)) = highlight_element( | 194 | if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { |
195 | continue; | ||
196 | } | ||
197 | |||
198 | if let Some((mut highlight, binding_hash)) = highlight::element( | ||
201 | &sema, | 199 | &sema, |
202 | &mut bindings_shadow_count, | 200 | &mut bindings_shadow_count, |
203 | syntactic_name_ref_highlighting, | 201 | syntactic_name_ref_highlighting, |
204 | element_to_highlight.clone(), | 202 | element_to_highlight.clone(), |
205 | ) { | 203 | ) { |
206 | if inside_attribute { | 204 | if inside_attribute { |
207 | highlight = highlight | HighlightModifier::Attribute; | 205 | highlight = highlight | HlMod::Attribute; |
208 | } | ||
209 | |||
210 | if macro_rules_highlighter.highlight(element_to_highlight.clone()).is_none() { | ||
211 | stack.add(HighlightedRange { range, highlight, binding_hash }); | ||
212 | } | 206 | } |
213 | 207 | ||
214 | if let Some(string) = | 208 | hl.add(HlRange { range, highlight, binding_hash }); |
215 | element_to_highlight.as_token().cloned().and_then(ast::String::cast) | ||
216 | { | ||
217 | format_string_highlighter.highlight_format_string(&mut stack, &string, range); | ||
218 | // Highlight escape sequences | ||
219 | if let Some(char_ranges) = string.char_ranges() { | ||
220 | stack.push(); | ||
221 | for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) { | ||
222 | if string.text()[piece_range.start().into()..].starts_with('\\') { | ||
223 | stack.add(HighlightedRange { | ||
224 | range: piece_range + range.start(), | ||
225 | highlight: HighlightTag::EscapeSequence.into(), | ||
226 | binding_hash: None, | ||
227 | }); | ||
228 | } | ||
229 | } | ||
230 | stack.pop_and_inject(None); | ||
231 | } | ||
232 | } | ||
233 | } | 209 | } |
234 | } | ||
235 | |||
236 | stack.flattened() | ||
237 | } | ||
238 | |||
239 | #[derive(Debug)] | ||
240 | struct HighlightedRangeStack { | ||
241 | stack: Vec<Vec<HighlightedRange>>, | ||
242 | } | ||
243 | |||
244 | /// We use a stack to implement the flattening logic for the highlighted | ||
245 | /// syntax ranges. | ||
246 | impl HighlightedRangeStack { | ||
247 | fn new() -> Self { | ||
248 | Self { stack: vec![Vec::new()] } | ||
249 | } | ||
250 | |||
251 | fn push(&mut self) { | ||
252 | self.stack.push(Vec::new()); | ||
253 | } | ||
254 | |||
255 | /// Flattens the highlighted ranges. | ||
256 | /// | ||
257 | /// For example `#[cfg(feature = "foo")]` contains the nested ranges: | ||
258 | /// 1) parent-range: Attribute [0, 23) | ||
259 | /// 2) child-range: String [16, 21) | ||
260 | /// | ||
261 | /// The following code implements the flattening, for our example this results to: | ||
262 | /// `[Attribute [0, 16), String [16, 21), Attribute [21, 23)]` | ||
263 | fn pop(&mut self) { | ||
264 | let children = self.stack.pop().unwrap(); | ||
265 | let prev = self.stack.last_mut().unwrap(); | ||
266 | let needs_flattening = !children.is_empty() | ||
267 | && !prev.is_empty() | ||
268 | && prev.last().unwrap().range.contains_range(children.first().unwrap().range); | ||
269 | if !needs_flattening { | ||
270 | prev.extend(children); | ||
271 | } else { | ||
272 | let mut parent = prev.pop().unwrap(); | ||
273 | for ele in children { | ||
274 | assert!(parent.range.contains_range(ele.range)); | ||
275 | |||
276 | let cloned = Self::intersect(&mut parent, &ele); | ||
277 | if !parent.range.is_empty() { | ||
278 | prev.push(parent); | ||
279 | } | ||
280 | prev.push(ele); | ||
281 | parent = cloned; | ||
282 | } | ||
283 | if !parent.range.is_empty() { | ||
284 | prev.push(parent); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /// Intersects the `HighlightedRange` `parent` with `child`. | ||
290 | /// `parent` is mutated in place, becoming the range before `child`. | ||
291 | /// Returns the range (of the same type as `parent`) *after* `child`. | ||
292 | fn intersect(parent: &mut HighlightedRange, child: &HighlightedRange) -> HighlightedRange { | ||
293 | assert!(parent.range.contains_range(child.range)); | ||
294 | |||
295 | let mut cloned = parent.clone(); | ||
296 | parent.range = TextRange::new(parent.range.start(), child.range.start()); | ||
297 | cloned.range = TextRange::new(child.range.end(), cloned.range.end()); | ||
298 | 210 | ||
299 | cloned | 211 | if let Some(string) = element_to_highlight.as_token().cloned().and_then(ast::String::cast) { |
300 | } | 212 | highlight_format_string(hl, &string, range); |
301 | 213 | // Highlight escape sequences | |
302 | /// Remove the `HighlightRange` of `parent` that's currently covered by `child`. | 214 | if let Some(char_ranges) = string.char_ranges() { |
303 | fn intersect_partial(parent: &mut HighlightedRange, child: &HighlightedRange) { | 215 | for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) { |
304 | assert!( | 216 | if string.text()[piece_range.start().into()..].starts_with('\\') { |
305 | parent.range.start() <= child.range.start() | 217 | hl.add(HlRange { |
306 | && parent.range.end() >= child.range.start() | 218 | range: piece_range + range.start(), |
307 | && child.range.end() > parent.range.end() | 219 | highlight: HlTag::EscapeSequence.into(), |
308 | ); | 220 | binding_hash: None, |
309 | 221 | }); | |
310 | parent.range = TextRange::new(parent.range.start(), child.range.start()); | ||
311 | } | ||
312 | |||
313 | /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`) | ||
314 | /// can only modify the last range currently on the stack. | ||
315 | /// Can be used to do injections that span multiple ranges, like the | ||
316 | /// doctest injection below. | ||
317 | /// If `overwrite_parent` is non-optional, the highlighting of the parent range | ||
318 | /// is overwritten with the argument. | ||
319 | /// | ||
320 | /// Note that `pop` can be simulated by `pop_and_inject(false)` but the | ||
321 | /// latter is computationally more expensive. | ||
322 | fn pop_and_inject(&mut self, overwrite_parent: Option<Highlight>) { | ||
323 | let mut children = self.stack.pop().unwrap(); | ||
324 | let prev = self.stack.last_mut().unwrap(); | ||
325 | children.sort_by_key(|range| range.range.start()); | ||
326 | prev.sort_by_key(|range| range.range.start()); | ||
327 | |||
328 | for child in children { | ||
329 | if let Some(idx) = | ||
330 | prev.iter().position(|parent| parent.range.contains_range(child.range)) | ||
331 | { | ||
332 | if let Some(tag) = overwrite_parent { | ||
333 | prev[idx].highlight = tag; | ||
334 | } | ||
335 | |||
336 | let cloned = Self::intersect(&mut prev[idx], &child); | ||
337 | let insert_idx = if prev[idx].range.is_empty() { | ||
338 | prev.remove(idx); | ||
339 | idx | ||
340 | } else { | ||
341 | idx + 1 | ||
342 | }; | ||
343 | prev.insert(insert_idx, child); | ||
344 | if !cloned.range.is_empty() { | ||
345 | prev.insert(insert_idx + 1, cloned); | ||
346 | } | ||
347 | } else { | ||
348 | let maybe_idx = | ||
349 | prev.iter().position(|parent| parent.range.contains(child.range.start())); | ||
350 | match (overwrite_parent, maybe_idx) { | ||
351 | (Some(_), Some(idx)) => { | ||
352 | Self::intersect_partial(&mut prev[idx], &child); | ||
353 | let insert_idx = if prev[idx].range.is_empty() { | ||
354 | prev.remove(idx); | ||
355 | idx | ||
356 | } else { | ||
357 | idx + 1 | ||
358 | }; | ||
359 | prev.insert(insert_idx, child); | ||
360 | } | ||
361 | (_, None) => { | ||
362 | let idx = prev | ||
363 | .binary_search_by_key(&child.range.start(), |range| range.range.start()) | ||
364 | .unwrap_or_else(|x| x); | ||
365 | prev.insert(idx, child); | ||
366 | } | ||
367 | _ => { | ||
368 | unreachable!("child range should be completely contained in parent range"); | ||
369 | } | 222 | } |
370 | } | 223 | } |
371 | } | 224 | } |
372 | } | 225 | } |
373 | } | 226 | } |
374 | |||
375 | fn add(&mut self, range: HighlightedRange) { | ||
376 | self.stack | ||
377 | .last_mut() | ||
378 | .expect("during DFS traversal, the stack must not be empty") | ||
379 | .push(range) | ||
380 | } | ||
381 | |||
382 | fn flattened(mut self) -> Vec<HighlightedRange> { | ||
383 | assert_eq!( | ||
384 | self.stack.len(), | ||
385 | 1, | ||
386 | "after DFS traversal, the stack should only contain a single element" | ||
387 | ); | ||
388 | let mut res = self.stack.pop().unwrap(); | ||
389 | res.sort_by_key(|range| range.range.start()); | ||
390 | // Check that ranges are sorted and disjoint | ||
391 | for (left, right) in res.iter().zip(res.iter().skip(1)) { | ||
392 | assert!( | ||
393 | left.range.end() <= right.range.start(), | ||
394 | "left: {:#?}, right: {:#?}", | ||
395 | left, | ||
396 | right | ||
397 | ); | ||
398 | } | ||
399 | res | ||
400 | } | ||
401 | } | 227 | } |
402 | 228 | ||
403 | fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { | 229 | fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { |
@@ -415,523 +241,3 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { | |||
415 | 241 | ||
416 | Some(TextRange::new(range_start, range_end)) | 242 | Some(TextRange::new(range_start, range_end)) |
417 | } | 243 | } |
418 | |||
419 | /// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. | ||
420 | fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool { | ||
421 | while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { | ||
422 | if parent.kind() != *kind { | ||
423 | return false; | ||
424 | } | ||
425 | |||
426 | // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value | ||
427 | // in the same pattern is unstable: rust-lang/rust#68354. | ||
428 | node = node.parent().unwrap().into(); | ||
429 | kinds = rest; | ||
430 | } | ||
431 | |||
432 | // Only true if we matched all expected kinds | ||
433 | kinds.len() == 0 | ||
434 | } | ||
435 | |||
436 | fn is_consumed_lvalue( | ||
437 | node: NodeOrToken<SyntaxNode, SyntaxToken>, | ||
438 | local: &Local, | ||
439 | db: &RootDatabase, | ||
440 | ) -> bool { | ||
441 | // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. | ||
442 | parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db) | ||
443 | } | ||
444 | |||
445 | fn highlight_element( | ||
446 | sema: &Semantics<RootDatabase>, | ||
447 | bindings_shadow_count: &mut FxHashMap<Name, u32>, | ||
448 | syntactic_name_ref_highlighting: bool, | ||
449 | element: SyntaxElement, | ||
450 | ) -> Option<(Highlight, Option<u64>)> { | ||
451 | let db = sema.db; | ||
452 | let mut binding_hash = None; | ||
453 | let highlight: Highlight = match element.kind() { | ||
454 | FN => { | ||
455 | bindings_shadow_count.clear(); | ||
456 | return None; | ||
457 | } | ||
458 | |||
459 | // Highlight definitions depending on the "type" of the definition. | ||
460 | NAME => { | ||
461 | let name = element.into_node().and_then(ast::Name::cast).unwrap(); | ||
462 | let name_kind = NameClass::classify(sema, &name); | ||
463 | |||
464 | if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind { | ||
465 | if let Some(name) = local.name(db) { | ||
466 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | ||
467 | *shadow_count += 1; | ||
468 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
469 | } | ||
470 | }; | ||
471 | |||
472 | match name_kind { | ||
473 | Some(NameClass::ExternCrate(_)) => HighlightTag::Symbol(SymbolKind::Module).into(), | ||
474 | Some(NameClass::Definition(def)) => { | ||
475 | highlight_def(db, def) | HighlightModifier::Definition | ||
476 | } | ||
477 | Some(NameClass::ConstReference(def)) => highlight_def(db, def), | ||
478 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | ||
479 | let mut h = HighlightTag::Symbol(SymbolKind::Field).into(); | ||
480 | if let Definition::Field(field) = field_ref { | ||
481 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
482 | h |= HighlightModifier::Unsafe; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | h | ||
487 | } | ||
488 | None => highlight_name_by_syntax(name) | HighlightModifier::Definition, | ||
489 | } | ||
490 | } | ||
491 | |||
492 | // Highlight references like the definitions they resolve to | ||
493 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => { | ||
494 | // even though we track whether we are in an attribute or not we still need this special case | ||
495 | // as otherwise we would emit unresolved references for name refs inside attributes | ||
496 | Highlight::from(HighlightTag::Symbol(SymbolKind::Function)) | ||
497 | } | ||
498 | NAME_REF => { | ||
499 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | ||
500 | highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { | ||
501 | match NameRefClass::classify(sema, &name_ref) { | ||
502 | Some(name_kind) => match name_kind { | ||
503 | NameRefClass::ExternCrate(_) => { | ||
504 | HighlightTag::Symbol(SymbolKind::Module).into() | ||
505 | } | ||
506 | NameRefClass::Definition(def) => { | ||
507 | if let Definition::Local(local) = &def { | ||
508 | if let Some(name) = local.name(db) { | ||
509 | let shadow_count = | ||
510 | bindings_shadow_count.entry(name.clone()).or_default(); | ||
511 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
512 | } | ||
513 | }; | ||
514 | |||
515 | let mut h = highlight_def(db, def); | ||
516 | |||
517 | if let Definition::Local(local) = &def { | ||
518 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | ||
519 | h |= HighlightModifier::Consuming; | ||
520 | } | ||
521 | } | ||
522 | |||
523 | if let Some(parent) = name_ref.syntax().parent() { | ||
524 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | ||
525 | if let Definition::Field(field) = def { | ||
526 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
527 | h |= HighlightModifier::Unsafe; | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | |||
533 | h | ||
534 | } | ||
535 | NameRefClass::FieldShorthand { .. } => { | ||
536 | HighlightTag::Symbol(SymbolKind::Field).into() | ||
537 | } | ||
538 | }, | ||
539 | None if syntactic_name_ref_highlighting => { | ||
540 | highlight_name_ref_by_syntax(name_ref, sema) | ||
541 | } | ||
542 | None => HighlightTag::UnresolvedReference.into(), | ||
543 | } | ||
544 | }) | ||
545 | } | ||
546 | |||
547 | // Simple token-based highlighting | ||
548 | COMMENT => { | ||
549 | let comment = element.into_token().and_then(ast::Comment::cast)?; | ||
550 | let h = HighlightTag::Comment; | ||
551 | match comment.kind().doc { | ||
552 | Some(_) => h | HighlightModifier::Documentation, | ||
553 | None => h.into(), | ||
554 | } | ||
555 | } | ||
556 | STRING | BYTE_STRING => HighlightTag::StringLiteral.into(), | ||
557 | ATTR => HighlightTag::Attribute.into(), | ||
558 | INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(), | ||
559 | BYTE => HighlightTag::ByteLiteral.into(), | ||
560 | CHAR => HighlightTag::CharLiteral.into(), | ||
561 | QUESTION => Highlight::new(HighlightTag::Operator) | HighlightModifier::ControlFlow, | ||
562 | LIFETIME => { | ||
563 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); | ||
564 | |||
565 | match NameClass::classify_lifetime(sema, &lifetime) { | ||
566 | Some(NameClass::Definition(def)) => { | ||
567 | highlight_def(db, def) | HighlightModifier::Definition | ||
568 | } | ||
569 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { | ||
570 | Some(NameRefClass::Definition(def)) => highlight_def(db, def), | ||
571 | _ => Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)), | ||
572 | }, | ||
573 | _ => { | ||
574 | Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)) | ||
575 | | HighlightModifier::Definition | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | p if p.is_punct() => match p { | ||
580 | T![&] => { | ||
581 | let h = HighlightTag::Operator.into(); | ||
582 | let is_unsafe = element | ||
583 | .parent() | ||
584 | .and_then(ast::RefExpr::cast) | ||
585 | .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)) | ||
586 | .unwrap_or(false); | ||
587 | if is_unsafe { | ||
588 | h | HighlightModifier::Unsafe | ||
589 | } else { | ||
590 | h | ||
591 | } | ||
592 | } | ||
593 | T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => { | ||
594 | HighlightTag::Operator.into() | ||
595 | } | ||
596 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | ||
597 | HighlightTag::Symbol(SymbolKind::Macro).into() | ||
598 | } | ||
599 | T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { | ||
600 | HighlightTag::BuiltinType.into() | ||
601 | } | ||
602 | T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { | ||
603 | HighlightTag::Keyword.into() | ||
604 | } | ||
605 | T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
606 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
607 | |||
608 | let expr = prefix_expr.expr()?; | ||
609 | let ty = sema.type_of_expr(&expr)?; | ||
610 | if ty.is_raw_ptr() { | ||
611 | HighlightTag::Operator | HighlightModifier::Unsafe | ||
612 | } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { | ||
613 | HighlightTag::Operator.into() | ||
614 | } else { | ||
615 | HighlightTag::Punctuation.into() | ||
616 | } | ||
617 | } | ||
618 | T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
619 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
620 | |||
621 | let expr = prefix_expr.expr()?; | ||
622 | match expr { | ||
623 | ast::Expr::Literal(_) => HighlightTag::NumericLiteral, | ||
624 | _ => HighlightTag::Operator, | ||
625 | } | ||
626 | .into() | ||
627 | } | ||
628 | _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
629 | HighlightTag::Operator.into() | ||
630 | } | ||
631 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => { | ||
632 | HighlightTag::Operator.into() | ||
633 | } | ||
634 | _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { | ||
635 | HighlightTag::Operator.into() | ||
636 | } | ||
637 | _ if element.parent().and_then(ast::RangePat::cast).is_some() => { | ||
638 | HighlightTag::Operator.into() | ||
639 | } | ||
640 | _ if element.parent().and_then(ast::RestPat::cast).is_some() => { | ||
641 | HighlightTag::Operator.into() | ||
642 | } | ||
643 | _ if element.parent().and_then(ast::Attr::cast).is_some() => { | ||
644 | HighlightTag::Attribute.into() | ||
645 | } | ||
646 | _ => HighlightTag::Punctuation.into(), | ||
647 | }, | ||
648 | |||
649 | k if k.is_keyword() => { | ||
650 | let h = Highlight::new(HighlightTag::Keyword); | ||
651 | match k { | ||
652 | T![break] | ||
653 | | T![continue] | ||
654 | | T![else] | ||
655 | | T![if] | ||
656 | | T![loop] | ||
657 | | T![match] | ||
658 | | T![return] | ||
659 | | T![while] | ||
660 | | T![in] => h | HighlightModifier::ControlFlow, | ||
661 | T![for] if !is_child_of_impl(&element) => h | HighlightModifier::ControlFlow, | ||
662 | T![unsafe] => h | HighlightModifier::Unsafe, | ||
663 | T![true] | T![false] => HighlightTag::BoolLiteral.into(), | ||
664 | T![self] => { | ||
665 | let self_param_is_mut = element | ||
666 | .parent() | ||
667 | .and_then(ast::SelfParam::cast) | ||
668 | .and_then(|p| p.mut_token()) | ||
669 | .is_some(); | ||
670 | let self_path = &element | ||
671 | .parent() | ||
672 | .as_ref() | ||
673 | .and_then(SyntaxNode::parent) | ||
674 | .and_then(ast::Path::cast) | ||
675 | .and_then(|p| sema.resolve_path(&p)); | ||
676 | let mut h = HighlightTag::Symbol(SymbolKind::SelfParam).into(); | ||
677 | if self_param_is_mut | ||
678 | || matches!(self_path, | ||
679 | Some(hir::PathResolution::Local(local)) | ||
680 | if local.is_self(db) | ||
681 | && (local.is_mut(db) || local.ty(db).is_mutable_reference()) | ||
682 | ) | ||
683 | { | ||
684 | h |= HighlightModifier::Mutable | ||
685 | } | ||
686 | |||
687 | if let Some(hir::PathResolution::Local(local)) = self_path { | ||
688 | if is_consumed_lvalue(element, &local, db) { | ||
689 | h |= HighlightModifier::Consuming; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | h | ||
694 | } | ||
695 | T![ref] => element | ||
696 | .parent() | ||
697 | .and_then(ast::IdentPat::cast) | ||
698 | .and_then(|ident_pat| { | ||
699 | if sema.is_unsafe_ident_pat(&ident_pat) { | ||
700 | Some(HighlightModifier::Unsafe) | ||
701 | } else { | ||
702 | None | ||
703 | } | ||
704 | }) | ||
705 | .map(|modifier| h | modifier) | ||
706 | .unwrap_or(h), | ||
707 | _ => h, | ||
708 | } | ||
709 | } | ||
710 | |||
711 | _ => return None, | ||
712 | }; | ||
713 | |||
714 | return Some((highlight, binding_hash)); | ||
715 | |||
716 | fn calc_binding_hash(name: &Name, shadow_count: u32) -> u64 { | ||
717 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { | ||
718 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | ||
719 | |||
720 | let mut hasher = DefaultHasher::new(); | ||
721 | x.hash(&mut hasher); | ||
722 | hasher.finish() | ||
723 | } | ||
724 | |||
725 | hash((name, shadow_count)) | ||
726 | } | ||
727 | } | ||
728 | |||
729 | fn is_child_of_impl(element: &SyntaxElement) -> bool { | ||
730 | match element.parent() { | ||
731 | Some(e) => e.kind() == IMPL, | ||
732 | _ => false, | ||
733 | } | ||
734 | } | ||
735 | |||
736 | fn highlight_func_by_name_ref( | ||
737 | sema: &Semantics<RootDatabase>, | ||
738 | name_ref: &ast::NameRef, | ||
739 | ) -> Option<Highlight> { | ||
740 | let method_call = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; | ||
741 | highlight_method_call(sema, &method_call) | ||
742 | } | ||
743 | |||
744 | fn highlight_method_call( | ||
745 | sema: &Semantics<RootDatabase>, | ||
746 | method_call: &ast::MethodCallExpr, | ||
747 | ) -> Option<Highlight> { | ||
748 | let func = sema.resolve_method_call(&method_call)?; | ||
749 | let mut h = HighlightTag::Symbol(SymbolKind::Function).into(); | ||
750 | h |= HighlightModifier::Associated; | ||
751 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | ||
752 | h |= HighlightModifier::Unsafe; | ||
753 | } | ||
754 | if let Some(self_param) = func.self_param(sema.db) { | ||
755 | match self_param.access(sema.db) { | ||
756 | hir::Access::Shared => (), | ||
757 | hir::Access::Exclusive => h |= HighlightModifier::Mutable, | ||
758 | hir::Access::Owned => { | ||
759 | if let Some(receiver_ty) = | ||
760 | method_call.receiver().and_then(|it| sema.type_of_expr(&it)) | ||
761 | { | ||
762 | if !receiver_ty.is_copy(sema.db) { | ||
763 | h |= HighlightModifier::Consuming | ||
764 | } | ||
765 | } | ||
766 | } | ||
767 | } | ||
768 | } | ||
769 | Some(h) | ||
770 | } | ||
771 | |||
772 | fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | ||
773 | match def { | ||
774 | Definition::Macro(_) => HighlightTag::Symbol(SymbolKind::Macro), | ||
775 | Definition::Field(_) => HighlightTag::Symbol(SymbolKind::Field), | ||
776 | Definition::ModuleDef(def) => match def { | ||
777 | hir::ModuleDef::Module(_) => HighlightTag::Symbol(SymbolKind::Module), | ||
778 | hir::ModuleDef::Function(func) => { | ||
779 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Function)); | ||
780 | if func.as_assoc_item(db).is_some() { | ||
781 | h |= HighlightModifier::Associated; | ||
782 | if func.self_param(db).is_none() { | ||
783 | h |= HighlightModifier::Static | ||
784 | } | ||
785 | } | ||
786 | if func.is_unsafe(db) { | ||
787 | h |= HighlightModifier::Unsafe; | ||
788 | } | ||
789 | return h; | ||
790 | } | ||
791 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Symbol(SymbolKind::Struct), | ||
792 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Symbol(SymbolKind::Enum), | ||
793 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Symbol(SymbolKind::Union), | ||
794 | hir::ModuleDef::Variant(_) => HighlightTag::Symbol(SymbolKind::Variant), | ||
795 | hir::ModuleDef::Const(konst) => { | ||
796 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Const)); | ||
797 | if konst.as_assoc_item(db).is_some() { | ||
798 | h |= HighlightModifier::Associated | ||
799 | } | ||
800 | return h; | ||
801 | } | ||
802 | hir::ModuleDef::Trait(_) => HighlightTag::Symbol(SymbolKind::Trait), | ||
803 | hir::ModuleDef::TypeAlias(type_) => { | ||
804 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::TypeAlias)); | ||
805 | if type_.as_assoc_item(db).is_some() { | ||
806 | h |= HighlightModifier::Associated | ||
807 | } | ||
808 | return h; | ||
809 | } | ||
810 | hir::ModuleDef::BuiltinType(_) => HighlightTag::BuiltinType, | ||
811 | hir::ModuleDef::Static(s) => { | ||
812 | let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Static)); | ||
813 | if s.is_mut(db) { | ||
814 | h |= HighlightModifier::Mutable; | ||
815 | h |= HighlightModifier::Unsafe; | ||
816 | } | ||
817 | return h; | ||
818 | } | ||
819 | }, | ||
820 | Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), | ||
821 | Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), | ||
822 | Definition::Local(local) => { | ||
823 | let tag = if local.is_param(db) { | ||
824 | HighlightTag::Symbol(SymbolKind::ValueParam) | ||
825 | } else { | ||
826 | HighlightTag::Symbol(SymbolKind::Local) | ||
827 | }; | ||
828 | let mut h = Highlight::new(tag); | ||
829 | if local.is_mut(db) || local.ty(db).is_mutable_reference() { | ||
830 | h |= HighlightModifier::Mutable; | ||
831 | } | ||
832 | if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) { | ||
833 | h |= HighlightModifier::Callable; | ||
834 | } | ||
835 | return h; | ||
836 | } | ||
837 | Definition::LifetimeParam(_) => HighlightTag::Symbol(SymbolKind::LifetimeParam), | ||
838 | Definition::Label(_) => HighlightTag::Symbol(SymbolKind::Label), | ||
839 | } | ||
840 | .into() | ||
841 | } | ||
842 | |||
843 | fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | ||
844 | let default = HighlightTag::UnresolvedReference; | ||
845 | |||
846 | let parent = match name.syntax().parent() { | ||
847 | Some(it) => it, | ||
848 | _ => return default.into(), | ||
849 | }; | ||
850 | |||
851 | let tag = match parent.kind() { | ||
852 | STRUCT => HighlightTag::Symbol(SymbolKind::Struct), | ||
853 | ENUM => HighlightTag::Symbol(SymbolKind::Enum), | ||
854 | VARIANT => HighlightTag::Symbol(SymbolKind::Variant), | ||
855 | UNION => HighlightTag::Symbol(SymbolKind::Union), | ||
856 | TRAIT => HighlightTag::Symbol(SymbolKind::Trait), | ||
857 | TYPE_ALIAS => HighlightTag::Symbol(SymbolKind::TypeAlias), | ||
858 | TYPE_PARAM => HighlightTag::Symbol(SymbolKind::TypeParam), | ||
859 | RECORD_FIELD => HighlightTag::Symbol(SymbolKind::Field), | ||
860 | MODULE => HighlightTag::Symbol(SymbolKind::Module), | ||
861 | FN => HighlightTag::Symbol(SymbolKind::Function), | ||
862 | CONST => HighlightTag::Symbol(SymbolKind::Const), | ||
863 | STATIC => HighlightTag::Symbol(SymbolKind::Static), | ||
864 | IDENT_PAT => HighlightTag::Symbol(SymbolKind::Local), | ||
865 | _ => default, | ||
866 | }; | ||
867 | |||
868 | tag.into() | ||
869 | } | ||
870 | |||
871 | fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight { | ||
872 | let default = HighlightTag::UnresolvedReference; | ||
873 | |||
874 | let parent = match name.syntax().parent() { | ||
875 | Some(it) => it, | ||
876 | _ => return default.into(), | ||
877 | }; | ||
878 | |||
879 | match parent.kind() { | ||
880 | METHOD_CALL_EXPR => { | ||
881 | return ast::MethodCallExpr::cast(parent) | ||
882 | .and_then(|method_call| highlight_method_call(sema, &method_call)) | ||
883 | .unwrap_or_else(|| HighlightTag::Symbol(SymbolKind::Function).into()); | ||
884 | } | ||
885 | FIELD_EXPR => { | ||
886 | let h = HighlightTag::Symbol(SymbolKind::Field); | ||
887 | let is_union = ast::FieldExpr::cast(parent) | ||
888 | .and_then(|field_expr| { | ||
889 | let field = sema.resolve_field(&field_expr)?; | ||
890 | Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { | ||
891 | true | ||
892 | } else { | ||
893 | false | ||
894 | }) | ||
895 | }) | ||
896 | .unwrap_or(false); | ||
897 | if is_union { | ||
898 | h | HighlightModifier::Unsafe | ||
899 | } else { | ||
900 | h.into() | ||
901 | } | ||
902 | } | ||
903 | PATH_SEGMENT => { | ||
904 | let path = match parent.parent().and_then(ast::Path::cast) { | ||
905 | Some(it) => it, | ||
906 | _ => return default.into(), | ||
907 | }; | ||
908 | let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) { | ||
909 | Some(it) => it, | ||
910 | _ => { | ||
911 | // within path, decide whether it is module or adt by checking for uppercase name | ||
912 | return if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
913 | HighlightTag::Symbol(SymbolKind::Struct) | ||
914 | } else { | ||
915 | HighlightTag::Symbol(SymbolKind::Module) | ||
916 | } | ||
917 | .into(); | ||
918 | } | ||
919 | }; | ||
920 | let parent = match expr.syntax().parent() { | ||
921 | Some(it) => it, | ||
922 | None => return default.into(), | ||
923 | }; | ||
924 | |||
925 | match parent.kind() { | ||
926 | CALL_EXPR => HighlightTag::Symbol(SymbolKind::Function).into(), | ||
927 | _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
928 | HighlightTag::Symbol(SymbolKind::Struct) | ||
929 | } else { | ||
930 | HighlightTag::Symbol(SymbolKind::Const) | ||
931 | } | ||
932 | .into(), | ||
933 | } | ||
934 | } | ||
935 | _ => default.into(), | ||
936 | } | ||
937 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index 26416022b..a74ca844b 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -1,65 +1,51 @@ | |||
1 | //! Syntax highlighting for format macro strings. | 1 | //! Syntax highlighting for format macro strings. |
2 | use syntax::{ | 2 | use syntax::{ |
3 | ast::{self, FormatSpecifier, HasFormatSpecifier}, | 3 | ast::{self, FormatSpecifier, HasFormatSpecifier}, |
4 | AstNode, AstToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, | 4 | AstNode, AstToken, TextRange, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag, SymbolKind}; |
8 | syntax_highlighting::HighlightedRangeStack, HighlightTag, HighlightedRange, SymbolKind, | ||
9 | }; | ||
10 | |||
11 | #[derive(Default)] | ||
12 | pub(super) struct FormatStringHighlighter { | ||
13 | format_string: Option<SyntaxElement>, | ||
14 | } | ||
15 | 8 | ||
16 | impl FormatStringHighlighter { | 9 | pub(super) fn highlight_format_string( |
17 | pub(super) fn check_for_format_string(&mut self, parent: &SyntaxNode) { | 10 | stack: &mut Highlights, |
18 | // Check if macro takes a format string and remember it for highlighting later. | 11 | string: &ast::String, |
19 | // The macros that accept a format string expand to a compiler builtin macros | 12 | range: TextRange, |
20 | // `format_args` and `format_args_nl`. | 13 | ) { |
21 | if let Some(name) = parent | 14 | if is_format_string(string).is_none() { |
22 | .parent() | 15 | return; |
23 | .and_then(ast::MacroCall::cast) | ||
24 | .and_then(|mc| mc.path()) | ||
25 | .and_then(|p| p.segment()) | ||
26 | .and_then(|s| s.name_ref()) | ||
27 | { | ||
28 | match name.text().as_str() { | ||
29 | "format_args" | "format_args_nl" => { | ||
30 | self.format_string = parent | ||
31 | .children_with_tokens() | ||
32 | .filter(|t| t.kind() != SyntaxKind::WHITESPACE) | ||
33 | .nth(1) | ||
34 | .filter(|e| ast::String::can_cast(e.kind())) | ||
35 | } | ||
36 | _ => {} | ||
37 | } | ||
38 | } | ||
39 | } | 16 | } |
40 | pub(super) fn highlight_format_string( | 17 | |
41 | &self, | 18 | string.lex_format_specifier(|piece_range, kind| { |
42 | range_stack: &mut HighlightedRangeStack, | 19 | if let Some(highlight) = highlight_format_specifier(kind) { |
43 | string: &impl HasFormatSpecifier, | 20 | stack.add(HlRange { |
44 | range: TextRange, | 21 | range: piece_range + range.start(), |
45 | ) { | 22 | highlight: highlight.into(), |
46 | if self.format_string.as_ref() == Some(&SyntaxElement::from(string.syntax().clone())) { | 23 | binding_hash: None, |
47 | range_stack.push(); | ||
48 | string.lex_format_specifier(|piece_range, kind| { | ||
49 | if let Some(highlight) = highlight_format_specifier(kind) { | ||
50 | range_stack.add(HighlightedRange { | ||
51 | range: piece_range + range.start(), | ||
52 | highlight: highlight.into(), | ||
53 | binding_hash: None, | ||
54 | }); | ||
55 | } | ||
56 | }); | 24 | }); |
57 | range_stack.pop(); | ||
58 | } | 25 | } |
26 | }); | ||
27 | } | ||
28 | |||
29 | fn is_format_string(string: &ast::String) -> Option<()> { | ||
30 | let parent = string.syntax().parent(); | ||
31 | |||
32 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; | ||
33 | if !matches!(name.text().as_str(), "format_args" | "format_args_nl") { | ||
34 | return None; | ||
35 | } | ||
36 | |||
37 | let first_literal = parent | ||
38 | .children_with_tokens() | ||
39 | .filter_map(|it| it.as_token().cloned().and_then(ast::String::cast)) | ||
40 | .next()?; | ||
41 | if &first_literal != string { | ||
42 | return None; | ||
59 | } | 43 | } |
44 | |||
45 | Some(()) | ||
60 | } | 46 | } |
61 | 47 | ||
62 | fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> { | 48 | fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> { |
63 | Some(match kind { | 49 | Some(match kind { |
64 | FormatSpecifier::Open | 50 | FormatSpecifier::Open |
65 | | FormatSpecifier::Close | 51 | | FormatSpecifier::Close |
@@ -71,8 +57,10 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> { | |||
71 | | FormatSpecifier::DollarSign | 57 | | FormatSpecifier::DollarSign |
72 | | FormatSpecifier::Dot | 58 | | FormatSpecifier::Dot |
73 | | FormatSpecifier::Asterisk | 59 | | FormatSpecifier::Asterisk |
74 | | FormatSpecifier::QuestionMark => HighlightTag::FormatSpecifier, | 60 | | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier, |
75 | FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral, | 61 | |
76 | FormatSpecifier::Identifier => HighlightTag::Symbol(SymbolKind::Local), | 62 | FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral, |
63 | |||
64 | FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local), | ||
77 | }) | 65 | }) |
78 | } | 66 | } |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs new file mode 100644 index 000000000..34bae49a8 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -0,0 +1,530 @@ | |||
1 | //! Computes color for a single element. | ||
2 | |||
3 | use hir::{AsAssocItem, Semantics, VariantDef}; | ||
4 | use ide_db::{ | ||
5 | defs::{Definition, NameClass, NameRefClass}, | ||
6 | RootDatabase, | ||
7 | }; | ||
8 | use rustc_hash::FxHashMap; | ||
9 | use syntax::{ | ||
10 | ast, AstNode, AstToken, NodeOrToken, SyntaxElement, | ||
11 | SyntaxKind::{self, *}, | ||
12 | SyntaxNode, SyntaxToken, T, | ||
13 | }; | ||
14 | |||
15 | use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag, SymbolKind}; | ||
16 | |||
17 | pub(super) fn element( | ||
18 | sema: &Semantics<RootDatabase>, | ||
19 | bindings_shadow_count: &mut FxHashMap<hir::Name, u32>, | ||
20 | syntactic_name_ref_highlighting: bool, | ||
21 | element: SyntaxElement, | ||
22 | ) -> Option<(Highlight, Option<u64>)> { | ||
23 | let db = sema.db; | ||
24 | let mut binding_hash = None; | ||
25 | let highlight: Highlight = match element.kind() { | ||
26 | FN => { | ||
27 | bindings_shadow_count.clear(); | ||
28 | return None; | ||
29 | } | ||
30 | |||
31 | // Highlight definitions depending on the "type" of the definition. | ||
32 | NAME => { | ||
33 | let name = element.into_node().and_then(ast::Name::cast).unwrap(); | ||
34 | let name_kind = NameClass::classify(sema, &name); | ||
35 | |||
36 | if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind { | ||
37 | if let Some(name) = local.name(db) { | ||
38 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | ||
39 | *shadow_count += 1; | ||
40 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
41 | } | ||
42 | }; | ||
43 | |||
44 | match name_kind { | ||
45 | Some(NameClass::ExternCrate(_)) => HlTag::Symbol(SymbolKind::Module).into(), | ||
46 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | ||
47 | Some(NameClass::ConstReference(def)) => highlight_def(db, def), | ||
48 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | ||
49 | let mut h = HlTag::Symbol(SymbolKind::Field).into(); | ||
50 | if let Definition::Field(field) = field_ref { | ||
51 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
52 | h |= HlMod::Unsafe; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | h | ||
57 | } | ||
58 | None => highlight_name_by_syntax(name) | HlMod::Definition, | ||
59 | } | ||
60 | } | ||
61 | |||
62 | // Highlight references like the definitions they resolve to | ||
63 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => { | ||
64 | // even though we track whether we are in an attribute or not we still need this special case | ||
65 | // as otherwise we would emit unresolved references for name refs inside attributes | ||
66 | Highlight::from(HlTag::Symbol(SymbolKind::Function)) | ||
67 | } | ||
68 | NAME_REF => { | ||
69 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | ||
70 | highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { | ||
71 | match NameRefClass::classify(sema, &name_ref) { | ||
72 | Some(name_kind) => match name_kind { | ||
73 | NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(), | ||
74 | NameRefClass::Definition(def) => { | ||
75 | if let Definition::Local(local) = &def { | ||
76 | if let Some(name) = local.name(db) { | ||
77 | let shadow_count = | ||
78 | bindings_shadow_count.entry(name.clone()).or_default(); | ||
79 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | ||
80 | } | ||
81 | }; | ||
82 | |||
83 | let mut h = highlight_def(db, def); | ||
84 | |||
85 | if let Definition::Local(local) = &def { | ||
86 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | ||
87 | h |= HlMod::Consuming; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | if let Some(parent) = name_ref.syntax().parent() { | ||
92 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | ||
93 | if let Definition::Field(field) = def { | ||
94 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
95 | h |= HlMod::Unsafe; | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | h | ||
102 | } | ||
103 | NameRefClass::FieldShorthand { .. } => { | ||
104 | HlTag::Symbol(SymbolKind::Field).into() | ||
105 | } | ||
106 | }, | ||
107 | None if syntactic_name_ref_highlighting => { | ||
108 | highlight_name_ref_by_syntax(name_ref, sema) | ||
109 | } | ||
110 | None => HlTag::UnresolvedReference.into(), | ||
111 | } | ||
112 | }) | ||
113 | } | ||
114 | |||
115 | // Simple token-based highlighting | ||
116 | COMMENT => { | ||
117 | let comment = element.into_token().and_then(ast::Comment::cast)?; | ||
118 | let h = HlTag::Comment; | ||
119 | match comment.kind().doc { | ||
120 | Some(_) => h | HlMod::Documentation, | ||
121 | None => h.into(), | ||
122 | } | ||
123 | } | ||
124 | STRING | BYTE_STRING => HlTag::StringLiteral.into(), | ||
125 | ATTR => HlTag::Attribute.into(), | ||
126 | INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), | ||
127 | BYTE => HlTag::ByteLiteral.into(), | ||
128 | CHAR => HlTag::CharLiteral.into(), | ||
129 | QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow, | ||
130 | LIFETIME => { | ||
131 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); | ||
132 | |||
133 | match NameClass::classify_lifetime(sema, &lifetime) { | ||
134 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | ||
135 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { | ||
136 | Some(NameRefClass::Definition(def)) => highlight_def(db, def), | ||
137 | _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)), | ||
138 | }, | ||
139 | _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | HlMod::Definition, | ||
140 | } | ||
141 | } | ||
142 | p if p.is_punct() => match p { | ||
143 | T![&] => { | ||
144 | let h = HlTag::Operator.into(); | ||
145 | let is_unsafe = element | ||
146 | .parent() | ||
147 | .and_then(ast::RefExpr::cast) | ||
148 | .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)) | ||
149 | .unwrap_or(false); | ||
150 | if is_unsafe { | ||
151 | h | HlMod::Unsafe | ||
152 | } else { | ||
153 | h | ||
154 | } | ||
155 | } | ||
156 | T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(), | ||
157 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | ||
158 | HlTag::Symbol(SymbolKind::Macro).into() | ||
159 | } | ||
160 | T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { | ||
161 | HlTag::BuiltinType.into() | ||
162 | } | ||
163 | T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { | ||
164 | HlTag::Keyword.into() | ||
165 | } | ||
166 | T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
167 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
168 | |||
169 | let expr = prefix_expr.expr()?; | ||
170 | let ty = sema.type_of_expr(&expr)?; | ||
171 | if ty.is_raw_ptr() { | ||
172 | HlTag::Operator | HlMod::Unsafe | ||
173 | } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { | ||
174 | HlTag::Operator.into() | ||
175 | } else { | ||
176 | HlTag::Punctuation(HlPunct::Other).into() | ||
177 | } | ||
178 | } | ||
179 | T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
180 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
181 | |||
182 | let expr = prefix_expr.expr()?; | ||
183 | match expr { | ||
184 | ast::Expr::Literal(_) => HlTag::NumericLiteral, | ||
185 | _ => HlTag::Operator, | ||
186 | } | ||
187 | .into() | ||
188 | } | ||
189 | _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { | ||
190 | HlTag::Operator.into() | ||
191 | } | ||
192 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(), | ||
193 | _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { | ||
194 | HlTag::Operator.into() | ||
195 | } | ||
196 | _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(), | ||
197 | _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(), | ||
198 | _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(), | ||
199 | kind => HlTag::Punctuation(match kind { | ||
200 | T!['['] | T![']'] => HlPunct::Bracket, | ||
201 | T!['{'] | T!['}'] => HlPunct::Brace, | ||
202 | T!['('] | T![')'] => HlPunct::Parenthesis, | ||
203 | T![<] | T![>] => HlPunct::Angle, | ||
204 | T![,] => HlPunct::Comma, | ||
205 | T![:] => HlPunct::Colon, | ||
206 | T![;] => HlPunct::Semi, | ||
207 | T![.] => HlPunct::Dot, | ||
208 | _ => HlPunct::Other, | ||
209 | }) | ||
210 | .into(), | ||
211 | }, | ||
212 | |||
213 | k if k.is_keyword() => { | ||
214 | let h = Highlight::new(HlTag::Keyword); | ||
215 | match k { | ||
216 | T![break] | ||
217 | | T![continue] | ||
218 | | T![else] | ||
219 | | T![if] | ||
220 | | T![loop] | ||
221 | | T![match] | ||
222 | | T![return] | ||
223 | | T![while] | ||
224 | | T![in] => h | HlMod::ControlFlow, | ||
225 | T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow, | ||
226 | T![unsafe] => h | HlMod::Unsafe, | ||
227 | T![true] | T![false] => HlTag::BoolLiteral.into(), | ||
228 | T![self] => { | ||
229 | let self_param_is_mut = element | ||
230 | .parent() | ||
231 | .and_then(ast::SelfParam::cast) | ||
232 | .and_then(|p| p.mut_token()) | ||
233 | .is_some(); | ||
234 | let self_path = &element | ||
235 | .parent() | ||
236 | .as_ref() | ||
237 | .and_then(SyntaxNode::parent) | ||
238 | .and_then(ast::Path::cast) | ||
239 | .and_then(|p| sema.resolve_path(&p)); | ||
240 | let mut h = HlTag::Symbol(SymbolKind::SelfParam).into(); | ||
241 | if self_param_is_mut | ||
242 | || matches!(self_path, | ||
243 | Some(hir::PathResolution::Local(local)) | ||
244 | if local.is_self(db) | ||
245 | && (local.is_mut(db) || local.ty(db).is_mutable_reference()) | ||
246 | ) | ||
247 | { | ||
248 | h |= HlMod::Mutable | ||
249 | } | ||
250 | |||
251 | if let Some(hir::PathResolution::Local(local)) = self_path { | ||
252 | if is_consumed_lvalue(element, &local, db) { | ||
253 | h |= HlMod::Consuming; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | h | ||
258 | } | ||
259 | T![ref] => element | ||
260 | .parent() | ||
261 | .and_then(ast::IdentPat::cast) | ||
262 | .and_then(|ident_pat| { | ||
263 | if sema.is_unsafe_ident_pat(&ident_pat) { | ||
264 | Some(HlMod::Unsafe) | ||
265 | } else { | ||
266 | None | ||
267 | } | ||
268 | }) | ||
269 | .map(|modifier| h | modifier) | ||
270 | .unwrap_or(h), | ||
271 | _ => h, | ||
272 | } | ||
273 | } | ||
274 | |||
275 | _ => return None, | ||
276 | }; | ||
277 | |||
278 | return Some((highlight, binding_hash)); | ||
279 | |||
280 | fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 { | ||
281 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { | ||
282 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | ||
283 | |||
284 | let mut hasher = DefaultHasher::new(); | ||
285 | x.hash(&mut hasher); | ||
286 | hasher.finish() | ||
287 | } | ||
288 | |||
289 | hash((name, shadow_count)) | ||
290 | } | ||
291 | } | ||
292 | |||
293 | fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | ||
294 | match def { | ||
295 | Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro), | ||
296 | Definition::Field(_) => HlTag::Symbol(SymbolKind::Field), | ||
297 | Definition::ModuleDef(def) => match def { | ||
298 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), | ||
299 | hir::ModuleDef::Function(func) => { | ||
300 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); | ||
301 | if func.as_assoc_item(db).is_some() { | ||
302 | h |= HlMod::Associated; | ||
303 | if func.self_param(db).is_none() { | ||
304 | h |= HlMod::Static | ||
305 | } | ||
306 | } | ||
307 | if func.is_unsafe(db) { | ||
308 | h |= HlMod::Unsafe; | ||
309 | } | ||
310 | return h; | ||
311 | } | ||
312 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct), | ||
313 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum), | ||
314 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union), | ||
315 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), | ||
316 | hir::ModuleDef::Const(konst) => { | ||
317 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); | ||
318 | if konst.as_assoc_item(db).is_some() { | ||
319 | h |= HlMod::Associated | ||
320 | } | ||
321 | return h; | ||
322 | } | ||
323 | hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), | ||
324 | hir::ModuleDef::TypeAlias(type_) => { | ||
325 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); | ||
326 | if type_.as_assoc_item(db).is_some() { | ||
327 | h |= HlMod::Associated | ||
328 | } | ||
329 | return h; | ||
330 | } | ||
331 | hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType, | ||
332 | hir::ModuleDef::Static(s) => { | ||
333 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); | ||
334 | if s.is_mut(db) { | ||
335 | h |= HlMod::Mutable; | ||
336 | h |= HlMod::Unsafe; | ||
337 | } | ||
338 | return h; | ||
339 | } | ||
340 | }, | ||
341 | Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl), | ||
342 | Definition::GenericParam(it) => match it { | ||
343 | hir::GenericParam::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam), | ||
344 | hir::GenericParam::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam), | ||
345 | hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam), | ||
346 | }, | ||
347 | Definition::Local(local) => { | ||
348 | let tag = if local.is_param(db) { | ||
349 | HlTag::Symbol(SymbolKind::ValueParam) | ||
350 | } else { | ||
351 | HlTag::Symbol(SymbolKind::Local) | ||
352 | }; | ||
353 | let mut h = Highlight::new(tag); | ||
354 | if local.is_mut(db) || local.ty(db).is_mutable_reference() { | ||
355 | h |= HlMod::Mutable; | ||
356 | } | ||
357 | if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) { | ||
358 | h |= HlMod::Callable; | ||
359 | } | ||
360 | return h; | ||
361 | } | ||
362 | Definition::Label(_) => HlTag::Symbol(SymbolKind::Label), | ||
363 | } | ||
364 | .into() | ||
365 | } | ||
366 | |||
367 | fn highlight_func_by_name_ref( | ||
368 | sema: &Semantics<RootDatabase>, | ||
369 | name_ref: &ast::NameRef, | ||
370 | ) -> Option<Highlight> { | ||
371 | let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; | ||
372 | highlight_method_call(sema, &mc) | ||
373 | } | ||
374 | |||
375 | fn highlight_method_call( | ||
376 | sema: &Semantics<RootDatabase>, | ||
377 | method_call: &ast::MethodCallExpr, | ||
378 | ) -> Option<Highlight> { | ||
379 | let func = sema.resolve_method_call(&method_call)?; | ||
380 | let mut h = HlTag::Symbol(SymbolKind::Function).into(); | ||
381 | h |= HlMod::Associated; | ||
382 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | ||
383 | h |= HlMod::Unsafe; | ||
384 | } | ||
385 | if let Some(self_param) = func.self_param(sema.db) { | ||
386 | match self_param.access(sema.db) { | ||
387 | hir::Access::Shared => (), | ||
388 | hir::Access::Exclusive => h |= HlMod::Mutable, | ||
389 | hir::Access::Owned => { | ||
390 | if let Some(receiver_ty) = | ||
391 | method_call.receiver().and_then(|it| sema.type_of_expr(&it)) | ||
392 | { | ||
393 | if !receiver_ty.is_copy(sema.db) { | ||
394 | h |= HlMod::Consuming | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | Some(h) | ||
401 | } | ||
402 | |||
403 | fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | ||
404 | let default = HlTag::UnresolvedReference; | ||
405 | |||
406 | let parent = match name.syntax().parent() { | ||
407 | Some(it) => it, | ||
408 | _ => return default.into(), | ||
409 | }; | ||
410 | |||
411 | let tag = match parent.kind() { | ||
412 | STRUCT => HlTag::Symbol(SymbolKind::Struct), | ||
413 | ENUM => HlTag::Symbol(SymbolKind::Enum), | ||
414 | VARIANT => HlTag::Symbol(SymbolKind::Variant), | ||
415 | UNION => HlTag::Symbol(SymbolKind::Union), | ||
416 | TRAIT => HlTag::Symbol(SymbolKind::Trait), | ||
417 | TYPE_ALIAS => HlTag::Symbol(SymbolKind::TypeAlias), | ||
418 | TYPE_PARAM => HlTag::Symbol(SymbolKind::TypeParam), | ||
419 | RECORD_FIELD => HlTag::Symbol(SymbolKind::Field), | ||
420 | MODULE => HlTag::Symbol(SymbolKind::Module), | ||
421 | FN => HlTag::Symbol(SymbolKind::Function), | ||
422 | CONST => HlTag::Symbol(SymbolKind::Const), | ||
423 | STATIC => HlTag::Symbol(SymbolKind::Static), | ||
424 | IDENT_PAT => HlTag::Symbol(SymbolKind::Local), | ||
425 | _ => default, | ||
426 | }; | ||
427 | |||
428 | tag.into() | ||
429 | } | ||
430 | |||
431 | fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight { | ||
432 | let default = HlTag::UnresolvedReference; | ||
433 | |||
434 | let parent = match name.syntax().parent() { | ||
435 | Some(it) => it, | ||
436 | _ => return default.into(), | ||
437 | }; | ||
438 | |||
439 | match parent.kind() { | ||
440 | METHOD_CALL_EXPR => { | ||
441 | return ast::MethodCallExpr::cast(parent) | ||
442 | .and_then(|it| highlight_method_call(sema, &it)) | ||
443 | .unwrap_or_else(|| HlTag::Symbol(SymbolKind::Function).into()); | ||
444 | } | ||
445 | FIELD_EXPR => { | ||
446 | let h = HlTag::Symbol(SymbolKind::Field); | ||
447 | let is_union = ast::FieldExpr::cast(parent) | ||
448 | .and_then(|field_expr| { | ||
449 | let field = sema.resolve_field(&field_expr)?; | ||
450 | Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { | ||
451 | true | ||
452 | } else { | ||
453 | false | ||
454 | }) | ||
455 | }) | ||
456 | .unwrap_or(false); | ||
457 | if is_union { | ||
458 | h | HlMod::Unsafe | ||
459 | } else { | ||
460 | h.into() | ||
461 | } | ||
462 | } | ||
463 | PATH_SEGMENT => { | ||
464 | let path = match parent.parent().and_then(ast::Path::cast) { | ||
465 | Some(it) => it, | ||
466 | _ => return default.into(), | ||
467 | }; | ||
468 | let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) { | ||
469 | Some(it) => it, | ||
470 | _ => { | ||
471 | // within path, decide whether it is module or adt by checking for uppercase name | ||
472 | return if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
473 | HlTag::Symbol(SymbolKind::Struct) | ||
474 | } else { | ||
475 | HlTag::Symbol(SymbolKind::Module) | ||
476 | } | ||
477 | .into(); | ||
478 | } | ||
479 | }; | ||
480 | let parent = match expr.syntax().parent() { | ||
481 | Some(it) => it, | ||
482 | None => return default.into(), | ||
483 | }; | ||
484 | |||
485 | match parent.kind() { | ||
486 | CALL_EXPR => HlTag::Symbol(SymbolKind::Function).into(), | ||
487 | _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { | ||
488 | HlTag::Symbol(SymbolKind::Struct) | ||
489 | } else { | ||
490 | HlTag::Symbol(SymbolKind::Const) | ||
491 | } | ||
492 | .into(), | ||
493 | } | ||
494 | } | ||
495 | _ => default.into(), | ||
496 | } | ||
497 | } | ||
498 | |||
499 | fn is_consumed_lvalue( | ||
500 | node: NodeOrToken<SyntaxNode, SyntaxToken>, | ||
501 | local: &hir::Local, | ||
502 | db: &RootDatabase, | ||
503 | ) -> bool { | ||
504 | // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. | ||
505 | parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db) | ||
506 | } | ||
507 | |||
508 | /// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. | ||
509 | fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool { | ||
510 | while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { | ||
511 | if parent.kind() != *kind { | ||
512 | return false; | ||
513 | } | ||
514 | |||
515 | // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value | ||
516 | // in the same pattern is unstable: rust-lang/rust#68354. | ||
517 | node = node.parent().unwrap().into(); | ||
518 | kinds = rest; | ||
519 | } | ||
520 | |||
521 | // Only true if we matched all expected kinds | ||
522 | kinds.len() == 0 | ||
523 | } | ||
524 | |||
525 | fn is_child_of_impl(element: &SyntaxElement) -> bool { | ||
526 | match element.parent() { | ||
527 | Some(e) => e.kind() == IMPL, | ||
528 | _ => false, | ||
529 | } | ||
530 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/highlights.rs b/crates/ide/src/syntax_highlighting/highlights.rs new file mode 100644 index 000000000..882a685a5 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/highlights.rs | |||
@@ -0,0 +1,92 @@ | |||
1 | //! Collects a tree of highlighted ranges and flattens it. | ||
2 | use std::iter; | ||
3 | |||
4 | use stdx::equal_range_by; | ||
5 | use syntax::TextRange; | ||
6 | |||
7 | use crate::{HlRange, HlTag}; | ||
8 | |||
9 | pub(super) struct Highlights { | ||
10 | root: Node, | ||
11 | } | ||
12 | |||
13 | struct Node { | ||
14 | hl_range: HlRange, | ||
15 | nested: Vec<Node>, | ||
16 | } | ||
17 | |||
18 | impl Highlights { | ||
19 | pub(super) fn new(range: TextRange) -> Highlights { | ||
20 | Highlights { | ||
21 | root: Node::new(HlRange { range, highlight: HlTag::None.into(), binding_hash: None }), | ||
22 | } | ||
23 | } | ||
24 | |||
25 | pub(super) fn add(&mut self, hl_range: HlRange) { | ||
26 | self.root.add(hl_range); | ||
27 | } | ||
28 | |||
29 | pub(super) fn to_vec(self) -> Vec<HlRange> { | ||
30 | let mut res = Vec::new(); | ||
31 | self.root.flatten(&mut res); | ||
32 | res | ||
33 | } | ||
34 | } | ||
35 | |||
36 | impl Node { | ||
37 | fn new(hl_range: HlRange) -> Node { | ||
38 | Node { hl_range, nested: Vec::new() } | ||
39 | } | ||
40 | |||
41 | fn add(&mut self, hl_range: HlRange) { | ||
42 | assert!(self.hl_range.range.contains_range(hl_range.range)); | ||
43 | |||
44 | // Fast path | ||
45 | if let Some(last) = self.nested.last_mut() { | ||
46 | if last.hl_range.range.contains_range(hl_range.range) { | ||
47 | return last.add(hl_range); | ||
48 | } | ||
49 | if last.hl_range.range.end() <= hl_range.range.start() { | ||
50 | return self.nested.push(Node::new(hl_range)); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | let overlapping = | ||
55 | equal_range_by(&self.nested, |n| TextRange::ordering(n.hl_range.range, hl_range.range)); | ||
56 | |||
57 | if overlapping.len() == 1 | ||
58 | && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range) | ||
59 | { | ||
60 | return self.nested[overlapping.start].add(hl_range); | ||
61 | } | ||
62 | |||
63 | let nested = self | ||
64 | .nested | ||
65 | .splice(overlapping.clone(), iter::once(Node::new(hl_range))) | ||
66 | .collect::<Vec<_>>(); | ||
67 | self.nested[overlapping.start].nested = nested; | ||
68 | } | ||
69 | |||
70 | fn flatten(&self, acc: &mut Vec<HlRange>) { | ||
71 | let mut start = self.hl_range.range.start(); | ||
72 | let mut nested = self.nested.iter(); | ||
73 | loop { | ||
74 | let next = nested.next(); | ||
75 | let end = next.map_or(self.hl_range.range.end(), |it| it.hl_range.range.start()); | ||
76 | if start < end { | ||
77 | acc.push(HlRange { | ||
78 | range: TextRange::new(start, end), | ||
79 | highlight: self.hl_range.highlight, | ||
80 | binding_hash: self.hl_range.binding_hash, | ||
81 | }); | ||
82 | } | ||
83 | start = match next { | ||
84 | Some(child) => { | ||
85 | child.flatten(acc); | ||
86 | child.hl_range.range.end() | ||
87 | } | ||
88 | None => break, | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 99ba3a59d..0ee7bc96e 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use ide_db::base_db::SourceDatabase; | 3 | use ide_db::base_db::SourceDatabase; |
4 | use oorandom::Rand32; | 4 | use oorandom::Rand32; |
5 | use stdx::format_to; | 5 | use stdx::format_to; |
6 | use syntax::{AstNode, TextRange, TextSize}; | 6 | use syntax::AstNode; |
7 | 7 | ||
8 | use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; | 8 | use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; |
9 | 9 | ||
@@ -20,35 +20,27 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo | |||
20 | ) | 20 | ) |
21 | } | 21 | } |
22 | 22 | ||
23 | let ranges = highlight(db, file_id, None, false); | 23 | let hl_ranges = highlight(db, file_id, None, false); |
24 | let text = parse.tree().syntax().to_string(); | 24 | let text = parse.tree().syntax().to_string(); |
25 | let mut prev_pos = TextSize::from(0); | ||
26 | let mut buf = String::new(); | 25 | let mut buf = String::new(); |
27 | buf.push_str(&STYLE); | 26 | buf.push_str(&STYLE); |
28 | buf.push_str("<pre><code>"); | 27 | buf.push_str("<pre><code>"); |
29 | for range in &ranges { | 28 | for r in &hl_ranges { |
30 | if range.range.start() > prev_pos { | 29 | let chunk = html_escape(&text[r.range]); |
31 | let curr = &text[TextRange::new(prev_pos, range.range.start())]; | 30 | if r.highlight.is_empty() { |
32 | let text = html_escape(curr); | 31 | format_to!(buf, "{}", chunk); |
33 | buf.push_str(&text); | 32 | continue; |
34 | } | 33 | } |
35 | let curr = &text[TextRange::new(range.range.start(), range.range.end())]; | ||
36 | 34 | ||
37 | let class = range.highlight.to_string().replace('.', " "); | 35 | let class = r.highlight.to_string().replace('.', " "); |
38 | let color = match (rainbow, range.binding_hash) { | 36 | let color = match (rainbow, r.binding_hash) { |
39 | (true, Some(hash)) => { | 37 | (true, Some(hash)) => { |
40 | format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash)) | 38 | format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash)) |
41 | } | 39 | } |
42 | _ => "".into(), | 40 | _ => "".into(), |
43 | }; | 41 | }; |
44 | format_to!(buf, "<span class=\"{}\"{}>{}</span>", class, color, html_escape(curr)); | 42 | format_to!(buf, "<span class=\"{}\"{}>{}</span>", class, color, chunk); |
45 | |||
46 | prev_pos = range.range.end(); | ||
47 | } | 43 | } |
48 | // Add the remaining (non-highlighted) text | ||
49 | let curr = &text[TextRange::new(prev_pos, TextSize::of(&text))]; | ||
50 | let text = html_escape(curr); | ||
51 | buf.push_str(&text); | ||
52 | buf.push_str("</code></pre>"); | 44 | buf.push_str("</code></pre>"); |
53 | buf | 45 | buf |
54 | } | 46 | } |
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs new file mode 100644 index 000000000..281461493 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -0,0 +1,158 @@ | |||
1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. | ||
2 | |||
3 | use hir::Semantics; | ||
4 | use ide_db::call_info::ActiveParameter; | ||
5 | use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | ||
6 | |||
7 | use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; | ||
8 | |||
9 | use super::{highlights::Highlights, injector::Injector}; | ||
10 | |||
11 | pub(super) fn ra_fixture( | ||
12 | hl: &mut Highlights, | ||
13 | sema: &Semantics<RootDatabase>, | ||
14 | literal: ast::String, | ||
15 | expanded: SyntaxToken, | ||
16 | ) -> Option<()> { | ||
17 | let active_parameter = ActiveParameter::at_token(&sema, expanded)?; | ||
18 | if !active_parameter.name.starts_with("ra_fixture") { | ||
19 | return None; | ||
20 | } | ||
21 | let value = literal.value()?; | ||
22 | |||
23 | if let Some(range) = literal.open_quote_text_range() { | ||
24 | hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) | ||
25 | } | ||
26 | |||
27 | let mut inj = Injector::default(); | ||
28 | |||
29 | let mut text = &*value; | ||
30 | let mut offset: TextSize = 0.into(); | ||
31 | |||
32 | while !text.is_empty() { | ||
33 | let marker = "$0"; | ||
34 | let idx = text.find(marker).unwrap_or(text.len()); | ||
35 | let (chunk, next) = text.split_at(idx); | ||
36 | inj.add(chunk, TextRange::at(offset, TextSize::of(chunk))); | ||
37 | |||
38 | text = next; | ||
39 | offset += TextSize::of(chunk); | ||
40 | |||
41 | if let Some(next) = text.strip_prefix(marker) { | ||
42 | if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) { | ||
43 | hl.add(HlRange { range, highlight: HlTag::Keyword.into(), binding_hash: None }); | ||
44 | } | ||
45 | |||
46 | text = next; | ||
47 | |||
48 | let marker_len = TextSize::of(marker); | ||
49 | offset += marker_len; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); | ||
54 | |||
55 | for mut hl_range in analysis.highlight(tmp_file_id).unwrap() { | ||
56 | for range in inj.map_range_up(hl_range.range) { | ||
57 | if let Some(range) = literal.map_range_up(range) { | ||
58 | hl_range.range = range; | ||
59 | hl.add(hl_range.clone()); | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | if let Some(range) = literal.close_quote_text_range() { | ||
65 | hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) | ||
66 | } | ||
67 | |||
68 | Some(()) | ||
69 | } | ||
70 | |||
71 | const RUSTDOC_FENCE: &'static str = "```"; | ||
72 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ | ||
73 | "", | ||
74 | "rust", | ||
75 | "should_panic", | ||
76 | "ignore", | ||
77 | "no_run", | ||
78 | "compile_fail", | ||
79 | "edition2015", | ||
80 | "edition2018", | ||
81 | "edition2021", | ||
82 | ]; | ||
83 | |||
84 | /// Injection of syntax highlighting of doctests. | ||
85 | pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | ||
86 | let doc_comments = node | ||
87 | .children_with_tokens() | ||
88 | .filter_map(|it| it.into_token().and_then(ast::Comment::cast)) | ||
89 | .filter(|it| it.kind().doc.is_some()); | ||
90 | |||
91 | if !doc_comments.clone().any(|it| it.text().contains(RUSTDOC_FENCE)) { | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | let mut inj = Injector::default(); | ||
96 | inj.add_unmapped("fn doctest() {\n"); | ||
97 | |||
98 | let mut is_codeblock = false; | ||
99 | let mut is_doctest = false; | ||
100 | |||
101 | // Replace the original, line-spanning comment ranges by new, only comment-prefix | ||
102 | // spanning comment ranges. | ||
103 | let mut new_comments = Vec::new(); | ||
104 | for comment in doc_comments { | ||
105 | match comment.text().find(RUSTDOC_FENCE) { | ||
106 | Some(idx) => { | ||
107 | is_codeblock = !is_codeblock; | ||
108 | // Check whether code is rust by inspecting fence guards | ||
109 | let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..]; | ||
110 | let is_rust = | ||
111 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); | ||
112 | is_doctest = is_codeblock && is_rust; | ||
113 | continue; | ||
114 | } | ||
115 | None if !is_doctest => continue, | ||
116 | None => (), | ||
117 | } | ||
118 | |||
119 | let line: &str = comment.text().as_str(); | ||
120 | let range = comment.syntax().text_range(); | ||
121 | |||
122 | let mut pos = TextSize::of(comment.prefix()); | ||
123 | // whitespace after comment is ignored | ||
124 | if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { | ||
125 | pos += TextSize::of(ws); | ||
126 | } | ||
127 | // lines marked with `#` should be ignored in output, we skip the `#` char | ||
128 | if let Some(ws) = line[pos.into()..].chars().next().filter(|&c| c == '#') { | ||
129 | pos += TextSize::of(ws); | ||
130 | } | ||
131 | |||
132 | new_comments.push(TextRange::at(range.start(), pos)); | ||
133 | |||
134 | inj.add(&line[pos.into()..], TextRange::new(range.start() + pos, range.end())); | ||
135 | inj.add_unmapped("\n"); | ||
136 | } | ||
137 | inj.add_unmapped("\n}"); | ||
138 | |||
139 | let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); | ||
140 | |||
141 | for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { | ||
142 | for r in inj.map_range_up(h.range) { | ||
143 | hl.add(HlRange { | ||
144 | range: r, | ||
145 | highlight: h.highlight | HlMod::Injected, | ||
146 | binding_hash: h.binding_hash, | ||
147 | }); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | for range in new_comments { | ||
152 | hl.add(HlRange { | ||
153 | range, | ||
154 | highlight: HlTag::Comment | HlMod::Documentation, | ||
155 | binding_hash: None, | ||
156 | }); | ||
157 | } | ||
158 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs deleted file mode 100644 index 9eb184c74..000000000 --- a/crates/ide/src/syntax_highlighting/injection.rs +++ /dev/null | |||
@@ -1,183 +0,0 @@ | |||
1 | //! Syntax highlighting injections such as highlighting of documentation tests. | ||
2 | |||
3 | use std::{collections::BTreeMap, convert::TryFrom}; | ||
4 | |||
5 | use hir::Semantics; | ||
6 | use ide_db::call_info::ActiveParameter; | ||
7 | use itertools::Itertools; | ||
8 | use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | ||
9 | |||
10 | use crate::{Analysis, Highlight, HighlightModifier, HighlightTag, HighlightedRange, RootDatabase}; | ||
11 | |||
12 | use super::HighlightedRangeStack; | ||
13 | |||
14 | pub(super) fn highlight_injection( | ||
15 | acc: &mut HighlightedRangeStack, | ||
16 | sema: &Semantics<RootDatabase>, | ||
17 | literal: ast::String, | ||
18 | expanded: SyntaxToken, | ||
19 | ) -> Option<()> { | ||
20 | let active_parameter = ActiveParameter::at_token(&sema, expanded)?; | ||
21 | if !active_parameter.name.starts_with("ra_fixture") { | ||
22 | return None; | ||
23 | } | ||
24 | let value = literal.value()?; | ||
25 | let (analysis, tmp_file_id) = Analysis::from_single_file(value.into_owned()); | ||
26 | |||
27 | if let Some(range) = literal.open_quote_text_range() { | ||
28 | acc.add(HighlightedRange { | ||
29 | range, | ||
30 | highlight: HighlightTag::StringLiteral.into(), | ||
31 | binding_hash: None, | ||
32 | }) | ||
33 | } | ||
34 | |||
35 | for mut h in analysis.highlight(tmp_file_id).unwrap() { | ||
36 | if let Some(r) = literal.map_range_up(h.range) { | ||
37 | h.range = r; | ||
38 | acc.add(h) | ||
39 | } | ||
40 | } | ||
41 | |||
42 | if let Some(range) = literal.close_quote_text_range() { | ||
43 | acc.add(HighlightedRange { | ||
44 | range, | ||
45 | highlight: HighlightTag::StringLiteral.into(), | ||
46 | binding_hash: None, | ||
47 | }) | ||
48 | } | ||
49 | |||
50 | Some(()) | ||
51 | } | ||
52 | |||
53 | /// Mapping from extracted documentation code to original code | ||
54 | type RangesMap = BTreeMap<TextSize, TextSize>; | ||
55 | |||
56 | const RUSTDOC_FENCE: &'static str = "```"; | ||
57 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = | ||
58 | &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; | ||
59 | |||
60 | /// Extracts Rust code from documentation comments as well as a mapping from | ||
61 | /// the extracted source code back to the original source ranges. | ||
62 | /// Lastly, a vector of new comment highlight ranges (spanning only the | ||
63 | /// comment prefix) is returned which is used in the syntax highlighting | ||
64 | /// injection to replace the previous (line-spanning) comment ranges. | ||
65 | pub(super) fn extract_doc_comments( | ||
66 | node: &SyntaxNode, | ||
67 | ) -> Option<(String, RangesMap, Vec<HighlightedRange>)> { | ||
68 | // wrap the doctest into function body to get correct syntax highlighting | ||
69 | let prefix = "fn doctest() {\n"; | ||
70 | let suffix = "}\n"; | ||
71 | // Mapping from extracted documentation code to original code | ||
72 | let mut range_mapping: RangesMap = BTreeMap::new(); | ||
73 | let mut line_start = TextSize::try_from(prefix.len()).unwrap(); | ||
74 | let mut is_codeblock = false; | ||
75 | let mut is_doctest = false; | ||
76 | // Replace the original, line-spanning comment ranges by new, only comment-prefix | ||
77 | // spanning comment ranges. | ||
78 | let mut new_comments = Vec::new(); | ||
79 | let doctest = node | ||
80 | .children_with_tokens() | ||
81 | .filter_map(|el| el.into_token().and_then(ast::Comment::cast)) | ||
82 | .filter(|comment| comment.kind().doc.is_some()) | ||
83 | .filter(|comment| { | ||
84 | if let Some(idx) = comment.text().find(RUSTDOC_FENCE) { | ||
85 | is_codeblock = !is_codeblock; | ||
86 | // Check whether code is rust by inspecting fence guards | ||
87 | let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..]; | ||
88 | let is_rust = | ||
89 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); | ||
90 | is_doctest = is_codeblock && is_rust; | ||
91 | false | ||
92 | } else { | ||
93 | is_doctest | ||
94 | } | ||
95 | }) | ||
96 | .map(|comment| { | ||
97 | let prefix_len = comment.prefix().len(); | ||
98 | let line: &str = comment.text().as_str(); | ||
99 | let range = comment.syntax().text_range(); | ||
100 | |||
101 | // whitespace after comment is ignored | ||
102 | let pos = if let Some(ws) = line.chars().nth(prefix_len).filter(|c| c.is_whitespace()) { | ||
103 | prefix_len + ws.len_utf8() | ||
104 | } else { | ||
105 | prefix_len | ||
106 | }; | ||
107 | |||
108 | // lines marked with `#` should be ignored in output, we skip the `#` char | ||
109 | let pos = if let Some(ws) = line.chars().nth(pos).filter(|&c| c == '#') { | ||
110 | pos + ws.len_utf8() | ||
111 | } else { | ||
112 | pos | ||
113 | }; | ||
114 | |||
115 | range_mapping.insert(line_start, range.start() + TextSize::try_from(pos).unwrap()); | ||
116 | new_comments.push(HighlightedRange { | ||
117 | range: TextRange::new( | ||
118 | range.start(), | ||
119 | range.start() + TextSize::try_from(pos).unwrap(), | ||
120 | ), | ||
121 | highlight: HighlightTag::Comment | HighlightModifier::Documentation, | ||
122 | binding_hash: None, | ||
123 | }); | ||
124 | line_start += range.len() - TextSize::try_from(pos).unwrap(); | ||
125 | line_start += TextSize::try_from('\n'.len_utf8()).unwrap(); | ||
126 | |||
127 | line[pos..].to_owned() | ||
128 | }) | ||
129 | .join("\n"); | ||
130 | |||
131 | if doctest.is_empty() { | ||
132 | return None; | ||
133 | } | ||
134 | |||
135 | let doctest = format!("{}{}{}", prefix, doctest, suffix); | ||
136 | Some((doctest, range_mapping, new_comments)) | ||
137 | } | ||
138 | |||
139 | /// Injection of syntax highlighting of doctests. | ||
140 | pub(super) fn highlight_doc_comment( | ||
141 | text: String, | ||
142 | range_mapping: RangesMap, | ||
143 | new_comments: Vec<HighlightedRange>, | ||
144 | stack: &mut HighlightedRangeStack, | ||
145 | ) { | ||
146 | let (analysis, tmp_file_id) = Analysis::from_single_file(text); | ||
147 | |||
148 | stack.push(); | ||
149 | for mut h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { | ||
150 | // Determine start offset and end offset in case of multi-line ranges | ||
151 | let mut start_offset = None; | ||
152 | let mut end_offset = None; | ||
153 | for (line_start, orig_line_start) in range_mapping.range(..h.range.end()).rev() { | ||
154 | // It's possible for orig_line_start - line_start to be negative. Add h.range.start() | ||
155 | // here and remove it from the end range after the loop below so that the values are | ||
156 | // always non-negative. | ||
157 | let offset = h.range.start() + orig_line_start - line_start; | ||
158 | if line_start <= &h.range.start() { | ||
159 | start_offset.get_or_insert(offset); | ||
160 | break; | ||
161 | } else { | ||
162 | end_offset.get_or_insert(offset); | ||
163 | } | ||
164 | } | ||
165 | if let Some(start_offset) = start_offset { | ||
166 | h.range = TextRange::new( | ||
167 | start_offset, | ||
168 | h.range.end() + end_offset.unwrap_or(start_offset) - h.range.start(), | ||
169 | ); | ||
170 | |||
171 | h.highlight |= HighlightModifier::Injected; | ||
172 | stack.add(h); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | // Inject the comment prefix highlight ranges | ||
177 | stack.push(); | ||
178 | for comment in new_comments { | ||
179 | stack.add(comment); | ||
180 | } | ||
181 | stack.pop_and_inject(None); | ||
182 | stack.pop_and_inject(Some(Highlight::from(HighlightTag::Dummy) | HighlightModifier::Injected)); | ||
183 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs new file mode 100644 index 000000000..24ff473ec --- /dev/null +++ b/crates/ide/src/syntax_highlighting/injector.rs | |||
@@ -0,0 +1,78 @@ | |||
1 | //! Extracts a subsequence of a text document, remembering the mapping of ranges | ||
2 | //! between original and extracted texts. | ||
3 | use std::ops::{self, Sub}; | ||
4 | |||
5 | use stdx::equal_range_by; | ||
6 | use syntax::{TextRange, TextSize}; | ||
7 | |||
8 | #[derive(Default)] | ||
9 | pub(super) struct Injector { | ||
10 | buf: String, | ||
11 | ranges: Vec<(TextRange, Option<Delta<TextSize>>)>, | ||
12 | } | ||
13 | |||
14 | impl Injector { | ||
15 | pub(super) fn add(&mut self, text: &str, source_range: TextRange) { | ||
16 | let len = TextSize::of(text); | ||
17 | assert_eq!(len, source_range.len()); | ||
18 | self.add_impl(text, Some(source_range.start())); | ||
19 | } | ||
20 | pub(super) fn add_unmapped(&mut self, text: &str) { | ||
21 | self.add_impl(text, None); | ||
22 | } | ||
23 | fn add_impl(&mut self, text: &str, source: Option<TextSize>) { | ||
24 | let len = TextSize::of(text); | ||
25 | let target_range = TextRange::at(TextSize::of(&self.buf), len); | ||
26 | self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it)))); | ||
27 | self.buf.push_str(text); | ||
28 | } | ||
29 | |||
30 | pub(super) fn text(&self) -> &str { | ||
31 | &self.buf | ||
32 | } | ||
33 | pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | ||
34 | equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| { | ||
35 | let (target_range, delta) = self.ranges[i]; | ||
36 | let intersection = target_range.intersect(range).unwrap(); | ||
37 | Some(intersection + delta?) | ||
38 | }) | ||
39 | } | ||
40 | } | ||
41 | |||
42 | #[derive(Clone, Copy)] | ||
43 | enum Delta<T> { | ||
44 | Add(T), | ||
45 | Sub(T), | ||
46 | } | ||
47 | |||
48 | impl<T> Delta<T> { | ||
49 | fn new(from: T, to: T) -> Delta<T> | ||
50 | where | ||
51 | T: Ord + Sub<Output = T>, | ||
52 | { | ||
53 | if to >= from { | ||
54 | Delta::Add(to - from) | ||
55 | } else { | ||
56 | Delta::Sub(from - to) | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | impl ops::Add<Delta<TextSize>> for TextSize { | ||
62 | type Output = TextSize; | ||
63 | |||
64 | fn add(self, rhs: Delta<TextSize>) -> TextSize { | ||
65 | match rhs { | ||
66 | Delta::Add(it) => self + it, | ||
67 | Delta::Sub(it) => self - it, | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | impl ops::Add<Delta<TextSize>> for TextRange { | ||
73 | type Output = TextRange; | ||
74 | |||
75 | fn add(self, rhs: Delta<TextSize>) -> TextRange { | ||
76 | TextRange::at(self.start() + rhs, self.len()) | ||
77 | } | ||
78 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_rules.rs index 4462af47e..44620e912 100644 --- a/crates/ide/src/syntax_highlighting/macro_rules.rs +++ b/crates/ide/src/syntax_highlighting/macro_rules.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Syntax highlighting for macro_rules!. | 1 | //! Syntax highlighting for macro_rules!. |
2 | use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; | 2 | use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; |
3 | 3 | ||
4 | use crate::{HighlightTag, HighlightedRange}; | 4 | use crate::{HlRange, HlTag}; |
5 | 5 | ||
6 | #[derive(Default)] | 6 | #[derive(Default)] |
7 | pub(super) struct MacroRulesHighlighter { | 7 | pub(super) struct MacroRulesHighlighter { |
@@ -19,13 +19,13 @@ impl MacroRulesHighlighter { | |||
19 | } | 19 | } |
20 | } | 20 | } |
21 | 21 | ||
22 | pub(super) fn highlight(&self, element: SyntaxElement) -> Option<HighlightedRange> { | 22 | pub(super) fn highlight(&self, element: SyntaxElement) -> Option<HlRange> { |
23 | if let Some(state) = self.state.as_ref() { | 23 | if let Some(state) = self.state.as_ref() { |
24 | if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { | 24 | if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { |
25 | if let Some(range) = is_metavariable(element) { | 25 | if let Some(range) = is_metavariable(element) { |
26 | return Some(HighlightedRange { | 26 | return Some(HlRange { |
27 | range, | 27 | range, |
28 | highlight: HighlightTag::UnresolvedReference.into(), | 28 | highlight: HlTag::UnresolvedReference.into(), |
29 | binding_hash: None, | 29 | binding_hash: None, |
30 | }); | 30 | }); |
31 | } | 31 | } |
@@ -119,7 +119,7 @@ fn is_metavariable(element: SyntaxElement) -> Option<TextRange> { | |||
119 | let tok = element.as_token()?; | 119 | let tok = element.as_token()?; |
120 | match tok.kind() { | 120 | match tok.kind() { |
121 | kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { | 121 | kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { |
122 | if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == SyntaxKind::DOLLAR) { | 122 | if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == T![$]) { |
123 | return Some(tok.text_range()); | 123 | return Some(tok.text_range()); |
124 | } | 124 | } |
125 | } | 125 | } |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 2a6cc0cab..8dd05ac52 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -7,15 +7,15 @@ use crate::SymbolKind; | |||
7 | 7 | ||
8 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 8 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
9 | pub struct Highlight { | 9 | pub struct Highlight { |
10 | pub tag: HighlightTag, | 10 | pub tag: HlTag, |
11 | pub modifiers: HighlightModifiers, | 11 | pub mods: HlMods, |
12 | } | 12 | } |
13 | 13 | ||
14 | #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 14 | #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
15 | pub struct HighlightModifiers(u32); | 15 | pub struct HlMods(u32); |
16 | 16 | ||
17 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 17 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
18 | pub enum HighlightTag { | 18 | pub enum HlTag { |
19 | Symbol(SymbolKind), | 19 | Symbol(SymbolKind), |
20 | 20 | ||
21 | BoolLiteral, | 21 | BoolLiteral, |
@@ -29,17 +29,17 @@ pub enum HighlightTag { | |||
29 | EscapeSequence, | 29 | EscapeSequence, |
30 | FormatSpecifier, | 30 | FormatSpecifier, |
31 | Keyword, | 31 | Keyword, |
32 | Punctuation, | 32 | Punctuation(HlPunct), |
33 | Operator, | 33 | Operator, |
34 | UnresolvedReference, | 34 | UnresolvedReference, |
35 | 35 | ||
36 | // For things which don't have proper Tag, but want to use modifiers. | 36 | // For things which don't have a specific highlight. |
37 | Dummy, | 37 | None, |
38 | } | 38 | } |
39 | 39 | ||
40 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 40 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
41 | #[repr(u8)] | 41 | #[repr(u8)] |
42 | pub enum HighlightModifier { | 42 | pub enum HlMod { |
43 | /// Used to differentiate individual elements within attributes. | 43 | /// Used to differentiate individual elements within attributes. |
44 | Attribute = 0, | 44 | Attribute = 0, |
45 | /// Used with keywords like `if` and `break`. | 45 | /// Used with keywords like `if` and `break`. |
@@ -61,10 +61,32 @@ pub enum HighlightModifier { | |||
61 | Unsafe, | 61 | Unsafe, |
62 | } | 62 | } |
63 | 63 | ||
64 | impl HighlightTag { | 64 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
65 | pub enum HlPunct { | ||
66 | /// [] | ||
67 | Bracket, | ||
68 | /// {} | ||
69 | Brace, | ||
70 | /// () | ||
71 | Parenthesis, | ||
72 | /// <> | ||
73 | Angle, | ||
74 | /// , | ||
75 | Comma, | ||
76 | /// . | ||
77 | Dot, | ||
78 | /// : | ||
79 | Colon, | ||
80 | /// ; | ||
81 | Semi, | ||
82 | /// | ||
83 | Other, | ||
84 | } | ||
85 | |||
86 | impl HlTag { | ||
65 | fn as_str(self) -> &'static str { | 87 | fn as_str(self) -> &'static str { |
66 | match self { | 88 | match self { |
67 | HighlightTag::Symbol(symbol) => match symbol { | 89 | HlTag::Symbol(symbol) => match symbol { |
68 | SymbolKind::Const => "constant", | 90 | SymbolKind::Const => "constant", |
69 | SymbolKind::Static => "static", | 91 | SymbolKind::Static => "static", |
70 | SymbolKind::Enum => "enum", | 92 | SymbolKind::Enum => "enum", |
@@ -77,6 +99,7 @@ impl HighlightTag { | |||
77 | SymbolKind::Function => "function", | 99 | SymbolKind::Function => "function", |
78 | SymbolKind::TypeAlias => "type_alias", | 100 | SymbolKind::TypeAlias => "type_alias", |
79 | SymbolKind::TypeParam => "type_param", | 101 | SymbolKind::TypeParam => "type_param", |
102 | SymbolKind::ConstParam => "const_param", | ||
80 | SymbolKind::LifetimeParam => "lifetime", | 103 | SymbolKind::LifetimeParam => "lifetime", |
81 | SymbolKind::Macro => "macro", | 104 | SymbolKind::Macro => "macro", |
82 | SymbolKind::Local => "variable", | 105 | SymbolKind::Local => "variable", |
@@ -85,59 +108,69 @@ impl HighlightTag { | |||
85 | SymbolKind::SelfParam => "self_keyword", | 108 | SymbolKind::SelfParam => "self_keyword", |
86 | SymbolKind::Impl => "self_type", | 109 | SymbolKind::Impl => "self_type", |
87 | }, | 110 | }, |
88 | HighlightTag::Attribute => "attribute", | 111 | HlTag::Attribute => "attribute", |
89 | HighlightTag::BoolLiteral => "bool_literal", | 112 | HlTag::BoolLiteral => "bool_literal", |
90 | HighlightTag::BuiltinType => "builtin_type", | 113 | HlTag::BuiltinType => "builtin_type", |
91 | HighlightTag::ByteLiteral => "byte_literal", | 114 | HlTag::ByteLiteral => "byte_literal", |
92 | HighlightTag::CharLiteral => "char_literal", | 115 | HlTag::CharLiteral => "char_literal", |
93 | HighlightTag::Comment => "comment", | 116 | HlTag::Comment => "comment", |
94 | HighlightTag::EscapeSequence => "escape_sequence", | 117 | HlTag::EscapeSequence => "escape_sequence", |
95 | HighlightTag::FormatSpecifier => "format_specifier", | 118 | HlTag::FormatSpecifier => "format_specifier", |
96 | HighlightTag::Dummy => "dummy", | 119 | HlTag::Keyword => "keyword", |
97 | HighlightTag::Keyword => "keyword", | 120 | HlTag::Punctuation(punct) => match punct { |
98 | HighlightTag::Punctuation => "punctuation", | 121 | HlPunct::Bracket => "bracket", |
99 | HighlightTag::NumericLiteral => "numeric_literal", | 122 | HlPunct::Brace => "brace", |
100 | HighlightTag::Operator => "operator", | 123 | HlPunct::Parenthesis => "parenthesis", |
101 | HighlightTag::StringLiteral => "string_literal", | 124 | HlPunct::Angle => "angle", |
102 | HighlightTag::UnresolvedReference => "unresolved_reference", | 125 | HlPunct::Comma => "comma", |
126 | HlPunct::Dot => "dot", | ||
127 | HlPunct::Colon => "colon", | ||
128 | HlPunct::Semi => "semicolon", | ||
129 | HlPunct::Other => "punctuation", | ||
130 | }, | ||
131 | HlTag::NumericLiteral => "numeric_literal", | ||
132 | HlTag::Operator => "operator", | ||
133 | HlTag::StringLiteral => "string_literal", | ||
134 | HlTag::UnresolvedReference => "unresolved_reference", | ||
135 | HlTag::None => "none", | ||
103 | } | 136 | } |
104 | } | 137 | } |
105 | } | 138 | } |
106 | 139 | ||
107 | impl fmt::Display for HighlightTag { | 140 | impl fmt::Display for HlTag { |
108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 141 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
109 | fmt::Display::fmt(self.as_str(), f) | 142 | fmt::Display::fmt(self.as_str(), f) |
110 | } | 143 | } |
111 | } | 144 | } |
112 | 145 | ||
113 | impl HighlightModifier { | 146 | impl HlMod { |
114 | const ALL: &'static [HighlightModifier; HighlightModifier::Unsafe as u8 as usize + 1] = &[ | 147 | const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[ |
115 | HighlightModifier::Attribute, | 148 | HlMod::Attribute, |
116 | HighlightModifier::ControlFlow, | 149 | HlMod::ControlFlow, |
117 | HighlightModifier::Definition, | 150 | HlMod::Definition, |
118 | HighlightModifier::Documentation, | 151 | HlMod::Documentation, |
119 | HighlightModifier::Injected, | 152 | HlMod::Injected, |
120 | HighlightModifier::Mutable, | 153 | HlMod::Mutable, |
121 | HighlightModifier::Consuming, | 154 | HlMod::Consuming, |
122 | HighlightModifier::Callable, | 155 | HlMod::Callable, |
123 | HighlightModifier::Static, | 156 | HlMod::Static, |
124 | HighlightModifier::Associated, | 157 | HlMod::Associated, |
125 | HighlightModifier::Unsafe, | 158 | HlMod::Unsafe, |
126 | ]; | 159 | ]; |
127 | 160 | ||
128 | fn as_str(self) -> &'static str { | 161 | fn as_str(self) -> &'static str { |
129 | match self { | 162 | match self { |
130 | HighlightModifier::Attribute => "attribute", | 163 | HlMod::Attribute => "attribute", |
131 | HighlightModifier::ControlFlow => "control", | 164 | HlMod::ControlFlow => "control", |
132 | HighlightModifier::Definition => "declaration", | 165 | HlMod::Definition => "declaration", |
133 | HighlightModifier::Documentation => "documentation", | 166 | HlMod::Documentation => "documentation", |
134 | HighlightModifier::Injected => "injected", | 167 | HlMod::Injected => "injected", |
135 | HighlightModifier::Mutable => "mutable", | 168 | HlMod::Mutable => "mutable", |
136 | HighlightModifier::Consuming => "consuming", | 169 | HlMod::Consuming => "consuming", |
137 | HighlightModifier::Unsafe => "unsafe", | 170 | HlMod::Unsafe => "unsafe", |
138 | HighlightModifier::Callable => "callable", | 171 | HlMod::Callable => "callable", |
139 | HighlightModifier::Static => "static", | 172 | HlMod::Static => "static", |
140 | HighlightModifier::Associated => "associated", | 173 | HlMod::Associated => "associated", |
141 | } | 174 | } |
142 | } | 175 | } |
143 | 176 | ||
@@ -146,7 +179,7 @@ impl HighlightModifier { | |||
146 | } | 179 | } |
147 | } | 180 | } |
148 | 181 | ||
149 | impl fmt::Display for HighlightModifier { | 182 | impl fmt::Display for HlMod { |
150 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 183 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
151 | fmt::Display::fmt(self.as_str(), f) | 184 | fmt::Display::fmt(self.as_str(), f) |
152 | } | 185 | } |
@@ -155,60 +188,63 @@ impl fmt::Display for HighlightModifier { | |||
155 | impl fmt::Display for Highlight { | 188 | impl fmt::Display for Highlight { |
156 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 189 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
157 | write!(f, "{}", self.tag)?; | 190 | write!(f, "{}", self.tag)?; |
158 | for modifier in self.modifiers.iter() { | 191 | for modifier in self.mods.iter() { |
159 | write!(f, ".{}", modifier)? | 192 | write!(f, ".{}", modifier)? |
160 | } | 193 | } |
161 | Ok(()) | 194 | Ok(()) |
162 | } | 195 | } |
163 | } | 196 | } |
164 | 197 | ||
165 | impl From<HighlightTag> for Highlight { | 198 | impl From<HlTag> for Highlight { |
166 | fn from(tag: HighlightTag) -> Highlight { | 199 | fn from(tag: HlTag) -> Highlight { |
167 | Highlight::new(tag) | 200 | Highlight::new(tag) |
168 | } | 201 | } |
169 | } | 202 | } |
170 | 203 | ||
171 | impl Highlight { | 204 | impl Highlight { |
172 | pub(crate) fn new(tag: HighlightTag) -> Highlight { | 205 | pub(crate) fn new(tag: HlTag) -> Highlight { |
173 | Highlight { tag, modifiers: HighlightModifiers::default() } | 206 | Highlight { tag, mods: HlMods::default() } |
207 | } | ||
208 | pub fn is_empty(&self) -> bool { | ||
209 | self.tag == HlTag::None && self.mods == HlMods::default() | ||
174 | } | 210 | } |
175 | } | 211 | } |
176 | 212 | ||
177 | impl ops::BitOr<HighlightModifier> for HighlightTag { | 213 | impl ops::BitOr<HlMod> for HlTag { |
178 | type Output = Highlight; | 214 | type Output = Highlight; |
179 | 215 | ||
180 | fn bitor(self, rhs: HighlightModifier) -> Highlight { | 216 | fn bitor(self, rhs: HlMod) -> Highlight { |
181 | Highlight::new(self) | rhs | 217 | Highlight::new(self) | rhs |
182 | } | 218 | } |
183 | } | 219 | } |
184 | 220 | ||
185 | impl ops::BitOrAssign<HighlightModifier> for HighlightModifiers { | 221 | impl ops::BitOrAssign<HlMod> for HlMods { |
186 | fn bitor_assign(&mut self, rhs: HighlightModifier) { | 222 | fn bitor_assign(&mut self, rhs: HlMod) { |
187 | self.0 |= rhs.mask(); | 223 | self.0 |= rhs.mask(); |
188 | } | 224 | } |
189 | } | 225 | } |
190 | 226 | ||
191 | impl ops::BitOrAssign<HighlightModifier> for Highlight { | 227 | impl ops::BitOrAssign<HlMod> for Highlight { |
192 | fn bitor_assign(&mut self, rhs: HighlightModifier) { | 228 | fn bitor_assign(&mut self, rhs: HlMod) { |
193 | self.modifiers |= rhs; | 229 | self.mods |= rhs; |
194 | } | 230 | } |
195 | } | 231 | } |
196 | 232 | ||
197 | impl ops::BitOr<HighlightModifier> for Highlight { | 233 | impl ops::BitOr<HlMod> for Highlight { |
198 | type Output = Highlight; | 234 | type Output = Highlight; |
199 | 235 | ||
200 | fn bitor(mut self, rhs: HighlightModifier) -> Highlight { | 236 | fn bitor(mut self, rhs: HlMod) -> Highlight { |
201 | self |= rhs; | 237 | self |= rhs; |
202 | self | 238 | self |
203 | } | 239 | } |
204 | } | 240 | } |
205 | 241 | ||
206 | impl HighlightModifiers { | 242 | impl HlMods { |
207 | pub fn contains(self, m: HighlightModifier) -> bool { | 243 | pub fn contains(self, m: HlMod) -> bool { |
208 | self.0 & m.mask() == m.mask() | 244 | self.0 & m.mask() == m.mask() |
209 | } | 245 | } |
210 | 246 | ||
211 | pub fn iter(self) -> impl Iterator<Item = HighlightModifier> { | 247 | pub fn iter(self) -> impl Iterator<Item = HlMod> { |
212 | HighlightModifier::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask()) | 248 | HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask()) |
213 | } | 249 | } |
214 | } | 250 | } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index 506ebe60e..e36e6fc3f 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -36,22 +36,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
40 | 40 | ||
41 | <span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 41 | <span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="brace">{</span><span class="brace">}</span> |
42 | 42 | ||
43 | <span class="keyword">impl</span> <span class="struct">foo</span> <span class="punctuation">{</span> | 43 | <span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span> |
44 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 44 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
45 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 45 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
46 | <span class="punctuation">}</span> | 46 | <span class="brace">}</span> |
47 | 47 | ||
48 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="punctuation">{</span> | 48 | <span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> |
49 | <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 49 | <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
50 | <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 50 | <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
51 | <span class="punctuation">}</span> | 51 | <span class="brace">}</span> |
52 | 52 | ||
53 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="punctuation">{</span> | 53 | <span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> |
54 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 54 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 55 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
56 | <span class="punctuation">}</span> | 56 | <span class="brace">}</span> |
57 | </code></pre> \ No newline at end of file | 57 | </code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 4dd7413ba..6dadda1c1 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -37,67 +37,72 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="comment documentation">/// ```</span> | 39 | <pre><code><span class="comment documentation">/// ```</span> |
40 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="punctuation injected">_</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 40 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="semicolon injected">;</span> |
41 | </span><span class="comment documentation">/// ```</span> | 41 | <span class="comment documentation">/// ```</span> |
42 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> | 42 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span> |
43 | <span class="field declaration">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span><span class="punctuation">,</span> | 43 | <span class="field declaration">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span><span class="comma">,</span> |
44 | <span class="punctuation">}</span> | 44 | <span class="brace">}</span> |
45 | 45 | ||
46 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 46 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span> |
47 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="punctuation">;</span> | 47 | <span class="comment documentation">/// ```</span> |
48 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Call me</span> | ||
49 | <span class="comment">// KILLER WHALE</span> | ||
50 | <span class="comment documentation">/// </span><span class="string_literal injected"> Ishmael."</span><span class="semicolon injected">;</span> | ||
51 | <span class="comment documentation">/// ```</span> | ||
52 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span> | ||
48 | 53 | ||
49 | <span class="comment documentation">/// Constructs a new `Foo`.</span> | 54 | <span class="comment documentation">/// Constructs a new `Foo`.</span> |
50 | <span class="comment documentation">///</span> | 55 | <span class="comment documentation">///</span> |
51 | <span class="comment documentation">/// # Examples</span> | 56 | <span class="comment documentation">/// # Examples</span> |
52 | <span class="comment documentation">///</span> | 57 | <span class="comment documentation">///</span> |
53 | <span class="comment documentation">/// ```</span> | 58 | <span class="comment documentation">/// ```</span> |
54 | <span class="comment documentation">/// #</span><span class="dummy injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="punctuation attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="punctuation attribute injected">)</span><span class="attribute attribute injected">]</span> | 59 | <span class="comment documentation">/// #</span><span class="none injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute attribute injected">]</span> |
55 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="keyword injected">mut</span><span class="dummy injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 60 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
56 | </span> <span class="comment documentation">/// ```</span> | 61 | <span class="comment documentation">/// ```</span> |
57 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 62 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="struct">Foo</span> <span class="brace">{</span> |
58 | <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">bar</span><span class="punctuation">:</span> <span class="bool_literal">true</span> <span class="punctuation">}</span> | 63 | <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">bar</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span> |
59 | <span class="punctuation">}</span> | 64 | <span class="brace">}</span> |
60 | 65 | ||
61 | <span class="comment documentation">/// `bar` method on `Foo`.</span> | 66 | <span class="comment documentation">/// `bar` method on `Foo`.</span> |
62 | <span class="comment documentation">///</span> | 67 | <span class="comment documentation">///</span> |
63 | <span class="comment documentation">/// # Examples</span> | 68 | <span class="comment documentation">/// # Examples</span> |
64 | <span class="comment documentation">///</span> | 69 | <span class="comment documentation">///</span> |
65 | <span class="comment documentation">/// ```</span> | 70 | <span class="comment documentation">/// ```</span> |
66 | <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="dummy injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="punctuation injected">;</span> | 71 | <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="none injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="semicolon injected">;</span> |
67 | <span class="comment documentation">///</span> | 72 | <span class="comment documentation">///</span> |
68 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">foo</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> | 73 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
69 | <span class="comment documentation">///</span> | 74 | <span class="comment documentation">///</span> |
70 | <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> | 75 | <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> |
71 | <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="punctuation injected">(</span><span class="dummy injected">foo</span><span class="operator injected">.</span><span class="dummy injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> | 76 | <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
72 | <span class="comment documentation">///</span> | 77 | <span class="comment documentation">///</span> |
73 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">bar</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="dummy injected"> </span><span class="operator injected">||</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="punctuation injected">;</span> | 78 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span> |
74 | <span class="comment documentation">///</span> | 79 | <span class="comment documentation">///</span> |
75 | <span class="comment documentation">/// </span><span class="comment injected">/* multi-line | 80 | <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span> |
76 | </span><span class="comment documentation">/// </span><span class="comment injected"> comment */</span> | 81 | <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> |
77 | <span class="comment documentation">///</span> | 82 | <span class="comment documentation">///</span> |
78 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="string_literal injected">"Foo | 83 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span> |
79 | </span><span class="comment documentation">/// </span><span class="string_literal injected"> bar | 84 | <span class="comment documentation">/// </span><span class="string_literal injected"> bar</span> |
80 | </span><span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="punctuation injected">;</span> | 85 | <span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="semicolon injected">;</span> |
81 | <span class="comment documentation">///</span> | 86 | <span class="comment documentation">///</span> |
82 | <span class="comment documentation">/// ```</span> | 87 | <span class="comment documentation">/// ```</span> |
83 | <span class="comment documentation">///</span> | 88 | <span class="comment documentation">///</span> |
84 | <span class="comment documentation">/// ```rust,no_run</span> | 89 | <span class="comment documentation">/// ```rust,no_run</span> |
85 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">foobar</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 90 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
86 | </span> <span class="comment documentation">/// ```</span> | 91 | <span class="comment documentation">/// ```</span> |
87 | <span class="comment documentation">///</span> | 92 | <span class="comment documentation">///</span> |
88 | <span class="comment documentation">/// ```sh</span> | 93 | <span class="comment documentation">/// ```sh</span> |
89 | <span class="comment documentation">/// echo 1</span> | 94 | <span class="comment documentation">/// echo 1</span> |
90 | <span class="comment documentation">/// ```</span> | 95 | <span class="comment documentation">/// ```</span> |
91 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">bool</span> <span class="punctuation">{</span> | 96 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">bool</span> <span class="brace">{</span> |
92 | <span class="bool_literal">true</span> | 97 | <span class="bool_literal">true</span> |
93 | <span class="punctuation">}</span> | 98 | <span class="brace">}</span> |
94 | <span class="punctuation">}</span> | 99 | <span class="brace">}</span> |
95 | 100 | ||
96 | <span class="comment documentation">/// ```</span> | 101 | <span class="comment documentation">/// ```</span> |
97 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> | 102 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
98 | </span><span class="comment documentation">/// ```</span> | 103 | <span class="comment documentation">/// ```</span> |
99 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> | 104 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> |
100 | <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span> | 105 | <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> |
101 | <span class="punctuation">$</span>expr | 106 | <span class="punctuation">$</span>expr |
102 | <span class="punctuation">}</span> | 107 | <span class="brace">}</span> |
103 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 108 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index ed452586a..6f7a7ffff 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html | |||
@@ -36,6 +36,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span> | 39 | <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="semicolon">;</span> |
40 | <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span> | 40 | <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="semicolon">;</span> |
41 | </code></pre> \ No newline at end of file | 41 | </code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 92e7dc3e4..753b535b5 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -36,14 +36,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
40 | 40 | ||
41 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 41 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
42 | <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span> | 42 | <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> |
43 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span> | 43 | <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> |
44 | <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 44 | <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
45 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> | 45 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
46 | <span class="punctuation">}</span> | 46 | <span class="brace">}</span> |
47 | <span class="punctuation">}</span><span class="string_literal">"#</span> | 47 | <span class="brace">}</span><span class="string_literal">"#</span> |
48 | <span class="punctuation">)</span><span class="punctuation">;</span> | 48 | <span class="parenthesis">)</span><span class="semicolon">;</span> |
49 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 49 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 31dad5d42..66d80c4b6 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html | |||
@@ -36,64 +36,64 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span> | 39 | <pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="brace">{</span> |
40 | <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">(</span><span class="punctuation">{</span> | 40 | <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="brace">{</span> |
41 | <span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> | 41 | <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
42 | <span class="punctuation">}</span><span class="punctuation">)</span> | 42 | <span class="brace">}</span><span class="parenthesis">)</span> |
43 | <span class="punctuation">}</span> | 43 | <span class="brace">}</span> |
44 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> | 44 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> |
45 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span> | 45 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span> |
46 | <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> | 46 | <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span> |
47 | <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> | 47 | <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>args<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span> |
48 | <span class="punctuation">}</span> | 48 | <span class="brace">}</span> |
49 | 49 | ||
50 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 50 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
51 | <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> | 51 | <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> |
52 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "Hello"</span> | 52 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello"</span> |
53 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "Hello, world!"</span> | 53 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello, world!"</span> |
54 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "The number is 1"</span> | 54 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "The number is 1"</span> |
55 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="numeric_literal">3</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "(3, 4)"</span> | 55 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="parenthesis">(</span><span class="numeric_literal">3</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "(3, 4)"</span> |
56 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "4"</span> | 56 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "4"</span> |
57 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "1 2"</span> | 57 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "1 2"</span> |
58 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">42</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "0042" with leading zerosV</span> | 58 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">42</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "0042" with leading zerosV</span> |
59 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "2 1 1 2"</span> | 59 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1 1 2"</span> |
60 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "test"</span> | 60 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "test"</span> |
61 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "2 1"</span> | 61 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1"</span> |
62 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="punctuation">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="punctuation">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "a 3 b"</span> | 62 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="comma">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="comma">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "a 3 b"</span> |
63 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// => "{2}"</span> | 63 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// => "{2}"</span> |
64 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 64 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
65 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 65 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
66 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 66 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
67 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 67 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
68 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 68 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
69 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 69 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
70 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 70 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
71 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 71 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
72 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 72 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
73 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> | 73 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
74 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 74 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
75 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> | 75 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
76 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> | 76 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
77 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 77 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
78 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 78 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
79 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 79 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
80 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 80 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
81 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 81 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
82 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> | 82 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="comma">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
83 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="punctuation">)</span><span class="punctuation">;</span> | 83 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
84 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 84 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
85 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 85 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
86 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello {{}}"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 86 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello {{}}"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
87 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{ Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 87 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{ Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
88 | 88 | ||
89 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 89 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
90 | 90 | ||
91 | <span class="comment">// escape sequences</span> | 91 | <span class="comment">// escape sequences</span> |
92 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 92 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
93 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="punctuation">)</span><span class="punctuation">;</span> | 93 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
94 | 94 | ||
95 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> | 95 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
96 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> | 96 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
97 | 97 | ||
98 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="punctuation">,</span> thingy<span class="punctuation">,</span> n2<span class="punctuation">)</span><span class="punctuation">;</span> | 98 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="comma">,</span> thingy<span class="comma">,</span> n2<span class="parenthesis">)</span><span class="semicolon">;</span> |
99 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 99 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index e3a0aa317..9d4d6d4a0 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -36,65 +36,65 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 39 | <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
40 | 40 | ||
41 | <span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span> | 41 | <span class="keyword">union</span> <span class="union declaration">Union</span> <span class="brace">{</span> |
42 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> | 42 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span> |
43 | <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span> | 43 | <span class="field declaration">b</span><span class="colon">:</span> <span class="builtin_type">f32</span><span class="comma">,</span> |
44 | <span class="punctuation">}</span> | 44 | <span class="brace">}</span> |
45 | 45 | ||
46 | <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> | 46 | <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span> |
47 | 47 | ||
48 | <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> | 48 | <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span> |
49 | <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 49 | <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
50 | <span class="punctuation">}</span> | 50 | <span class="brace">}</span> |
51 | 51 | ||
52 | <span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span> | 52 | <span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span> |
53 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u8</span> | 53 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u8</span> |
54 | <span class="punctuation">}</span> | 54 | <span class="brace">}</span> |
55 | 55 | ||
56 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="punctuation">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 56 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="colon">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span> |
57 | 57 | ||
58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="punctuation attribute">(</span><span class="attribute attribute">packed</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> | 58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span> |
59 | <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="punctuation">{</span> | 59 | <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span> |
60 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u16</span><span class="punctuation">,</span> | 60 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span> |
61 | <span class="punctuation">}</span> | 61 | <span class="brace">}</span> |
62 | 62 | ||
63 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span> | 63 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> |
64 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span><span class="punctuation">;</span> | 64 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
65 | <span class="punctuation">}</span> | 65 | <span class="brace">}</span> |
66 | 66 | ||
67 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="punctuation">{</span> | 67 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> |
68 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 68 | <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
69 | <span class="punctuation">}</span> | 69 | <span class="brace">}</span> |
70 | 70 | ||
71 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 71 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
72 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> | 72 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span> |
73 | <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 73 | <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span> |
74 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> | 74 | <span class="keyword unsafe">unsafe</span> <span class="brace">{</span> |
75 | <span class="comment">// unsafe fn and method calls</span> | 75 | <span class="comment">// unsafe fn and method calls</span> |
76 | <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 76 | <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
77 | <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="punctuation">;</span> | 77 | <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span> |
78 | <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span> | 78 | <span class="keyword control">match</span> <span class="variable">u</span> <span class="brace">{</span> |
79 | <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | 79 | <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span> <span class="operator">=></span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> |
80 | <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | 80 | <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">a</span> <span class="brace">}</span> <span class="operator">=></span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> |
81 | <span class="punctuation">}</span> | 81 | <span class="brace">}</span> |
82 | <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 82 | <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
83 | 83 | ||
84 | <span class="comment">// unsafe deref</span> | 84 | <span class="comment">// unsafe deref</span> |
85 | <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="punctuation">;</span> | 85 | <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span> |
86 | 86 | ||
87 | <span class="comment">// unsafe access to a static mut</span> | 87 | <span class="comment">// unsafe access to a static mut</span> |
88 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> | 88 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span> |
89 | 89 | ||
90 | <span class="comment">// unsafe ref of packed fields</span> | 90 | <span class="comment">// unsafe ref of packed fields</span> |
91 | <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 91 | <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span> |
92 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> | 92 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span> |
93 | <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> | 93 | <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span> |
94 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> | 94 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> |
95 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> | 95 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> |
96 | 96 | ||
97 | <span class="comment">// unsafe auto ref of packed field</span> | 97 | <span class="comment">// unsafe auto ref of packed field</span> |
98 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 98 | <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
99 | <span class="punctuation">}</span> | 99 | <span class="brace">}</span> |
100 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 100 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 72ff9dd40..6b7447c46 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -36,183 +36,187 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="punctuation">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="punctuation">}</span><span class="punctuation">;</span> | 39 | <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span> |
40 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 40 | <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> |
41 | 41 | ||
42 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> | 42 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> |
43 | <span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 43 | <span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
44 | 44 | ||
45 | <span class="comment">// Needed for function consuming vs normal</span> | 45 | <span class="comment">// Needed for function consuming vs normal</span> |
46 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="punctuation">{</span> | 46 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> |
47 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span> | 47 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span> |
48 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 48 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
49 | <span class="punctuation">}</span> | 49 | <span class="brace">}</span> |
50 | 50 | ||
51 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="punctuation">{</span> | 51 | <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="brace">{</span> |
52 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span> | 52 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span> |
53 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="punctuation"><</span><span class="type_param declaration">Args</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">}</span> | 53 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="angle"><</span><span class="type_param declaration">Args</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> |
54 | 54 | ||
55 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span> | 55 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span> |
56 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="punctuation"><</span><span class="type_param declaration">Args</span><span class="punctuation">></span><span class="punctuation">:</span> <span class="trait">FnOnce</span><span class="punctuation"><</span><span class="type_param">Args</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">}</span> | 56 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="angle"><</span><span class="type_param declaration">Args</span><span class="angle">></span><span class="colon">:</span> <span class="trait">FnOnce</span><span class="angle"><</span><span class="type_param">Args</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> |
57 | 57 | ||
58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span> | 58 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span> |
59 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="punctuation"><</span><span class="type_param declaration">Args</span><span class="punctuation">></span><span class="punctuation">:</span> <span class="trait">FnMut</span><span class="punctuation"><</span><span class="type_param">Args</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">}</span> | 59 | <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="angle"><</span><span class="type_param declaration">Args</span><span class="angle">></span><span class="colon">:</span> <span class="trait">FnMut</span><span class="angle"><</span><span class="type_param">Args</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> |
60 | <span class="punctuation">}</span> | 60 | <span class="brace">}</span> |
61 | 61 | ||
62 | 62 | ||
63 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> | 63 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span> |
64 | <span class="keyword">pub</span> <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> | 64 | <span class="keyword">pub</span> <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span> |
65 | <span class="keyword">pub</span> <span class="field declaration">y</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> | 65 | <span class="keyword">pub</span> <span class="field declaration">y</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span> |
66 | <span class="punctuation">}</span> | 66 | <span class="brace">}</span> |
67 | 67 | ||
68 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span> | 68 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> |
69 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="punctuation">;</span> | 69 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span><span class="semicolon">;</span> |
70 | <span class="punctuation">}</span> | 70 | <span class="brace">}</span> |
71 | 71 | ||
72 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 72 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> |
73 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> | 73 | <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
74 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 74 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
75 | <span class="punctuation">}</span> | 75 | <span class="brace">}</span> |
76 | <span class="punctuation">}</span> | 76 | <span class="brace">}</span> |
77 | 77 | ||
78 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 78 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span> |
79 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">Foo</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> | 79 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
80 | <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="self_keyword mutable consuming">self</span><span class="punctuation">)</span> | 80 | <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="self_keyword mutable consuming">self</span><span class="parenthesis">)</span> |
81 | <span class="punctuation">}</span> | 81 | <span class="brace">}</span> |
82 | 82 | ||
83 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 83 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> |
84 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> | 84 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> |
85 | <span class="punctuation">}</span> | 85 | <span class="brace">}</span> |
86 | 86 | ||
87 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> | 87 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="brace">{</span> |
88 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 88 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
89 | <span class="punctuation">}</span> | 89 | <span class="brace">}</span> |
90 | <span class="punctuation">}</span> | 90 | <span class="brace">}</span> |
91 | 91 | ||
92 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="punctuation attribute">(</span><span class="attribute attribute">Copy</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> | 92 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="parenthesis attribute">(</span><span class="attribute attribute">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span> |
93 | <span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="punctuation">{</span> | 93 | <span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="brace">{</span> |
94 | <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> | 94 | <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span> |
95 | <span class="punctuation">}</span> | 95 | <span class="brace">}</span> |
96 | 96 | ||
97 | <span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> | 97 | <span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span> |
98 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">FooCopy</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> | 98 | <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="brace">{</span> |
99 | <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span> | 99 | <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span> |
100 | <span class="punctuation">}</span> | 100 | <span class="brace">}</span> |
101 | 101 | ||
102 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 102 | <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> |
103 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> | 103 | <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> |
104 | <span class="punctuation">}</span> | 104 | <span class="brace">}</span> |
105 | 105 | ||
106 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> | 106 | <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="brace">{</span> |
107 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> | 107 | <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> |
108 | <span class="punctuation">}</span> | 108 | <span class="brace">}</span> |
109 | <span class="punctuation">}</span> | 109 | <span class="brace">}</span> |
110 | 110 | ||
111 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> | 111 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="colon">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> |
112 | 112 | ||
113 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation"><</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="type_param">T</span> <span class="punctuation">{</span> | 113 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="angle"><</span><span class="lifetime declaration">'a</span><span class="comma">,</span> <span class="type_param declaration">T</span><span class="angle">></span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="type_param">T</span> <span class="brace">{</span> |
114 | <span class="function">foo</span><span class="operator">::</span><span class="punctuation"><</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> | 114 | <span class="function">foo</span><span class="operator">::</span><span class="angle"><</span><span class="lifetime">'a</span><span class="comma">,</span> <span class="builtin_type">i32</span><span class="angle">></span><span class="parenthesis">(</span><span class="parenthesis">)</span> |
115 | <span class="punctuation">}</span> | 115 | <span class="brace">}</span> |
116 | 116 | ||
117 | <span class="keyword">fn</span> <span class="function declaration">never</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">!</span> <span class="punctuation">{</span> | 117 | <span class="keyword">fn</span> <span class="function declaration">never</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">!</span> <span class="brace">{</span> |
118 | <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 118 | <span class="keyword control">loop</span> <span class="brace">{</span><span class="brace">}</span> |
119 | <span class="punctuation">}</span> | 119 | <span class="brace">}</span> |
120 | 120 | ||
121 | <span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> | 121 | <span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle"><</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">></span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="builtin_type">usize</span> <span class="brace">{</span> |
122 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation"><</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">></span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 122 | <span class="const_param">FOO</span> |
123 | <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> | 123 | <span class="brace">}</span> |
124 | <span class="punctuation">}</span> | ||
125 | 124 | ||
126 | <span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 125 | <span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="semicolon">;</span> |
126 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle"><</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">></span><span class="parenthesis">(</span><span class="value_param declaration callable">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
127 | <span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span> | ||
128 | <span class="brace">}</span> | ||
127 | 129 | ||
128 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 130 | <span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="brace">{</span><span class="brace">}</span> |
129 | <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | ||
130 | <span class="punctuation">}</span> | ||
131 | 131 | ||
132 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span> | 132 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
133 | <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span> | 133 | <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
134 | <span class="punctuation">}</span> | 134 | <span class="brace">}</span> |
135 | 135 | ||
136 | <span class="macro">def_fn!</span> <span class="punctuation">{</span> | 136 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span> |
137 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-</span><span class="operator">></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> | 137 | <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span> |
138 | <span class="brace">}</span> | ||
139 | |||
140 | <span class="macro">def_fn!</span> <span class="brace">{</span> | ||
141 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-</span><span class="operator">></span> <span class="builtin_type">u32</span> <span class="brace">{</span> | ||
138 | <span class="numeric_literal">100</span> | 142 | <span class="numeric_literal">100</span> |
139 | <span class="punctuation">}</span> | 143 | <span class="brace">}</span> |
140 | <span class="punctuation">}</span> | 144 | <span class="brace">}</span> |
141 | 145 | ||
142 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> | 146 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> |
143 | <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span> | 147 | <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> |
144 | <span class="punctuation">$</span>expr | 148 | <span class="punctuation">$</span>expr |
145 | <span class="punctuation">}</span> | 149 | <span class="brace">}</span> |
146 | <span class="punctuation">}</span> | 150 | <span class="brace">}</span> |
147 | 151 | ||
148 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span> | 152 | <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span> |
149 | <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span> | 153 | <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> |
150 | <span class="punctuation">}</span> | 154 | <span class="brace">}</span> |
151 | 155 | ||
152 | <span class="comment">// comment</span> | 156 | <span class="comment">// comment</span> |
153 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 157 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
154 | <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> | 158 | <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
155 | 159 | ||
156 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 160 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
157 | <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="punctuation">{</span> | 161 | <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="brace">{</span> |
158 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">;</span> | 162 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="semicolon">;</span> |
159 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="punctuation">(</span><span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="numeric_literal">1</span> <span class="punctuation">}</span><span class="punctuation">)</span><span class="punctuation">;</span> | 163 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="parenthesis">(</span><span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="numeric_literal">1</span> <span class="brace">}</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
160 | <span class="punctuation">}</span> | 164 | <span class="brace">}</span> |
161 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> | 165 | <span class="keyword unsafe">unsafe</span> <span class="brace">{</span> |
162 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span> | 166 | <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="parenthesis">(</span><span class="numeric_literal">0</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
163 | <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span> | 167 | <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span> |
164 | <span class="punctuation">}</span> | 168 | <span class="brace">}</span> |
165 | 169 | ||
166 | <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span> | 170 | <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="brace">{</span> |
167 | <span class="comment">// Do nothing</span> | 171 | <span class="comment">// Do nothing</span> |
168 | <span class="punctuation">}</span> | 172 | <span class="brace">}</span> |
169 | 173 | ||
170 | <span class="macro">noop!</span><span class="punctuation">(</span><span class="macro">noop</span><span class="macro">!</span><span class="punctuation">(</span><span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> | 174 | <span class="macro">noop!</span><span class="parenthesis">(</span><span class="macro">noop</span><span class="macro">!</span><span class="parenthesis">(</span><span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
171 | 175 | ||
172 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="punctuation">;</span> | 176 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="semicolon">;</span> |
173 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="punctuation">;</span> | 177 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="semicolon">;</span> |
174 | <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="punctuation">;</span> | 178 | <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="semicolon">;</span> |
175 | 179 | ||
176 | <span class="keyword">let</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable declaration">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 180 | <span class="keyword">let</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable declaration">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span><span class="semicolon">;</span> |
177 | 181 | ||
178 | <span class="variable">y</span><span class="punctuation">;</span> | 182 | <span class="variable">y</span><span class="semicolon">;</span> |
179 | 183 | ||
180 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 184 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span> |
181 | <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 185 | <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span> |
182 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 186 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
183 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 187 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
184 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="variable consuming">foo2</span><span class="punctuation">)</span><span class="punctuation">;</span> | 188 | <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
185 | 189 | ||
186 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> <span class="field">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 190 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="brace">{</span> <span class="field">x</span> <span class="brace">}</span><span class="semicolon">;</span> |
187 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 191 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
188 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 192 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
189 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="variable mutable">copy</span><span class="punctuation">)</span><span class="punctuation">;</span> | 193 | <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
190 | 194 | ||
191 | <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="punctuation">;</span> | 195 | <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span> |
192 | <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="punctuation">;</span> | 196 | <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span> |
193 | 197 | ||
194 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="punctuation">;</span> | 198 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> |
195 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span> | 199 | <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> |
196 | 200 | ||
197 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="punctuation">;</span> | 201 | <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> |
198 | 202 | ||
199 | <span class="label declaration">'foo</span><span class="punctuation">:</span> <span class="keyword control">loop</span> <span class="punctuation">{</span> | 203 | <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span> |
200 | <span class="keyword control">break</span> <span class="label">'foo</span><span class="punctuation">;</span> | 204 | <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span> |
201 | <span class="keyword control">continue</span> <span class="label">'foo</span><span class="punctuation">;</span> | 205 | <span class="keyword control">continue</span> <span class="label">'foo</span><span class="semicolon">;</span> |
202 | <span class="punctuation">}</span> | 206 | <span class="brace">}</span> |
203 | <span class="punctuation">}</span> | 207 | <span class="brace">}</span> |
204 | 208 | ||
205 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="punctuation">{</span> | 209 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span> <span class="brace">{</span> |
206 | <span class="enum_variant declaration">Some</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">)</span><span class="punctuation">,</span> | 210 | <span class="enum_variant declaration">Some</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="parenthesis">)</span><span class="comma">,</span> |
207 | <span class="enum_variant declaration">None</span><span class="punctuation">,</span> | 211 | <span class="enum_variant declaration">None</span><span class="comma">,</span> |
208 | <span class="punctuation">}</span> | 212 | <span class="brace">}</span> |
209 | <span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="punctuation">;</span> | 213 | <span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> |
210 | 214 | ||
211 | <span class="keyword">impl</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="enum">Option</span><span class="punctuation"><</span><span class="type_param">T</span><span class="punctuation">></span> <span class="punctuation">{</span> | 215 | <span class="keyword">impl</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span> <span class="enum">Option</span><span class="angle"><</span><span class="type_param">T</span><span class="angle">></span> <span class="brace">{</span> |
212 | <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="punctuation"><</span><span class="type_param declaration">U</span><span class="punctuation">></span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">other</span><span class="punctuation">:</span> <span class="enum">Option</span><span class="punctuation"><</span><span class="type_param">U</span><span class="punctuation">></span><span class="punctuation">)</span> <span class="operator">-></span> <span class="enum">Option</span><span class="punctuation"><</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">,</span> <span class="type_param">U</span><span class="punctuation">)</span><span class="punctuation">></span> <span class="punctuation">{</span> | 216 | <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle"><</span><span class="type_param declaration">U</span><span class="angle">></span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle"><</span><span class="type_param">U</span><span class="angle">></span><span class="parenthesis">)</span> <span class="operator">-></span> <span class="enum">Option</span><span class="angle"><</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">></span> <span class="brace">{</span> |
213 | <span class="keyword control">match</span> <span class="value_param">other</span> <span class="punctuation">{</span> | 217 | <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span> |
214 | <span class="enum_variant">None</span> <span class="operator">=></span> <span class="macro">unimplemented!</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | 218 | <span class="enum_variant">None</span> <span class="operator">=></span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> |
215 | <span class="variable declaration">Nope</span> <span class="operator">=></span> <span class="variable">Nope</span><span class="punctuation">,</span> | 219 | <span class="variable declaration">Nope</span> <span class="operator">=></span> <span class="variable">Nope</span><span class="comma">,</span> |
216 | <span class="punctuation">}</span> | 220 | <span class="brace">}</span> |
217 | <span class="punctuation">}</span> | 221 | <span class="brace">}</span> |
218 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 222 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html new file mode 100644 index 000000000..78dfec951 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/injection.html | |||
@@ -0,0 +1,48 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | ||
7 | .label { color: #DFAF8F; font-style: italic; } | ||
8 | .comment { color: #7F9F7F; } | ||
9 | .documentation { color: #629755; } | ||
10 | .injected { opacity: 0.65 ; } | ||
11 | .struct, .enum { color: #7CB8BB; } | ||
12 | .enum_variant { color: #BDE0F3; } | ||
13 | .string_literal { color: #CC9393; } | ||
14 | .field { color: #94BFF3; } | ||
15 | .function { color: #93E0E3; } | ||
16 | .function.unsafe { color: #BC8383; } | ||
17 | .operator.unsafe { color: #BC8383; } | ||
18 | .parameter { color: #94BFF3; } | ||
19 | .text { color: #DCDCCC; } | ||
20 | .type { color: #7CB8BB; } | ||
21 | .builtin_type { color: #8CD0D3; } | ||
22 | .type_param { color: #DFAF8F; } | ||
23 | .attribute { color: #94BFF3; } | ||
24 | .numeric_literal { color: #BFEBBF; } | ||
25 | .bool_literal { color: #BFE6EB; } | ||
26 | .macro { color: #94BFF3; } | ||
27 | .module { color: #AFD8AF; } | ||
28 | .value_param { color: #DCDCCC; } | ||
29 | .variable { color: #DCDCCC; } | ||
30 | .format_specifier { color: #CC696B; } | ||
31 | .mutable { text-decoration: underline; } | ||
32 | .escape_sequence { color: #94BFF3; } | ||
33 | .keyword { color: #F0DFAF; font-weight: bold; } | ||
34 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | ||
35 | .control { font-style: italic; } | ||
36 | |||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | ||
38 | </style> | ||
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">f</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | ||
40 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
41 | <span class="function">f</span><span class="parenthesis">(</span><span class="string_literal">r"</span> | ||
42 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
43 | <span class="function">foo</span><span class="parenthesis">(</span><span class="keyword">$0</span><span class="brace">{</span> | ||
44 | <span class="numeric_literal">92</span> | ||
45 | <span class="brace">}</span><span class="keyword">$0</span><span class="parenthesis">)</span> | ||
46 | <span class="brace">}</span><span class="string_literal">"</span><span class="parenthesis">)</span><span class="semicolon">;</span> | ||
47 | <span class="brace">}</span> | ||
48 | </code></pre> \ No newline at end of file | ||
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html index 8b3dfa69f..e64f2e5e9 100644 --- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html | |||
@@ -36,15 +36,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
36 | 36 | ||
37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | 37 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
38 | </style> | 38 | </style> |
39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 39 | <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
40 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> | 40 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> |
41 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 41 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
42 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 42 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
43 | 43 | ||
44 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="punctuation">;</span> | 44 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span> |
45 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 45 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
46 | <span class="punctuation">}</span> | 46 | <span class="brace">}</span> |
47 | 47 | ||
48 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 48 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
49 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> | 49 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> |
50 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 50 | <span class="brace">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index e0df0d2b5..a62704c39 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -91,6 +91,10 @@ fn never() -> ! { | |||
91 | loop {} | 91 | loop {} |
92 | } | 92 | } |
93 | 93 | ||
94 | fn const_param<const FOO: usize>() -> usize { | ||
95 | FOO | ||
96 | } | ||
97 | |||
94 | use ops::Fn; | 98 | use ops::Fn; |
95 | fn baz<F: Fn() -> ()>(f: F) { | 99 | fn baz<F: Fn() -> ()>(f: F) { |
96 | f() | 100 | f() |
@@ -442,6 +446,11 @@ struct Foo { | |||
442 | } | 446 | } |
443 | 447 | ||
444 | impl Foo { | 448 | impl Foo { |
449 | /// ``` | ||
450 | /// let _ = "Call me | ||
451 | // KILLER WHALE | ||
452 | /// Ishmael."; | ||
453 | /// ``` | ||
445 | pub const bar: bool = true; | 454 | pub const bar: bool = true; |
446 | 455 | ||
447 | /// Constructs a new `Foo`. | 456 | /// Constructs a new `Foo`. |
@@ -551,6 +560,25 @@ impl t for foo { | |||
551 | ) | 560 | ) |
552 | } | 561 | } |
553 | 562 | ||
563 | #[test] | ||
564 | fn test_injection() { | ||
565 | check_highlighting( | ||
566 | r##" | ||
567 | fn f(ra_fixture: &str) {} | ||
568 | fn main() { | ||
569 | f(r" | ||
570 | fn foo() { | ||
571 | foo(\$0{ | ||
572 | 92 | ||
573 | }\$0) | ||
574 | }"); | ||
575 | } | ||
576 | "##, | ||
577 | expect_file!["./test_data/injection.html"], | ||
578 | false, | ||
579 | ); | ||
580 | } | ||
581 | |||
554 | /// Highlights the code given by the `ra_fixture` argument, renders the | 582 | /// Highlights the code given by the `ra_fixture` argument, renders the |
555 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | 583 | /// result as HTML, and compares it with the HTML file given as `snapshot`. |
556 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | 584 | /// Note that the `snapshot` file is overwritten by the rendered HTML. |
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 6dd05c05d..1f26f8043 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs | |||
@@ -85,7 +85,7 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<St | |||
85 | .trim_end_matches('"') | 85 | .trim_end_matches('"') |
86 | .trim() | 86 | .trim() |
87 | // Remove custom markers | 87 | // Remove custom markers |
88 | .replace("<|>", ""); | 88 | .replace("$0", ""); |
89 | 89 | ||
90 | let parsed = SourceFile::parse(&text); | 90 | let parsed = SourceFile::parse(&text); |
91 | 91 | ||
@@ -182,7 +182,7 @@ [email protected] | |||
182 | 182 | ||
183 | #[test] | 183 | #[test] |
184 | fn test_syntax_tree_with_range() { | 184 | fn test_syntax_tree_with_range() { |
185 | let (analysis, range) = fixture::range(r#"<|>fn foo() {}<|>"#.trim()); | 185 | let (analysis, range) = fixture::range(r#"$0fn foo() {}$0"#.trim()); |
186 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | 186 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); |
187 | 187 | ||
188 | assert_eq_text!( | 188 | assert_eq_text!( |
@@ -206,10 +206,10 @@ [email protected] | |||
206 | 206 | ||
207 | let (analysis, range) = fixture::range( | 207 | let (analysis, range) = fixture::range( |
208 | r#"fn test() { | 208 | r#"fn test() { |
209 | <|>assert!(" | 209 | $0assert!(" |
210 | fn foo() { | 210 | fn foo() { |
211 | } | 211 | } |
212 | ", "");<|> | 212 | ", "");$0 |
213 | }"# | 213 | }"# |
214 | .trim(), | 214 | .trim(), |
215 | ); | 215 | ); |
@@ -243,8 +243,8 @@ [email protected] | |||
243 | let (analysis, range) = fixture::range( | 243 | let (analysis, range) = fixture::range( |
244 | r#"fn test() { | 244 | r#"fn test() { |
245 | assert!(" | 245 | assert!(" |
246 | <|>fn foo() { | 246 | $0fn foo() { |
247 | }<|> | 247 | }$0 |
248 | fn bar() { | 248 | fn bar() { |
249 | } | 249 | } |
250 | ", ""); | 250 | ", ""); |
@@ -277,8 +277,8 @@ [email protected] | |||
277 | let (analysis, range) = fixture::range( | 277 | let (analysis, range) = fixture::range( |
278 | r###"fn test() { | 278 | r###"fn test() { |
279 | assert!(r#" | 279 | assert!(r#" |
280 | <|>fn foo() { | 280 | $0fn foo() { |
281 | }<|> | 281 | }$0 |
282 | fn bar() { | 282 | fn bar() { |
283 | } | 283 | } |
284 | "#, ""); | 284 | "#, ""); |
@@ -310,11 +310,11 @@ [email protected] | |||
310 | // With a raw string | 310 | // With a raw string |
311 | let (analysis, range) = fixture::range( | 311 | let (analysis, range) = fixture::range( |
312 | r###"fn test() { | 312 | r###"fn test() { |
313 | assert!(r<|>#" | 313 | assert!(r$0#" |
314 | fn foo() { | 314 | fn foo() { |
315 | } | 315 | } |
316 | fn bar() { | 316 | fn bar() { |
317 | }"<|>#, ""); | 317 | }"$0#, ""); |
318 | }"### | 318 | }"### |
319 | .trim(), | 319 | .trim(), |
320 | ); | 320 | ); |
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index 43458a3a2..88c905003 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -170,7 +170,7 @@ mod tests { | |||
170 | fn test_on_eq_typed() { | 170 | fn test_on_eq_typed() { |
171 | // do_check(r" | 171 | // do_check(r" |
172 | // fn foo() { | 172 | // fn foo() { |
173 | // let foo =<|> | 173 | // let foo =$0 |
174 | // } | 174 | // } |
175 | // ", r" | 175 | // ", r" |
176 | // fn foo() { | 176 | // fn foo() { |
@@ -181,7 +181,7 @@ mod tests { | |||
181 | '=', | 181 | '=', |
182 | r" | 182 | r" |
183 | fn foo() { | 183 | fn foo() { |
184 | let foo <|> 1 + 1 | 184 | let foo $0 1 + 1 |
185 | } | 185 | } |
186 | ", | 186 | ", |
187 | r" | 187 | r" |
@@ -192,7 +192,7 @@ fn foo() { | |||
192 | ); | 192 | ); |
193 | // do_check(r" | 193 | // do_check(r" |
194 | // fn foo() { | 194 | // fn foo() { |
195 | // let foo =<|> | 195 | // let foo =$0 |
196 | // let bar = 1; | 196 | // let bar = 1; |
197 | // } | 197 | // } |
198 | // ", r" | 198 | // ", r" |
@@ -210,7 +210,7 @@ fn foo() { | |||
210 | r" | 210 | r" |
211 | fn main() { | 211 | fn main() { |
212 | xs.foo() | 212 | xs.foo() |
213 | <|> | 213 | $0 |
214 | } | 214 | } |
215 | ", | 215 | ", |
216 | r" | 216 | r" |
@@ -225,7 +225,7 @@ fn foo() { | |||
225 | r" | 225 | r" |
226 | fn main() { | 226 | fn main() { |
227 | xs.foo() | 227 | xs.foo() |
228 | <|> | 228 | $0 |
229 | } | 229 | } |
230 | ", | 230 | ", |
231 | ) | 231 | ) |
@@ -238,7 +238,7 @@ fn foo() { | |||
238 | r" | 238 | r" |
239 | fn main() { | 239 | fn main() { |
240 | xs.foo() | 240 | xs.foo() |
241 | <|>; | 241 | $0; |
242 | } | 242 | } |
243 | ", | 243 | ", |
244 | r" | 244 | r" |
@@ -253,7 +253,7 @@ fn foo() { | |||
253 | r" | 253 | r" |
254 | fn main() { | 254 | fn main() { |
255 | xs.foo() | 255 | xs.foo() |
256 | <|>; | 256 | $0; |
257 | } | 257 | } |
258 | ", | 258 | ", |
259 | ) | 259 | ) |
@@ -266,7 +266,7 @@ fn foo() { | |||
266 | r#" | 266 | r#" |
267 | fn main() { | 267 | fn main() { |
268 | let _ = foo | 268 | let _ = foo |
269 | <|> | 269 | $0 |
270 | bar() | 270 | bar() |
271 | } | 271 | } |
272 | "#, | 272 | "#, |
@@ -288,7 +288,7 @@ fn main() { | |||
288 | fn main() { | 288 | fn main() { |
289 | xs.foo() | 289 | xs.foo() |
290 | .first() | 290 | .first() |
291 | <|> | 291 | $0 |
292 | } | 292 | } |
293 | ", | 293 | ", |
294 | r" | 294 | r" |
@@ -305,7 +305,7 @@ fn main() { | |||
305 | fn main() { | 305 | fn main() { |
306 | xs.foo() | 306 | xs.foo() |
307 | .first() | 307 | .first() |
308 | <|> | 308 | $0 |
309 | } | 309 | } |
310 | ", | 310 | ", |
311 | ); | 311 | ); |
@@ -318,7 +318,7 @@ fn main() { | |||
318 | r" | 318 | r" |
319 | fn source_impl() { | 319 | fn source_impl() { |
320 | let var = enum_defvariant_list().unwrap() | 320 | let var = enum_defvariant_list().unwrap() |
321 | <|> | 321 | $0 |
322 | .nth(92) | 322 | .nth(92) |
323 | .unwrap(); | 323 | .unwrap(); |
324 | } | 324 | } |
@@ -337,7 +337,7 @@ fn main() { | |||
337 | r" | 337 | r" |
338 | fn source_impl() { | 338 | fn source_impl() { |
339 | let var = enum_defvariant_list().unwrap() | 339 | let var = enum_defvariant_list().unwrap() |
340 | <|> | 340 | $0 |
341 | .nth(92) | 341 | .nth(92) |
342 | .unwrap(); | 342 | .unwrap(); |
343 | } | 343 | } |
@@ -351,7 +351,7 @@ fn main() { | |||
351 | '.', | 351 | '.', |
352 | r" | 352 | r" |
353 | fn main() { | 353 | fn main() { |
354 | <|> | 354 | $0 |
355 | } | 355 | } |
356 | ", | 356 | ", |
357 | ); | 357 | ); |
@@ -359,7 +359,7 @@ fn main() { | |||
359 | '.', | 359 | '.', |
360 | r" | 360 | r" |
361 | fn main() { | 361 | fn main() { |
362 | <|> | 362 | $0 |
363 | } | 363 | } |
364 | ", | 364 | ", |
365 | ); | 365 | ); |
@@ -367,6 +367,6 @@ fn main() { | |||
367 | 367 | ||
368 | #[test] | 368 | #[test] |
369 | fn adds_space_after_return_type() { | 369 | fn adds_space_after_return_type() { |
370 | type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -> { 92 }") | 370 | type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }") |
371 | } | 371 | } |
372 | } | 372 | } |
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs index f4ea30352..63cd51b69 100644 --- a/crates/ide/src/typing/on_enter.rs +++ b/crates/ide/src/typing/on_enter.rs | |||
@@ -136,7 +136,7 @@ mod tests { | |||
136 | fn continues_doc_comment() { | 136 | fn continues_doc_comment() { |
137 | do_check( | 137 | do_check( |
138 | r" | 138 | r" |
139 | /// Some docs<|> | 139 | /// Some docs$0 |
140 | fn foo() { | 140 | fn foo() { |
141 | } | 141 | } |
142 | ", | 142 | ", |
@@ -151,7 +151,7 @@ fn foo() { | |||
151 | do_check( | 151 | do_check( |
152 | r" | 152 | r" |
153 | impl S { | 153 | impl S { |
154 | /// Some<|> docs. | 154 | /// Some$0 docs. |
155 | fn foo() {} | 155 | fn foo() {} |
156 | } | 156 | } |
157 | ", | 157 | ", |
@@ -166,7 +166,7 @@ impl S { | |||
166 | 166 | ||
167 | do_check( | 167 | do_check( |
168 | r" | 168 | r" |
169 | ///<|> Some docs | 169 | ///$0 Some docs |
170 | fn foo() { | 170 | fn foo() { |
171 | } | 171 | } |
172 | ", | 172 | ", |
@@ -181,7 +181,7 @@ fn foo() { | |||
181 | 181 | ||
182 | #[test] | 182 | #[test] |
183 | fn does_not_continue_before_doc_comment() { | 183 | fn does_not_continue_before_doc_comment() { |
184 | do_check_noop(r"<|>//! docz"); | 184 | do_check_noop(r"$0//! docz"); |
185 | } | 185 | } |
186 | 186 | ||
187 | #[test] | 187 | #[test] |
@@ -189,7 +189,7 @@ fn foo() { | |||
189 | do_check( | 189 | do_check( |
190 | r" | 190 | r" |
191 | fn main() { | 191 | fn main() { |
192 | // Fix<|> me | 192 | // Fix$0 me |
193 | let x = 1 + 1; | 193 | let x = 1 + 1; |
194 | } | 194 | } |
195 | ", | 195 | ", |
@@ -208,7 +208,7 @@ fn main() { | |||
208 | do_check( | 208 | do_check( |
209 | r" | 209 | r" |
210 | fn main() { | 210 | fn main() { |
211 | // Fix<|> | 211 | // Fix$0 |
212 | // me | 212 | // me |
213 | let x = 1 + 1; | 213 | let x = 1 + 1; |
214 | } | 214 | } |
@@ -229,7 +229,7 @@ fn main() { | |||
229 | do_check_noop( | 229 | do_check_noop( |
230 | r" | 230 | r" |
231 | fn main() { | 231 | fn main() { |
232 | // Fix me<|> | 232 | // Fix me$0 |
233 | let x = 1 + 1; | 233 | let x = 1 + 1; |
234 | } | 234 | } |
235 | ", | 235 | ", |
@@ -242,7 +242,7 @@ fn main() { | |||
242 | do_check( | 242 | do_check( |
243 | r#" | 243 | r#" |
244 | fn main() { | 244 | fn main() { |
245 | // Fix me <|> | 245 | // Fix me $0 |
246 | let x = 1 + 1; | 246 | let x = 1 + 1; |
247 | } | 247 | } |
248 | "#, | 248 | "#, |
@@ -261,7 +261,7 @@ fn main() { | |||
261 | do_check( | 261 | do_check( |
262 | " | 262 | " |
263 | fn main() { | 263 | fn main() { |
264 | // Fix me \t\t <|> | 264 | // Fix me \t\t $0 |
265 | let x = 1 + 1; | 265 | let x = 1 + 1; |
266 | } | 266 | } |
267 | ", | 267 | ", |
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs new file mode 100644 index 000000000..cfcfb7cfb --- /dev/null +++ b/crates/ide/src/view_hir.rs | |||
@@ -0,0 +1,25 @@ | |||
1 | use hir::{Function, Semantics}; | ||
2 | use ide_db::base_db::FilePosition; | ||
3 | use ide_db::RootDatabase; | ||
4 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | ||
5 | |||
6 | // Feature: View Hir | ||
7 | // | ||
8 | // |=== | ||
9 | // | Editor | Action Name | ||
10 | // | ||
11 | // | VS Code | **Rust Analyzer: View Hir** | ||
12 | // |=== | ||
13 | pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { | ||
14 | body_hir(db, position).unwrap_or("Not inside a function body".to_string()) | ||
15 | } | ||
16 | |||
17 | fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> { | ||
18 | let sema = Semantics::new(db); | ||
19 | let source_file = sema.parse(position.file_id); | ||
20 | |||
21 | let function = find_node_at_offset::<ast::Fn>(source_file.syntax(), position.offset)?; | ||
22 | |||
23 | let function: Function = sema.to_def(&function)?; | ||
24 | Some(function.debug_hir(db)) | ||
25 | } | ||
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml index 0ad6e1000..d3d3dc688 100644 --- a/crates/ide_db/Cargo.toml +++ b/crates/ide_db/Cargo.toml | |||
@@ -19,7 +19,7 @@ fst = { version = "0.4", default-features = false } | |||
19 | rustc-hash = "1.1.0" | 19 | rustc-hash = "1.1.0" |
20 | once_cell = "1.3.1" | 20 | once_cell = "1.3.1" |
21 | either = "1.6.1" | 21 | either = "1.6.1" |
22 | itertools = "0.9.0" | 22 | itertools = "0.10.0" |
23 | 23 | ||
24 | stdx = { path = "../stdx", version = "0.0.0" } | 24 | stdx = { path = "../stdx", version = "0.0.0" } |
25 | syntax = { path = "../syntax", version = "0.0.0" } | 25 | syntax = { path = "../syntax", version = "0.0.0" } |
@@ -32,4 +32,4 @@ test_utils = { path = "../test_utils", version = "0.0.0" } | |||
32 | hir = { path = "../hir", version = "0.0.0" } | 32 | hir = { path = "../hir", version = "0.0.0" } |
33 | 33 | ||
34 | [dev-dependencies] | 34 | [dev-dependencies] |
35 | expect-test = "1.0" | 35 | expect-test = "1.1" |
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs index 71c19ed13..c770a236b 100644 --- a/crates/ide_db/src/apply_change.rs +++ b/crates/ide_db/src/apply_change.rs | |||
@@ -145,6 +145,7 @@ impl RootDatabase { | |||
145 | hir::db::MacroDefQuery | 145 | hir::db::MacroDefQuery |
146 | hir::db::ParseMacroExpansionQuery | 146 | hir::db::ParseMacroExpansionQuery |
147 | hir::db::MacroExpandQuery | 147 | hir::db::MacroExpandQuery |
148 | hir::db::HygieneFrameQuery | ||
148 | 149 | ||
149 | // DefDatabase | 150 | // DefDatabase |
150 | hir::db::ItemTreeQuery | 151 | hir::db::ItemTreeQuery |
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs index 9335aeaa5..c714cf280 100644 --- a/crates/ide_db/src/call_info/tests.rs +++ b/crates/ide_db/src/call_info/tests.rs | |||
@@ -3,12 +3,12 @@ use base_db::{fixture::ChangeFixture, FilePosition}; | |||
3 | use expect_test::{expect, Expect}; | 3 | use expect_test::{expect, Expect}; |
4 | use test_utils::{mark, RangeOrOffset}; | 4 | use test_utils::{mark, RangeOrOffset}; |
5 | 5 | ||
6 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 6 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
7 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 7 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { |
8 | let change_fixture = ChangeFixture::parse(ra_fixture); | 8 | let change_fixture = ChangeFixture::parse(ra_fixture); |
9 | let mut database = RootDatabase::default(); | 9 | let mut database = RootDatabase::default(); |
10 | database.apply_change(change_fixture.change); | 10 | database.apply_change(change_fixture.change); |
11 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 11 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
12 | let offset = match range_or_offset { | 12 | let offset = match range_or_offset { |
13 | RangeOrOffset::Range(_) => panic!(), | 13 | RangeOrOffset::Range(_) => panic!(), |
14 | RangeOrOffset::Offset(it) => it, | 14 | RangeOrOffset::Offset(it) => it, |
@@ -49,7 +49,7 @@ fn test_fn_signature_two_args() { | |||
49 | check( | 49 | check( |
50 | r#" | 50 | r#" |
51 | fn foo(x: u32, y: u32) -> u32 {x + y} | 51 | fn foo(x: u32, y: u32) -> u32 {x + y} |
52 | fn bar() { foo(<|>3, ); } | 52 | fn bar() { foo($03, ); } |
53 | "#, | 53 | "#, |
54 | expect![[r#" | 54 | expect![[r#" |
55 | fn foo(x: u32, y: u32) -> u32 | 55 | fn foo(x: u32, y: u32) -> u32 |
@@ -59,7 +59,7 @@ fn bar() { foo(<|>3, ); } | |||
59 | check( | 59 | check( |
60 | r#" | 60 | r#" |
61 | fn foo(x: u32, y: u32) -> u32 {x + y} | 61 | fn foo(x: u32, y: u32) -> u32 {x + y} |
62 | fn bar() { foo(3<|>, ); } | 62 | fn bar() { foo(3$0, ); } |
63 | "#, | 63 | "#, |
64 | expect![[r#" | 64 | expect![[r#" |
65 | fn foo(x: u32, y: u32) -> u32 | 65 | fn foo(x: u32, y: u32) -> u32 |
@@ -69,7 +69,7 @@ fn bar() { foo(3<|>, ); } | |||
69 | check( | 69 | check( |
70 | r#" | 70 | r#" |
71 | fn foo(x: u32, y: u32) -> u32 {x + y} | 71 | fn foo(x: u32, y: u32) -> u32 {x + y} |
72 | fn bar() { foo(3,<|> ); } | 72 | fn bar() { foo(3,$0 ); } |
73 | "#, | 73 | "#, |
74 | expect![[r#" | 74 | expect![[r#" |
75 | fn foo(x: u32, y: u32) -> u32 | 75 | fn foo(x: u32, y: u32) -> u32 |
@@ -79,7 +79,7 @@ fn bar() { foo(3,<|> ); } | |||
79 | check( | 79 | check( |
80 | r#" | 80 | r#" |
81 | fn foo(x: u32, y: u32) -> u32 {x + y} | 81 | fn foo(x: u32, y: u32) -> u32 {x + y} |
82 | fn bar() { foo(3, <|>); } | 82 | fn bar() { foo(3, $0); } |
83 | "#, | 83 | "#, |
84 | expect![[r#" | 84 | expect![[r#" |
85 | fn foo(x: u32, y: u32) -> u32 | 85 | fn foo(x: u32, y: u32) -> u32 |
@@ -93,7 +93,7 @@ fn test_fn_signature_two_args_empty() { | |||
93 | check( | 93 | check( |
94 | r#" | 94 | r#" |
95 | fn foo(x: u32, y: u32) -> u32 {x + y} | 95 | fn foo(x: u32, y: u32) -> u32 {x + y} |
96 | fn bar() { foo(<|>); } | 96 | fn bar() { foo($0); } |
97 | "#, | 97 | "#, |
98 | expect![[r#" | 98 | expect![[r#" |
99 | fn foo(x: u32, y: u32) -> u32 | 99 | fn foo(x: u32, y: u32) -> u32 |
@@ -110,7 +110,7 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | |||
110 | where T: Copy + Display, U: Debug | 110 | where T: Copy + Display, U: Debug |
111 | { x + y } | 111 | { x + y } |
112 | 112 | ||
113 | fn bar() { foo(<|>3, ); } | 113 | fn bar() { foo($03, ); } |
114 | "#, | 114 | "#, |
115 | expect![[r#" | 115 | expect![[r#" |
116 | fn foo(x: i32, y: {unknown}) -> u32 | 116 | fn foo(x: i32, y: {unknown}) -> u32 |
@@ -124,7 +124,7 @@ fn test_fn_signature_no_params() { | |||
124 | check( | 124 | check( |
125 | r#" | 125 | r#" |
126 | fn foo<T>() -> T where T: Copy + Display {} | 126 | fn foo<T>() -> T where T: Copy + Display {} |
127 | fn bar() { foo(<|>); } | 127 | fn bar() { foo($0); } |
128 | "#, | 128 | "#, |
129 | expect![[r#" | 129 | expect![[r#" |
130 | fn foo() -> {unknown} | 130 | fn foo() -> {unknown} |
@@ -140,7 +140,7 @@ fn test_fn_signature_for_impl() { | |||
140 | struct F; | 140 | struct F; |
141 | impl F { pub fn new() { } } | 141 | impl F { pub fn new() { } } |
142 | fn bar() { | 142 | fn bar() { |
143 | let _ : F = F::new(<|>); | 143 | let _ : F = F::new($0); |
144 | } | 144 | } |
145 | "#, | 145 | "#, |
146 | expect![[r#" | 146 | expect![[r#" |
@@ -159,7 +159,7 @@ impl S { pub fn do_it(&self) {} } | |||
159 | 159 | ||
160 | fn bar() { | 160 | fn bar() { |
161 | let s: S = S; | 161 | let s: S = S; |
162 | s.do_it(<|>); | 162 | s.do_it($0); |
163 | } | 163 | } |
164 | "#, | 164 | "#, |
165 | expect![[r#" | 165 | expect![[r#" |
@@ -178,7 +178,7 @@ impl S { | |||
178 | fn foo(&self, x: i32) {} | 178 | fn foo(&self, x: i32) {} |
179 | } | 179 | } |
180 | 180 | ||
181 | fn main() { S.foo(<|>); } | 181 | fn main() { S.foo($0); } |
182 | "#, | 182 | "#, |
183 | expect![[r#" | 183 | expect![[r#" |
184 | fn foo(&self, x: i32) | 184 | fn foo(&self, x: i32) |
@@ -196,7 +196,7 @@ impl S { | |||
196 | fn foo(&self, x: i32) {} | 196 | fn foo(&self, x: i32) {} |
197 | } | 197 | } |
198 | 198 | ||
199 | fn main() { S::foo(<|>); } | 199 | fn main() { S::foo($0); } |
200 | "#, | 200 | "#, |
201 | expect![[r#" | 201 | expect![[r#" |
202 | fn foo(self: &S, x: i32) | 202 | fn foo(self: &S, x: i32) |
@@ -216,7 +216,7 @@ fn foo(j: u32) -> u32 { | |||
216 | } | 216 | } |
217 | 217 | ||
218 | fn bar() { | 218 | fn bar() { |
219 | let _ = foo(<|>); | 219 | let _ = foo($0); |
220 | } | 220 | } |
221 | "#, | 221 | "#, |
222 | expect![[r#" | 222 | expect![[r#" |
@@ -246,7 +246,7 @@ pub fn add_one(x: i32) -> i32 { | |||
246 | } | 246 | } |
247 | 247 | ||
248 | pub fn do() { | 248 | pub fn do() { |
249 | add_one(<|> | 249 | add_one($0 |
250 | }"#, | 250 | }"#, |
251 | expect![[r##" | 251 | expect![[r##" |
252 | Adds one to the number given. | 252 | Adds one to the number given. |
@@ -287,7 +287,7 @@ impl addr { | |||
287 | 287 | ||
288 | pub fn do_it() { | 288 | pub fn do_it() { |
289 | addr {}; | 289 | addr {}; |
290 | addr::add_one(<|>); | 290 | addr::add_one($0); |
291 | } | 291 | } |
292 | "#, | 292 | "#, |
293 | expect![[r##" | 293 | expect![[r##" |
@@ -331,7 +331,7 @@ impl<E> WriteHandler<E> { | |||
331 | } | 331 | } |
332 | 332 | ||
333 | pub fn foo(mut r: WriteHandler<()>) { | 333 | pub fn foo(mut r: WriteHandler<()>) { |
334 | r.finished(<|>); | 334 | r.finished($0); |
335 | } | 335 | } |
336 | "#, | 336 | "#, |
337 | expect![[r#" | 337 | expect![[r#" |
@@ -351,7 +351,7 @@ fn call_info_bad_offset() { | |||
351 | check( | 351 | check( |
352 | r#" | 352 | r#" |
353 | fn foo(x: u32, y: u32) -> u32 {x + y} | 353 | fn foo(x: u32, y: u32) -> u32 {x + y} |
354 | fn bar() { foo <|> (3, ); } | 354 | fn bar() { foo $0 (3, ); } |
355 | "#, | 355 | "#, |
356 | expect![[""]], | 356 | expect![[""]], |
357 | ); | 357 | ); |
@@ -368,7 +368,7 @@ fn bar(_: u32) { } | |||
368 | 368 | ||
369 | fn main() { | 369 | fn main() { |
370 | let foo = Foo; | 370 | let foo = Foo; |
371 | std::thread::spawn(move || foo.bar(<|>)); | 371 | std::thread::spawn(move || foo.bar($0)); |
372 | } | 372 | } |
373 | "#, | 373 | "#, |
374 | expect![[r#" | 374 | expect![[r#" |
@@ -385,7 +385,7 @@ fn works_for_tuple_structs() { | |||
385 | /// A cool tuple struct | 385 | /// A cool tuple struct |
386 | struct S(u32, i32); | 386 | struct S(u32, i32); |
387 | fn main() { | 387 | fn main() { |
388 | let s = S(0, <|>); | 388 | let s = S(0, $0); |
389 | } | 389 | } |
390 | "#, | 390 | "#, |
391 | expect![[r#" | 391 | expect![[r#" |
@@ -403,7 +403,7 @@ fn generic_struct() { | |||
403 | r#" | 403 | r#" |
404 | struct S<T>(T); | 404 | struct S<T>(T); |
405 | fn main() { | 405 | fn main() { |
406 | let s = S(<|>); | 406 | let s = S($0); |
407 | } | 407 | } |
408 | "#, | 408 | "#, |
409 | expect![[r#" | 409 | expect![[r#" |
@@ -427,7 +427,7 @@ enum E { | |||
427 | } | 427 | } |
428 | 428 | ||
429 | fn main() { | 429 | fn main() { |
430 | let a = E::A(<|>); | 430 | let a = E::A($0); |
431 | } | 431 | } |
432 | "#, | 432 | "#, |
433 | expect![[r#" | 433 | expect![[r#" |
@@ -445,7 +445,7 @@ fn cant_call_struct_record() { | |||
445 | r#" | 445 | r#" |
446 | struct S { x: u32, y: i32 } | 446 | struct S { x: u32, y: i32 } |
447 | fn main() { | 447 | fn main() { |
448 | let s = S(<|>); | 448 | let s = S($0); |
449 | } | 449 | } |
450 | "#, | 450 | "#, |
451 | expect![[""]], | 451 | expect![[""]], |
@@ -466,7 +466,7 @@ enum E { | |||
466 | } | 466 | } |
467 | 467 | ||
468 | fn main() { | 468 | fn main() { |
469 | let a = E::C(<|>); | 469 | let a = E::C($0); |
470 | } | 470 | } |
471 | "#, | 471 | "#, |
472 | expect![[""]], | 472 | expect![[""]], |
@@ -480,7 +480,7 @@ fn fn_signature_for_call_in_macro() { | |||
480 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | 480 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
481 | fn foo() { } | 481 | fn foo() { } |
482 | id! { | 482 | id! { |
483 | fn bar() { foo(<|>); } | 483 | fn bar() { foo($0); } |
484 | } | 484 | } |
485 | "#, | 485 | "#, |
486 | expect![[r#" | 486 | expect![[r#" |
@@ -497,7 +497,7 @@ fn call_info_for_lambdas() { | |||
497 | struct S; | 497 | struct S; |
498 | fn foo(s: S) -> i32 { 92 } | 498 | fn foo(s: S) -> i32 { 92 } |
499 | fn main() { | 499 | fn main() { |
500 | (|s| foo(s))(<|>) | 500 | (|s| foo(s))($0) |
501 | } | 501 | } |
502 | "#, | 502 | "#, |
503 | expect![[r#" | 503 | expect![[r#" |
@@ -512,7 +512,7 @@ fn call_info_for_fn_ptr() { | |||
512 | check( | 512 | check( |
513 | r#" | 513 | r#" |
514 | fn main(f: fn(i32, f64) -> char) { | 514 | fn main(f: fn(i32, f64) -> char) { |
515 | f(0, <|>) | 515 | f(0, $0) |
516 | } | 516 | } |
517 | "#, | 517 | "#, |
518 | expect![[r#" | 518 | expect![[r#" |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index d33a6cb86..d68fe42b0 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, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, | 9 | db::HirDatabase, Crate, Field, GenericParam, HasVisibility, Impl, Label, Local, MacroDef, |
10 | Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, | 10 | Module, ModuleDef, Name, PathResolution, Semantics, Visibility, |
11 | }; | 11 | }; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode}, | 13 | ast::{self, AstNode}, |
@@ -24,8 +24,7 @@ pub enum Definition { | |||
24 | ModuleDef(ModuleDef), | 24 | ModuleDef(ModuleDef), |
25 | SelfType(Impl), | 25 | SelfType(Impl), |
26 | Local(Local), | 26 | Local(Local), |
27 | TypeParam(TypeParam), | 27 | GenericParam(GenericParam), |
28 | LifetimeParam(LifetimeParam), | ||
29 | Label(Label), | 28 | Label(Label), |
30 | } | 29 | } |
31 | 30 | ||
@@ -37,8 +36,7 @@ impl Definition { | |||
37 | Definition::ModuleDef(it) => it.module(db), | 36 | Definition::ModuleDef(it) => it.module(db), |
38 | Definition::SelfType(it) => Some(it.module(db)), | 37 | Definition::SelfType(it) => Some(it.module(db)), |
39 | Definition::Local(it) => Some(it.module(db)), | 38 | Definition::Local(it) => Some(it.module(db)), |
40 | Definition::TypeParam(it) => Some(it.module(db)), | 39 | Definition::GenericParam(it) => Some(it.module(db)), |
41 | Definition::LifetimeParam(it) => Some(it.module(db)), | ||
42 | Definition::Label(it) => Some(it.module(db)), | 40 | Definition::Label(it) => Some(it.module(db)), |
43 | } | 41 | } |
44 | } | 42 | } |
@@ -50,8 +48,7 @@ impl Definition { | |||
50 | Definition::ModuleDef(def) => def.definition_visibility(db), | 48 | Definition::ModuleDef(def) => def.definition_visibility(db), |
51 | Definition::SelfType(_) => None, | 49 | Definition::SelfType(_) => None, |
52 | Definition::Local(_) => None, | 50 | Definition::Local(_) => None, |
53 | Definition::TypeParam(_) => None, | 51 | Definition::GenericParam(_) => None, |
54 | Definition::LifetimeParam(_) => None, | ||
55 | Definition::Label(_) => None, | 52 | Definition::Label(_) => None, |
56 | } | 53 | } |
57 | } | 54 | } |
@@ -77,8 +74,7 @@ impl Definition { | |||
77 | }, | 74 | }, |
78 | Definition::SelfType(_) => return None, | 75 | Definition::SelfType(_) => return None, |
79 | Definition::Local(it) => it.name(db)?, | 76 | Definition::Local(it) => it.name(db)?, |
80 | Definition::TypeParam(it) => it.name(db), | 77 | Definition::GenericParam(it) => it.name(db), |
81 | Definition::LifetimeParam(it) => it.name(db), | ||
82 | Definition::Label(it) => it.name(db), | 78 | Definition::Label(it) => it.name(db), |
83 | }; | 79 | }; |
84 | Some(name) | 80 | Some(name) |
@@ -231,7 +227,11 @@ impl NameClass { | |||
231 | }, | 227 | }, |
232 | ast::TypeParam(it) => { | 228 | ast::TypeParam(it) => { |
233 | let def = sema.to_def(&it)?; | 229 | let def = sema.to_def(&it)?; |
234 | Some(NameClass::Definition(Definition::TypeParam(def))) | 230 | Some(NameClass::Definition(Definition::GenericParam(def.into()))) |
231 | }, | ||
232 | ast::ConstParam(it) => { | ||
233 | let def = sema.to_def(&it)?; | ||
234 | Some(NameClass::Definition(Definition::GenericParam(def.into()))) | ||
235 | }, | 235 | }, |
236 | _ => None, | 236 | _ => None, |
237 | } | 237 | } |
@@ -249,7 +249,7 @@ impl NameClass { | |||
249 | match parent { | 249 | match parent { |
250 | ast::LifetimeParam(it) => { | 250 | ast::LifetimeParam(it) => { |
251 | let def = sema.to_def(&it)?; | 251 | let def = sema.to_def(&it)?; |
252 | Some(NameClass::Definition(Definition::LifetimeParam(def))) | 252 | Some(NameClass::Definition(Definition::GenericParam(def.into()))) |
253 | }, | 253 | }, |
254 | ast::Label(it) => { | 254 | ast::Label(it) => { |
255 | let def = sema.to_def(&it)?; | 255 | let def = sema.to_def(&it)?; |
@@ -350,7 +350,7 @@ impl NameRefClass { | |||
350 | if let Some(path) = macro_call.path() { | 350 | if let Some(path) = macro_call.path() { |
351 | if path.qualifier().is_none() { | 351 | if path.qualifier().is_none() { |
352 | // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment | 352 | // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment |
353 | // paths are handled below (allowing `log<|>::info!` to resolve to the log crate). | 353 | // paths are handled below (allowing `log$0::info!` to resolve to the log crate). |
354 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { | 354 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { |
355 | return Some(NameRefClass::Definition(Definition::Macro(macro_def))); | 355 | return Some(NameRefClass::Definition(Definition::Macro(macro_def))); |
356 | } | 356 | } |
@@ -385,7 +385,8 @@ impl NameRefClass { | |||
385 | | SyntaxKind::WHERE_PRED | 385 | | SyntaxKind::WHERE_PRED |
386 | | SyntaxKind::REF_TYPE => sema | 386 | | SyntaxKind::REF_TYPE => sema |
387 | .resolve_lifetime_param(lifetime) | 387 | .resolve_lifetime_param(lifetime) |
388 | .map(Definition::LifetimeParam) | 388 | .map(GenericParam::LifetimeParam) |
389 | .map(Definition::GenericParam) | ||
389 | .map(NameRefClass::Definition), | 390 | .map(NameRefClass::Definition), |
390 | // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check | 391 | // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check |
391 | // if our lifetime is in a LifetimeParam without being the constrained lifetime | 392 | // if our lifetime is in a LifetimeParam without being the constrained lifetime |
@@ -393,7 +394,8 @@ impl NameRefClass { | |||
393 | != Some(lifetime) => | 394 | != Some(lifetime) => |
394 | { | 395 | { |
395 | sema.resolve_lifetime_param(lifetime) | 396 | sema.resolve_lifetime_param(lifetime) |
396 | .map(Definition::LifetimeParam) | 397 | .map(GenericParam::LifetimeParam) |
398 | .map(Definition::GenericParam) | ||
397 | .map(NameRefClass::Definition) | 399 | .map(NameRefClass::Definition) |
398 | } | 400 | } |
399 | _ => None, | 401 | _ => None, |
@@ -414,9 +416,10 @@ impl From<PathResolution> for Definition { | |||
414 | Definition::ModuleDef(def) | 416 | Definition::ModuleDef(def) |
415 | } | 417 | } |
416 | PathResolution::Local(local) => Definition::Local(local), | 418 | PathResolution::Local(local) => Definition::Local(local), |
417 | PathResolution::TypeParam(par) => Definition::TypeParam(par), | 419 | PathResolution::TypeParam(par) => Definition::GenericParam(par.into()), |
418 | PathResolution::Macro(def) => Definition::Macro(def), | 420 | PathResolution::Macro(def) => Definition::Macro(def), |
419 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), | 421 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), |
422 | PathResolution::ConstParam(par) => Definition::GenericParam(par.into()), | ||
420 | } | 423 | } |
421 | } | 424 | } |
422 | } | 425 | } |
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index d988588ff..c6763ae36 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs | |||
@@ -1,9 +1,10 @@ | |||
1 | //! A module with ide helpers for high-level ide features. | 1 | //! A module with ide helpers for high-level ide features. |
2 | use crate::RootDatabase; | 2 | pub mod insert_use; |
3 | |||
3 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; | 4 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; |
4 | use syntax::ast::{self, make}; | 5 | use syntax::ast::{self, make}; |
5 | 6 | ||
6 | pub mod insert_use; | 7 | use crate::RootDatabase; |
7 | 8 | ||
8 | /// Converts the mod path struct into its ast representation. | 9 | /// Converts the mod path struct into its ast representation. |
9 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { | 10 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { |
@@ -37,94 +38,7 @@ pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Cr | |||
37 | 38 | ||
38 | #[allow(non_snake_case)] | 39 | #[allow(non_snake_case)] |
39 | impl FamousDefs<'_, '_> { | 40 | impl FamousDefs<'_, '_> { |
40 | pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core | 41 | pub const FIXTURE: &'static str = include_str!("helpers/famous_defs_fixture.rs"); |
41 | pub mod convert { | ||
42 | pub trait From<T> { | ||
43 | fn from(t: T) -> Self; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | pub mod default { | ||
48 | pub trait Default { | ||
49 | fn default() -> Self; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | pub mod iter { | ||
54 | pub use self::traits::{collect::IntoIterator, iterator::Iterator}; | ||
55 | mod traits { | ||
56 | pub(crate) mod iterator { | ||
57 | use crate::option::Option; | ||
58 | pub trait Iterator { | ||
59 | type Item; | ||
60 | fn next(&mut self) -> Option<Self::Item>; | ||
61 | fn by_ref(&mut self) -> &mut Self { | ||
62 | self | ||
63 | } | ||
64 | fn take(self, n: usize) -> crate::iter::Take<Self> { | ||
65 | crate::iter::Take { inner: self } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | impl<I: Iterator> Iterator for &mut I { | ||
70 | type Item = I::Item; | ||
71 | fn next(&mut self) -> Option<I::Item> { | ||
72 | (**self).next() | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | pub(crate) mod collect { | ||
77 | pub trait IntoIterator { | ||
78 | type Item; | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | pub use self::sources::*; | ||
84 | pub(crate) mod sources { | ||
85 | use super::Iterator; | ||
86 | use crate::option::Option::{self, *}; | ||
87 | pub struct Repeat<A> { | ||
88 | element: A, | ||
89 | } | ||
90 | |||
91 | pub fn repeat<T>(elt: T) -> Repeat<T> { | ||
92 | Repeat { element: elt } | ||
93 | } | ||
94 | |||
95 | impl<A> Iterator for Repeat<A> { | ||
96 | type Item = A; | ||
97 | |||
98 | fn next(&mut self) -> Option<A> { | ||
99 | None | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | pub use self::adapters::*; | ||
105 | pub(crate) mod adapters { | ||
106 | use super::Iterator; | ||
107 | use crate::option::Option::{self, *}; | ||
108 | pub struct Take<I> { pub(crate) inner: I } | ||
109 | impl<I> Iterator for Take<I> where I: Iterator { | ||
110 | type Item = <I as Iterator>::Item; | ||
111 | fn next(&mut self) -> Option<<I as Iterator>::Item> { | ||
112 | None | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | pub mod option { | ||
119 | pub enum Option<T> { None, Some(T)} | ||
120 | } | ||
121 | |||
122 | pub mod prelude { | ||
123 | pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default}; | ||
124 | } | ||
125 | #[prelude_import] | ||
126 | pub use prelude::*; | ||
127 | "#; | ||
128 | 42 | ||
129 | pub fn core(&self) -> Option<Crate> { | 43 | pub fn core(&self) -> Option<Crate> { |
130 | self.find_crate("core") | 44 | self.find_crate("core") |
@@ -201,3 +115,18 @@ pub use prelude::*; | |||
201 | Some(def) | 115 | Some(def) |
202 | } | 116 | } |
203 | } | 117 | } |
118 | |||
119 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
120 | pub struct SnippetCap { | ||
121 | _private: (), | ||
122 | } | ||
123 | |||
124 | impl SnippetCap { | ||
125 | pub const fn new(allow_snippets: bool) -> Option<SnippetCap> { | ||
126 | if allow_snippets { | ||
127 | Some(SnippetCap { _private: () }) | ||
128 | } else { | ||
129 | None | ||
130 | } | ||
131 | } | ||
132 | } | ||
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs new file mode 100644 index 000000000..5e88de64d --- /dev/null +++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs | |||
@@ -0,0 +1,120 @@ | |||
1 | //- /libcore.rs crate:core | ||
2 | //! Signatures of traits, types and functions from the core lib for use in tests. | ||
3 | pub mod convert { | ||
4 | pub trait From<T> { | ||
5 | fn from(t: T) -> Self; | ||
6 | } | ||
7 | } | ||
8 | |||
9 | pub mod default { | ||
10 | pub trait Default { | ||
11 | fn default() -> Self; | ||
12 | } | ||
13 | } | ||
14 | |||
15 | pub mod iter { | ||
16 | pub use self::traits::{collect::IntoIterator, iterator::Iterator}; | ||
17 | mod traits { | ||
18 | pub(crate) mod iterator { | ||
19 | use crate::option::Option; | ||
20 | pub trait Iterator { | ||
21 | type Item; | ||
22 | fn next(&mut self) -> Option<Self::Item>; | ||
23 | fn by_ref(&mut self) -> &mut Self { | ||
24 | self | ||
25 | } | ||
26 | fn take(self, n: usize) -> crate::iter::Take<Self> { | ||
27 | crate::iter::Take { inner: self } | ||
28 | } | ||
29 | } | ||
30 | |||
31 | impl<I: Iterator> Iterator for &mut I { | ||
32 | type Item = I::Item; | ||
33 | fn next(&mut self) -> Option<I::Item> { | ||
34 | (**self).next() | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | pub(crate) mod collect { | ||
39 | pub trait IntoIterator { | ||
40 | type Item; | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | pub use self::sources::*; | ||
46 | pub(crate) mod sources { | ||
47 | use super::Iterator; | ||
48 | use crate::option::Option::{self, *}; | ||
49 | pub struct Repeat<A> { | ||
50 | element: A, | ||
51 | } | ||
52 | |||
53 | pub fn repeat<T>(elt: T) -> Repeat<T> { | ||
54 | Repeat { element: elt } | ||
55 | } | ||
56 | |||
57 | impl<A> Iterator for Repeat<A> { | ||
58 | type Item = A; | ||
59 | |||
60 | fn next(&mut self) -> Option<A> { | ||
61 | None | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | |||
66 | pub use self::adapters::*; | ||
67 | pub(crate) mod adapters { | ||
68 | use super::Iterator; | ||
69 | use crate::option::Option::{self, *}; | ||
70 | pub struct Take<I> { | ||
71 | pub(crate) inner: I, | ||
72 | } | ||
73 | impl<I> Iterator for Take<I> | ||
74 | where | ||
75 | I: Iterator, | ||
76 | { | ||
77 | type Item = <I as Iterator>::Item; | ||
78 | fn next(&mut self) -> Option<<I as Iterator>::Item> { | ||
79 | None | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | pub mod ops { | ||
86 | #[lang = "fn"] | ||
87 | pub trait Fn<Args>: FnMut<Args> { | ||
88 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
89 | } | ||
90 | |||
91 | #[lang = "fn_mut"] | ||
92 | pub trait FnMut<Args>: FnOnce<Args> { | ||
93 | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; | ||
94 | } | ||
95 | #[lang = "fn_once"] | ||
96 | pub trait FnOnce<Args> { | ||
97 | #[lang = "fn_once_output"] | ||
98 | type Output; | ||
99 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | pub mod option { | ||
104 | pub enum Option<T> { | ||
105 | None, | ||
106 | Some(T), | ||
107 | } | ||
108 | } | ||
109 | |||
110 | pub mod prelude { | ||
111 | pub use crate::{ | ||
112 | convert::From, | ||
113 | default::Default, | ||
114 | iter::{IntoIterator, Iterator}, | ||
115 | ops::{Fn, FnMut, FnOnce}, | ||
116 | option::Option::{self, *}, | ||
117 | }; | ||
118 | } | ||
119 | #[prelude_import] | ||
120 | pub use prelude::*; | ||
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index 0f4c2ca47..e9f23adf8 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the assists module. | 1 | //! This module contains an import search functionality that is provided to the assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. |
3 | 3 | ||
4 | use hir::{import_map, Crate, MacroDef, ModuleDef, Semantics}; | 4 | use hir::{import_map, AsAssocItem, Crate, MacroDef, ModuleDef, Semantics}; |
5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; | 5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
@@ -40,8 +40,9 @@ pub fn find_similar_imports<'a>( | |||
40 | krate: Crate, | 40 | krate: Crate, |
41 | limit: Option<usize>, | 41 | limit: Option<usize>, |
42 | fuzzy_search_string: String, | 42 | fuzzy_search_string: String, |
43 | ignore_assoc_items: bool, | ||
43 | name_only: bool, | 44 | name_only: bool, |
44 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 45 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a { |
45 | let _p = profile::span("find_similar_imports"); | 46 | let _p = profile::span("find_similar_imports"); |
46 | 47 | ||
47 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) | 48 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) |
@@ -57,7 +58,21 @@ pub fn find_similar_imports<'a>( | |||
57 | external_query = external_query.limit(limit); | 58 | external_query = external_query.limit(limit); |
58 | } | 59 | } |
59 | 60 | ||
60 | find_imports(sema, krate, local_query, external_query) | 61 | let db = sema.db; |
62 | find_imports(sema, krate, local_query, external_query).filter(move |import_candidate| { | ||
63 | if ignore_assoc_items { | ||
64 | match import_candidate { | ||
65 | Either::Left(ModuleDef::Function(function)) => function.as_assoc_item(db).is_none(), | ||
66 | Either::Left(ModuleDef::Const(const_)) => const_.as_assoc_item(db).is_none(), | ||
67 | Either::Left(ModuleDef::TypeAlias(type_alias)) => { | ||
68 | type_alias.as_assoc_item(db).is_none() | ||
69 | } | ||
70 | _ => true, | ||
71 | } | ||
72 | } else { | ||
73 | true | ||
74 | } | ||
75 | }) | ||
61 | } | 76 | } |
62 | 77 | ||
63 | fn find_imports<'a>( | 78 | fn find_imports<'a>( |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index ff10f71c3..b5fa46642 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -18,9 +18,43 @@ use crate::{ | |||
18 | RootDatabase, | 18 | RootDatabase, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | #[derive(Debug, Default, Clone)] | ||
22 | pub struct UsageSearchResult { | ||
23 | pub references: FxHashMap<FileId, Vec<FileReference>>, | ||
24 | } | ||
25 | |||
26 | impl UsageSearchResult { | ||
27 | pub fn is_empty(&self) -> bool { | ||
28 | self.references.is_empty() | ||
29 | } | ||
30 | |||
31 | pub fn len(&self) -> usize { | ||
32 | self.references.len() | ||
33 | } | ||
34 | |||
35 | pub fn iter(&self) -> impl Iterator<Item = (&FileId, &Vec<FileReference>)> + '_ { | ||
36 | self.references.iter() | ||
37 | } | ||
38 | |||
39 | pub fn file_ranges(&self) -> impl Iterator<Item = FileRange> + '_ { | ||
40 | self.references.iter().flat_map(|(&file_id, refs)| { | ||
41 | refs.iter().map(move |&FileReference { range, .. }| FileRange { file_id, range }) | ||
42 | }) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | impl IntoIterator for UsageSearchResult { | ||
47 | type Item = (FileId, Vec<FileReference>); | ||
48 | type IntoIter = <FxHashMap<FileId, Vec<FileReference>> as IntoIterator>::IntoIter; | ||
49 | |||
50 | fn into_iter(self) -> Self::IntoIter { | ||
51 | self.references.into_iter() | ||
52 | } | ||
53 | } | ||
54 | |||
21 | #[derive(Debug, Clone)] | 55 | #[derive(Debug, Clone)] |
22 | pub struct Reference { | 56 | pub struct FileReference { |
23 | pub file_range: FileRange, | 57 | pub range: TextRange, |
24 | pub kind: ReferenceKind, | 58 | pub kind: ReferenceKind, |
25 | pub access: Option<ReferenceAccess>, | 59 | pub access: Option<ReferenceAccess>, |
26 | } | 60 | } |
@@ -121,31 +155,55 @@ impl Definition { | |||
121 | 155 | ||
122 | if let Definition::Local(var) = self { | 156 | if let Definition::Local(var) = self { |
123 | let range = match var.parent(db) { | 157 | let range = match var.parent(db) { |
124 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), | 158 | DefWithBody::Function(f) => { |
125 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), | 159 | f.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
126 | DefWithBody::Static(s) => s.source(db).value.syntax().text_range(), | 160 | } |
161 | DefWithBody::Const(c) => { | ||
162 | c.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
163 | } | ||
164 | DefWithBody::Static(s) => { | ||
165 | s.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
166 | } | ||
127 | }; | 167 | }; |
128 | let mut res = FxHashMap::default(); | 168 | let mut res = FxHashMap::default(); |
129 | res.insert(file_id, Some(range)); | 169 | res.insert(file_id, range); |
130 | return SearchScope::new(res); | 170 | return SearchScope::new(res); |
131 | } | 171 | } |
132 | 172 | ||
133 | if let Definition::LifetimeParam(param) = self { | 173 | if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self { |
134 | let range = match param.parent(db) { | 174 | let range = match param.parent(db) { |
135 | hir::GenericDef::Function(it) => it.source(db).value.syntax().text_range(), | 175 | hir::GenericDef::Function(it) => { |
176 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
177 | } | ||
136 | hir::GenericDef::Adt(it) => match it { | 178 | hir::GenericDef::Adt(it) => match it { |
137 | hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(), | 179 | hir::Adt::Struct(it) => { |
138 | hir::Adt::Union(it) => it.source(db).value.syntax().text_range(), | 180 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
139 | hir::Adt::Enum(it) => it.source(db).value.syntax().text_range(), | 181 | } |
182 | hir::Adt::Union(it) => { | ||
183 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
184 | } | ||
185 | hir::Adt::Enum(it) => { | ||
186 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
187 | } | ||
140 | }, | 188 | }, |
141 | hir::GenericDef::Trait(it) => it.source(db).value.syntax().text_range(), | 189 | hir::GenericDef::Trait(it) => { |
142 | hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(), | 190 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
143 | hir::GenericDef::Impl(it) => it.source(db).value.syntax().text_range(), | 191 | } |
144 | hir::GenericDef::Variant(it) => it.source(db).value.syntax().text_range(), | 192 | hir::GenericDef::TypeAlias(it) => { |
145 | hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(), | 193 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
194 | } | ||
195 | hir::GenericDef::Impl(it) => { | ||
196 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
197 | } | ||
198 | hir::GenericDef::Variant(it) => { | ||
199 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
200 | } | ||
201 | hir::GenericDef::Const(it) => { | ||
202 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
203 | } | ||
146 | }; | 204 | }; |
147 | let mut res = FxHashMap::default(); | 205 | let mut res = FxHashMap::default(); |
148 | res.insert(file_id, Some(range)); | 206 | res.insert(file_id, range); |
149 | return SearchScope::new(res); | 207 | return SearchScope::new(res); |
150 | } | 208 | } |
151 | 209 | ||
@@ -228,23 +286,23 @@ impl<'a> FindUsages<'a> { | |||
228 | 286 | ||
229 | pub fn at_least_one(self) -> bool { | 287 | pub fn at_least_one(self) -> bool { |
230 | let mut found = false; | 288 | let mut found = false; |
231 | self.search(&mut |_reference| { | 289 | self.search(&mut |_, _| { |
232 | found = true; | 290 | found = true; |
233 | true | 291 | true |
234 | }); | 292 | }); |
235 | found | 293 | found |
236 | } | 294 | } |
237 | 295 | ||
238 | pub fn all(self) -> Vec<Reference> { | 296 | pub fn all(self) -> UsageSearchResult { |
239 | let mut res = Vec::new(); | 297 | let mut res = UsageSearchResult::default(); |
240 | self.search(&mut |reference| { | 298 | self.search(&mut |file_id, reference| { |
241 | res.push(reference); | 299 | res.references.entry(file_id).or_default().push(reference); |
242 | false | 300 | false |
243 | }); | 301 | }); |
244 | res | 302 | res |
245 | } | 303 | } |
246 | 304 | ||
247 | fn search(self, sink: &mut dyn FnMut(Reference) -> bool) { | 305 | fn search(self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) { |
248 | let _p = profile::span("FindUsages:search"); | 306 | let _p = profile::span("FindUsages:search"); |
249 | let sema = self.sema; | 307 | let sema = self.sema; |
250 | 308 | ||
@@ -296,16 +354,14 @@ impl<'a> FindUsages<'a> { | |||
296 | fn found_lifetime( | 354 | fn found_lifetime( |
297 | &self, | 355 | &self, |
298 | lifetime: &ast::Lifetime, | 356 | lifetime: &ast::Lifetime, |
299 | sink: &mut dyn FnMut(Reference) -> bool, | 357 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, |
300 | ) -> bool { | 358 | ) -> bool { |
301 | match NameRefClass::classify_lifetime(self.sema, lifetime) { | 359 | match NameRefClass::classify_lifetime(self.sema, lifetime) { |
302 | Some(NameRefClass::Definition(def)) if &def == self.def => { | 360 | Some(NameRefClass::Definition(def)) if &def == self.def => { |
303 | let reference = Reference { | 361 | let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); |
304 | file_range: self.sema.original_range(lifetime.syntax()), | 362 | let reference = |
305 | kind: ReferenceKind::Lifetime, | 363 | FileReference { range, kind: ReferenceKind::Lifetime, access: None }; |
306 | access: None, | 364 | sink(file_id, reference) |
307 | }; | ||
308 | sink(reference) | ||
309 | } | 365 | } |
310 | _ => false, // not a usage | 366 | _ => false, // not a usage |
311 | } | 367 | } |
@@ -314,7 +370,7 @@ impl<'a> FindUsages<'a> { | |||
314 | fn found_name_ref( | 370 | fn found_name_ref( |
315 | &self, | 371 | &self, |
316 | name_ref: &ast::NameRef, | 372 | name_ref: &ast::NameRef, |
317 | sink: &mut dyn FnMut(Reference) -> bool, | 373 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, |
318 | ) -> bool { | 374 | ) -> bool { |
319 | match NameRefClass::classify(self.sema, &name_ref) { | 375 | match NameRefClass::classify(self.sema, &name_ref) { |
320 | Some(NameRefClass::Definition(def)) if &def == self.def => { | 376 | Some(NameRefClass::Definition(def)) if &def == self.def => { |
@@ -328,46 +384,50 @@ impl<'a> FindUsages<'a> { | |||
328 | ReferenceKind::Other | 384 | ReferenceKind::Other |
329 | }; | 385 | }; |
330 | 386 | ||
331 | let reference = Reference { | 387 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); |
332 | file_range: self.sema.original_range(name_ref.syntax()), | 388 | let reference = |
333 | kind, | 389 | FileReference { range, kind, access: reference_access(&def, &name_ref) }; |
334 | access: reference_access(&def, &name_ref), | 390 | sink(file_id, reference) |
335 | }; | ||
336 | sink(reference) | ||
337 | } | 391 | } |
338 | Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { | 392 | Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { |
393 | let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); | ||
339 | let reference = match self.def { | 394 | let reference = match self.def { |
340 | Definition::Field(_) if &field == self.def => Reference { | 395 | Definition::Field(_) if &field == self.def => FileReference { |
341 | file_range: self.sema.original_range(name_ref.syntax()), | 396 | range, |
342 | kind: ReferenceKind::FieldShorthandForField, | 397 | kind: ReferenceKind::FieldShorthandForField, |
343 | access: reference_access(&field, &name_ref), | 398 | access: reference_access(&field, &name_ref), |
344 | }, | 399 | }, |
345 | Definition::Local(l) if &local == l => Reference { | 400 | Definition::Local(l) if &local == l => FileReference { |
346 | file_range: self.sema.original_range(name_ref.syntax()), | 401 | range, |
347 | kind: ReferenceKind::FieldShorthandForLocal, | 402 | kind: ReferenceKind::FieldShorthandForLocal, |
348 | access: reference_access(&Definition::Local(local), &name_ref), | 403 | access: reference_access(&Definition::Local(local), &name_ref), |
349 | }, | 404 | }, |
350 | _ => return false, // not a usage | 405 | _ => return false, // not a usage |
351 | }; | 406 | }; |
352 | sink(reference) | 407 | sink(file_id, reference) |
353 | } | 408 | } |
354 | _ => false, // not a usage | 409 | _ => false, // not a usage |
355 | } | 410 | } |
356 | } | 411 | } |
357 | 412 | ||
358 | fn found_name(&self, name: &ast::Name, sink: &mut dyn FnMut(Reference) -> bool) -> bool { | 413 | fn found_name( |
414 | &self, | ||
415 | name: &ast::Name, | ||
416 | sink: &mut dyn FnMut(FileId, FileReference) -> bool, | ||
417 | ) -> bool { | ||
359 | match NameClass::classify(self.sema, name) { | 418 | match NameClass::classify(self.sema, name) { |
360 | Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) => { | 419 | Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) => { |
361 | let reference = match self.def { | 420 | if !matches!(self.def, Definition::Field(_) if &field_ref == self.def) { |
362 | Definition::Field(_) if &field_ref == self.def => Reference { | 421 | return false; |
363 | file_range: self.sema.original_range(name.syntax()), | 422 | } |
364 | kind: ReferenceKind::FieldShorthandForField, | 423 | let FileRange { file_id, range } = self.sema.original_range(name.syntax()); |
365 | // FIXME: mutable patterns should have `Write` access | 424 | let reference = FileReference { |
366 | access: Some(ReferenceAccess::Read), | 425 | range, |
367 | }, | 426 | kind: ReferenceKind::FieldShorthandForField, |
368 | _ => return false, // not a usage | 427 | // FIXME: mutable patterns should have `Write` access |
428 | access: Some(ReferenceAccess::Read), | ||
369 | }; | 429 | }; |
370 | sink(reference) | 430 | sink(file_id, reference) |
371 | } | 431 | } |
372 | _ => false, // not a usage | 432 | _ => false, // not a usage |
373 | } | 433 | } |
diff --git a/crates/ide_db/src/traits/tests.rs b/crates/ide_db/src/traits/tests.rs index 09c7ac3ec..84bb25505 100644 --- a/crates/ide_db/src/traits/tests.rs +++ b/crates/ide_db/src/traits/tests.rs | |||
@@ -5,12 +5,12 @@ use hir::Semantics; | |||
5 | use syntax::ast::{self, AstNode}; | 5 | use syntax::ast::{self, AstNode}; |
6 | use test_utils::RangeOrOffset; | 6 | use test_utils::RangeOrOffset; |
7 | 7 | ||
8 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 8 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
9 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 9 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { |
10 | let change_fixture = ChangeFixture::parse(ra_fixture); | 10 | let change_fixture = ChangeFixture::parse(ra_fixture); |
11 | let mut database = RootDatabase::default(); | 11 | let mut database = RootDatabase::default(); |
12 | database.apply_change(change_fixture.change); | 12 | database.apply_change(change_fixture.change); |
13 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | 13 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
14 | let offset = match range_or_offset { | 14 | let offset = match range_or_offset { |
15 | RangeOrOffset::Range(_) => panic!(), | 15 | RangeOrOffset::Range(_) => panic!(), |
16 | RangeOrOffset::Offset(it) => it, | 16 | RangeOrOffset::Offset(it) => it, |
@@ -55,7 +55,7 @@ pub trait Foo { | |||
55 | fn bar(); | 55 | fn bar(); |
56 | } | 56 | } |
57 | impl Foo for u8 { | 57 | impl Foo for u8 { |
58 | <|> | 58 | $0 |
59 | } | 59 | } |
60 | "#, | 60 | "#, |
61 | expect![["Foo"]], | 61 | expect![["Foo"]], |
@@ -68,7 +68,7 @@ pub trait Foo { | |||
68 | impl Foo for u8 { | 68 | impl Foo for u8 { |
69 | fn bar() { | 69 | fn bar() { |
70 | fn baz() { | 70 | fn baz() { |
71 | <|> | 71 | $0 |
72 | } | 72 | } |
73 | baz(); | 73 | baz(); |
74 | } | 74 | } |
@@ -83,7 +83,7 @@ pub trait Foo { | |||
83 | } | 83 | } |
84 | pub struct Bar; | 84 | pub struct Bar; |
85 | impl Bar { | 85 | impl Bar { |
86 | <|> | 86 | $0 |
87 | } | 87 | } |
88 | "#, | 88 | "#, |
89 | expect![[""]], | 89 | expect![[""]], |
@@ -99,7 +99,7 @@ pub trait Foo { | |||
99 | fn bar(); | 99 | fn bar(); |
100 | } | 100 | } |
101 | impl Foo for u8 { | 101 | impl Foo for u8 { |
102 | <|> | 102 | $0 |
103 | }"#, | 103 | }"#, |
104 | expect![[r#" | 104 | expect![[r#" |
105 | FOO | 105 | FOO |
@@ -114,7 +114,7 @@ pub trait Foo { | |||
114 | } | 114 | } |
115 | impl Foo for u8 { | 115 | impl Foo for u8 { |
116 | const FOO: u8 = 10; | 116 | const FOO: u8 = 10; |
117 | <|> | 117 | $0 |
118 | }"#, | 118 | }"#, |
119 | expect![[r#" | 119 | expect![[r#" |
120 | bar"#]], | 120 | bar"#]], |
@@ -128,7 +128,7 @@ pub trait Foo { | |||
128 | } | 128 | } |
129 | impl Foo for u8 { | 129 | impl Foo for u8 { |
130 | const FOO: u8 = 10; | 130 | const FOO: u8 = 10; |
131 | fn bar() {<|>} | 131 | fn bar() {$0} |
132 | }"#, | 132 | }"#, |
133 | expect![[r#""#]], | 133 | expect![[r#""#]], |
134 | ); | 134 | ); |
@@ -137,7 +137,7 @@ impl Foo for u8 { | |||
137 | r#" | 137 | r#" |
138 | pub struct Foo; | 138 | pub struct Foo; |
139 | impl Foo { | 139 | impl Foo { |
140 | fn bar() {<|>} | 140 | fn bar() {$0} |
141 | }"#, | 141 | }"#, |
142 | expect![[r#""#]], | 142 | expect![[r#""#]], |
143 | ); | 143 | ); |
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 7878faaa4..19543d777 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -24,7 +24,7 @@ use crate::{ | |||
24 | #[derive(Debug, PartialEq, Eq)] | 24 | #[derive(Debug, PartialEq, Eq)] |
25 | pub enum ParseError { | 25 | pub enum ParseError { |
26 | Expected(String), | 26 | Expected(String), |
27 | RepetitionEmtpyTokenTree, | 27 | RepetitionEmptyTokenTree, |
28 | } | 28 | } |
29 | 29 | ||
30 | #[derive(Debug, PartialEq, Eq, Clone)] | 30 | #[derive(Debug, PartialEq, Eq, Clone)] |
@@ -217,18 +217,14 @@ impl MacroRules { | |||
217 | 217 | ||
218 | impl Rule { | 218 | impl Rule { |
219 | fn parse(src: &mut TtIter) -> Result<Rule, ParseError> { | 219 | fn parse(src: &mut TtIter) -> Result<Rule, ParseError> { |
220 | let mut lhs = src | 220 | let lhs = src |
221 | .expect_subtree() | 221 | .expect_subtree() |
222 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? | 222 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; |
223 | .clone(); | ||
224 | lhs.delimiter = None; | ||
225 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; | 223 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; |
226 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; | 224 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; |
227 | let mut rhs = src | 225 | let rhs = src |
228 | .expect_subtree() | 226 | .expect_subtree() |
229 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? | 227 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; |
230 | .clone(); | ||
231 | rhs.delimiter = None; | ||
232 | 228 | ||
233 | let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None }; | 229 | let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None }; |
234 | let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None }; | 230 | let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None }; |
@@ -274,7 +270,7 @@ fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { | |||
274 | } | 270 | } |
275 | false | 271 | false |
276 | }) { | 272 | }) { |
277 | return Err(ParseError::RepetitionEmtpyTokenTree); | 273 | return Err(ParseError::RepetitionEmptyTokenTree); |
278 | } | 274 | } |
279 | } | 275 | } |
280 | validate(subtree)? | 276 | validate(subtree)? |
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index ab5f87c48..d32e60521 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs | |||
@@ -150,7 +150,7 @@ fn match_subtree( | |||
150 | res.add_err(err!("leftover tokens")); | 150 | res.add_err(err!("leftover tokens")); |
151 | } | 151 | } |
152 | } | 152 | } |
153 | Op::Var { name, kind } => { | 153 | Op::Var { name, kind, .. } => { |
154 | let kind = match kind { | 154 | let kind = match kind { |
155 | Some(k) => k, | 155 | Some(k) => k, |
156 | None => { | 156 | None => { |
@@ -309,7 +309,7 @@ impl<'a> TtIter<'a> { | |||
309 | } | 309 | } |
310 | } | 310 | } |
311 | 311 | ||
312 | let buffer = TokenBuffer::new(&self.inner.as_slice()); | 312 | let buffer = TokenBuffer::from_tokens(&self.inner.as_slice()); |
313 | let mut src = SubtreeTokenSource::new(&buffer); | 313 | let mut src = SubtreeTokenSource::new(&buffer); |
314 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; | 314 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; |
315 | 315 | ||
@@ -336,11 +336,11 @@ impl<'a> TtIter<'a> { | |||
336 | err = Some(err!("no tokens consumed")); | 336 | err = Some(err!("no tokens consumed")); |
337 | } | 337 | } |
338 | let res = match res.len() { | 338 | let res = match res.len() { |
339 | 1 => Some(res[0].clone()), | 339 | 1 => Some(res[0].cloned()), |
340 | 0 => None, | 340 | 0 => None, |
341 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { | 341 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { |
342 | delimiter: None, | 342 | delimiter: None, |
343 | token_trees: res.into_iter().cloned().collect(), | 343 | token_trees: res.into_iter().map(|it| it.cloned()).collect(), |
344 | })), | 344 | })), |
345 | }; | 345 | }; |
346 | ExpandResult { value: res, err } | 346 | ExpandResult { value: res, err } |
@@ -378,7 +378,7 @@ pub(super) fn match_repeat( | |||
378 | src: &mut TtIter, | 378 | src: &mut TtIter, |
379 | ) -> Result<(), ExpandError> { | 379 | ) -> Result<(), ExpandError> { |
380 | // Dirty hack to make macro-expansion terminate. | 380 | // Dirty hack to make macro-expansion terminate. |
381 | // This should be replaced by a propper macro-by-example implementation | 381 | // This should be replaced by a proper macro-by-example implementation |
382 | let mut limit = 65536; | 382 | let mut limit = 65536; |
383 | let mut counter = 0; | 383 | let mut counter = 0; |
384 | 384 | ||
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs index 720531237..59a3c80a8 100644 --- a/crates/mbe/src/mbe_expander/transcriber.rs +++ b/crates/mbe/src/mbe_expander/transcriber.rs | |||
@@ -67,7 +67,7 @@ struct NestingState { | |||
67 | /// because there is no variable in use by the current repetition | 67 | /// because there is no variable in use by the current repetition |
68 | hit: bool, | 68 | hit: bool, |
69 | /// `at_end` is currently necessary to tell `expand_repeat` if it should stop | 69 | /// `at_end` is currently necessary to tell `expand_repeat` if it should stop |
70 | /// because there is no more value avaible for the current repetition | 70 | /// because there is no more value available for the current repetition |
71 | at_end: bool, | 71 | at_end: bool, |
72 | } | 72 | } |
73 | 73 | ||
@@ -100,8 +100,8 @@ fn expand_subtree( | |||
100 | err = err.or(e); | 100 | err = err.or(e); |
101 | arena.push(tt.into()); | 101 | arena.push(tt.into()); |
102 | } | 102 | } |
103 | Op::Var { name, .. } => { | 103 | Op::Var { name, id, .. } => { |
104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name); | 104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id); |
105 | err = err.or(e); | 105 | err = err.or(e); |
106 | push_fragment(arena, fragment); | 106 | push_fragment(arena, fragment); |
107 | } | 107 | } |
@@ -118,14 +118,11 @@ fn expand_subtree( | |||
118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } | 118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } |
119 | } | 119 | } |
120 | 120 | ||
121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | 121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> { |
122 | if v == "crate" { | 122 | // We already handle $crate case in mbe parser |
123 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. | 123 | debug_assert!(v != "crate"); |
124 | let tt = | 124 | |
125 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) | 125 | if !ctx.bindings.contains(v) { |
126 | .into(); | ||
127 | ExpandResult::ok(Fragment::Tokens(tt)) | ||
128 | } else if !ctx.bindings.contains(v) { | ||
129 | // Note that it is possible to have a `$var` inside a macro which is not bound. | 126 | // Note that it is possible to have a `$var` inside a macro which is not bound. |
130 | // For example: | 127 | // For example: |
131 | // ``` | 128 | // ``` |
@@ -142,14 +139,8 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | |||
142 | let tt = tt::Subtree { | 139 | let tt = tt::Subtree { |
143 | delimiter: None, | 140 | delimiter: None, |
144 | token_trees: vec![ | 141 | token_trees: vec![ |
145 | tt::Leaf::from(tt::Punct { | 142 | tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(), |
146 | char: '$', | 143 | tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(), |
147 | spacing: tt::Spacing::Alone, | ||
148 | id: tt::TokenId::unspecified(), | ||
149 | }) | ||
150 | .into(), | ||
151 | tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) | ||
152 | .into(), | ||
153 | ], | 144 | ], |
154 | } | 145 | } |
155 | .into(); | 146 | .into(); |
@@ -188,11 +179,7 @@ fn expand_repeat( | |||
188 | 179 | ||
189 | counter += 1; | 180 | counter += 1; |
190 | if counter == limit { | 181 | if counter == limit { |
191 | log::warn!( | 182 | log::warn!("expand_tt in repeat pattern exceed limit => {:#?}\n{:#?}", template, ctx); |
192 | "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}", | ||
193 | template, | ||
194 | ctx | ||
195 | ); | ||
196 | break; | 183 | break; |
197 | } | 184 | } |
198 | 185 | ||
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index 2f3ebc831..f3047972d 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -8,7 +8,7 @@ use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; | |||
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub(crate) enum Op { | 10 | pub(crate) enum Op { |
11 | Var { name: SmolStr, kind: Option<SmolStr> }, | 11 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, |
12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, | 12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, |
13 | Leaf(tt::Leaf), | 13 | Leaf(tt::Leaf), |
14 | Subtree(MetaTemplate), | 14 | Subtree(MetaTemplate), |
@@ -106,18 +106,25 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul | |||
106 | } | 106 | } |
107 | let name = UNDERSCORE.clone(); | 107 | let name = UNDERSCORE.clone(); |
108 | let kind = eat_fragment_kind(src, mode)?; | 108 | let kind = eat_fragment_kind(src, mode)?; |
109 | Op::Var { name, kind } | 109 | let id = punct.id; |
110 | Op::Var { name, kind, id } | ||
111 | } | ||
112 | tt::Leaf::Ident(ident) if ident.text == "crate" => { | ||
113 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. | ||
114 | Op::Leaf(tt::Leaf::from(tt::Ident { text: "$crate".into(), id: ident.id })) | ||
110 | } | 115 | } |
111 | tt::Leaf::Ident(ident) => { | 116 | tt::Leaf::Ident(ident) => { |
112 | let name = ident.text.clone(); | 117 | let name = ident.text.clone(); |
113 | let kind = eat_fragment_kind(src, mode)?; | 118 | let kind = eat_fragment_kind(src, mode)?; |
114 | Op::Var { name, kind } | 119 | let id = ident.id; |
120 | Op::Var { name, kind, id } | ||
115 | } | 121 | } |
116 | tt::Leaf::Literal(lit) => { | 122 | tt::Leaf::Literal(lit) => { |
117 | if is_boolean_literal(&lit) { | 123 | if is_boolean_literal(&lit) { |
118 | let name = lit.text.clone(); | 124 | let name = lit.text.clone(); |
119 | let kind = eat_fragment_kind(src, mode)?; | 125 | let kind = eat_fragment_kind(src, mode)?; |
120 | Op::Var { name, kind } | 126 | let id = lit.id; |
127 | Op::Var { name, kind, id } | ||
121 | } else { | 128 | } else { |
122 | bail!("bad var 2"); | 129 | bail!("bad var 2"); |
123 | } | 130 | } |
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs index d10d4b70e..d7433bd35 100644 --- a/crates/mbe/src/subtree_source.rs +++ b/crates/mbe/src/subtree_source.rs | |||
@@ -1,129 +1,104 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use parser::{Token, TokenSource}; | 3 | use parser::{Token, TokenSource}; |
4 | use std::cell::{Cell, Ref, RefCell}; | ||
5 | use syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; | 4 | use syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; |
6 | use tt::buffer::{Cursor, TokenBuffer}; | 5 | use tt::buffer::TokenBuffer; |
7 | 6 | ||
8 | #[derive(Debug, Clone, Eq, PartialEq)] | 7 | #[derive(Debug, Clone, Eq, PartialEq)] |
9 | struct TtToken { | 8 | struct TtToken { |
10 | kind: SyntaxKind, | 9 | tt: Token, |
11 | is_joint_to_next: bool, | ||
12 | text: SmolStr, | 10 | text: SmolStr, |
13 | } | 11 | } |
14 | 12 | ||
15 | pub(crate) struct SubtreeTokenSource<'a> { | 13 | pub(crate) struct SubtreeTokenSource { |
16 | cached_cursor: Cell<Cursor<'a>>, | 14 | cached: Vec<TtToken>, |
17 | cached: RefCell<Vec<Option<TtToken>>>, | ||
18 | curr: (Token, usize), | 15 | curr: (Token, usize), |
19 | } | 16 | } |
20 | 17 | ||
21 | impl<'a> SubtreeTokenSource<'a> { | 18 | impl<'a> SubtreeTokenSource { |
22 | // Helper function used in test | 19 | // Helper function used in test |
23 | #[cfg(test)] | 20 | #[cfg(test)] |
24 | pub(crate) fn text(&self) -> SmolStr { | 21 | pub(crate) fn text(&self) -> SmolStr { |
25 | match *self.get(self.curr.1) { | 22 | match self.cached.get(self.curr.1) { |
26 | Some(ref tt) => tt.text.clone(), | 23 | Some(ref tt) => tt.text.clone(), |
27 | _ => SmolStr::new(""), | 24 | _ => SmolStr::new(""), |
28 | } | 25 | } |
29 | } | 26 | } |
30 | } | 27 | } |
31 | 28 | ||
32 | impl<'a> SubtreeTokenSource<'a> { | 29 | impl<'a> SubtreeTokenSource { |
33 | pub(crate) fn new(buffer: &'a TokenBuffer) -> SubtreeTokenSource<'a> { | 30 | pub(crate) fn new(buffer: &TokenBuffer) -> SubtreeTokenSource { |
34 | let cursor = buffer.begin(); | 31 | let mut current = buffer.begin(); |
32 | let mut cached = Vec::with_capacity(100); | ||
35 | 33 | ||
36 | let mut res = SubtreeTokenSource { | 34 | while !current.eof() { |
37 | curr: (Token { kind: EOF, is_jointed_to_next: false }, 0), | 35 | let cursor = current; |
38 | cached_cursor: Cell::new(cursor), | 36 | let tt = cursor.token_tree(); |
39 | cached: RefCell::new(Vec::with_capacity(10)), | ||
40 | }; | ||
41 | res.curr = (res.mk_token(0), 0); | ||
42 | res | ||
43 | } | ||
44 | 37 | ||
45 | fn mk_token(&self, pos: usize) -> Token { | 38 | // Check if it is lifetime |
46 | match *self.get(pos) { | 39 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = tt { |
47 | Some(ref tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next }, | ||
48 | None => Token { kind: EOF, is_jointed_to_next: false }, | ||
49 | } | ||
50 | } | ||
51 | |||
52 | fn get(&self, pos: usize) -> Ref<Option<TtToken>> { | ||
53 | fn is_lifetime(c: Cursor) -> Option<(Cursor, SmolStr)> { | ||
54 | let tkn = c.token_tree(); | ||
55 | |||
56 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tkn { | ||
57 | if punct.char == '\'' { | 40 | if punct.char == '\'' { |
58 | let next = c.bump(); | 41 | let next = cursor.bump(); |
59 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = next.token_tree() { | 42 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = |
60 | let res_cursor = next.bump(); | 43 | next.token_tree() |
61 | let text = SmolStr::new("'".to_string() + &ident.to_string()); | 44 | { |
62 | 45 | let text = SmolStr::new("'".to_string() + &ident.text); | |
63 | return Some((res_cursor, text)); | 46 | cached.push(TtToken { |
47 | tt: Token { kind: LIFETIME_IDENT, is_jointed_to_next: false }, | ||
48 | text, | ||
49 | }); | ||
50 | current = next.bump(); | ||
51 | continue; | ||
64 | } else { | 52 | } else { |
65 | panic!("Next token must be ident : {:#?}", next.token_tree()); | 53 | panic!("Next token must be ident : {:#?}", next.token_tree()); |
66 | } | 54 | } |
67 | } | 55 | } |
68 | } | 56 | } |
69 | 57 | ||
70 | None | 58 | current = match tt { |
71 | } | 59 | Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { |
72 | 60 | cached.push(convert_leaf(&leaf)); | |
73 | if pos < self.cached.borrow().len() { | 61 | cursor.bump() |
74 | return Ref::map(self.cached.borrow(), |c| &c[pos]); | ||
75 | } | ||
76 | |||
77 | { | ||
78 | let mut cached = self.cached.borrow_mut(); | ||
79 | while pos >= cached.len() { | ||
80 | let cursor = self.cached_cursor.get(); | ||
81 | if cursor.eof() { | ||
82 | cached.push(None); | ||
83 | continue; | ||
84 | } | 62 | } |
85 | 63 | Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { | |
86 | if let Some((curr, text)) = is_lifetime(cursor) { | 64 | cached.push(convert_delim(subtree.delimiter_kind(), false)); |
87 | cached.push(Some(TtToken { | 65 | cursor.subtree().unwrap() |
88 | kind: LIFETIME_IDENT, | ||
89 | is_joint_to_next: false, | ||
90 | text, | ||
91 | })); | ||
92 | self.cached_cursor.set(curr); | ||
93 | continue; | ||
94 | } | 66 | } |
95 | 67 | None => { | |
96 | match cursor.token_tree() { | 68 | if let Some(subtree) = cursor.end() { |
97 | Some(tt::TokenTree::Leaf(leaf)) => { | 69 | cached.push(convert_delim(subtree.delimiter_kind(), true)); |
98 | cached.push(Some(convert_leaf(&leaf))); | 70 | cursor.bump() |
99 | self.cached_cursor.set(cursor.bump()); | 71 | } else { |
100 | } | 72 | continue; |
101 | Some(tt::TokenTree::Subtree(subtree)) => { | ||
102 | self.cached_cursor.set(cursor.subtree().unwrap()); | ||
103 | cached.push(Some(convert_delim(subtree.delimiter_kind(), false))); | ||
104 | } | ||
105 | None => { | ||
106 | if let Some(subtree) = cursor.end() { | ||
107 | cached.push(Some(convert_delim(subtree.delimiter_kind(), true))); | ||
108 | self.cached_cursor.set(cursor.bump()); | ||
109 | } | ||
110 | } | 73 | } |
111 | } | 74 | } |
112 | } | 75 | }; |
113 | } | 76 | } |
114 | 77 | ||
115 | Ref::map(self.cached.borrow(), |c| &c[pos]) | 78 | let mut res = SubtreeTokenSource { |
79 | curr: (Token { kind: EOF, is_jointed_to_next: false }, 0), | ||
80 | cached, | ||
81 | }; | ||
82 | res.curr = (res.token(0), 0); | ||
83 | res | ||
84 | } | ||
85 | |||
86 | fn token(&self, pos: usize) -> Token { | ||
87 | match self.cached.get(pos) { | ||
88 | Some(it) => it.tt, | ||
89 | None => Token { kind: EOF, is_jointed_to_next: false }, | ||
90 | } | ||
116 | } | 91 | } |
117 | } | 92 | } |
118 | 93 | ||
119 | impl<'a> TokenSource for SubtreeTokenSource<'a> { | 94 | impl<'a> TokenSource for SubtreeTokenSource { |
120 | fn current(&self) -> Token { | 95 | fn current(&self) -> Token { |
121 | self.curr.0 | 96 | self.curr.0 |
122 | } | 97 | } |
123 | 98 | ||
124 | /// Lookahead n token | 99 | /// Lookahead n token |
125 | fn lookahead_nth(&self, n: usize) -> Token { | 100 | fn lookahead_nth(&self, n: usize) -> Token { |
126 | self.mk_token(self.curr.1 + n) | 101 | self.token(self.curr.1 + n) |
127 | } | 102 | } |
128 | 103 | ||
129 | /// bump cursor to next token | 104 | /// bump cursor to next token |
@@ -131,13 +106,12 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> { | |||
131 | if self.current().kind == EOF { | 106 | if self.current().kind == EOF { |
132 | return; | 107 | return; |
133 | } | 108 | } |
134 | 109 | self.curr = (self.token(self.curr.1 + 1), self.curr.1 + 1); | |
135 | self.curr = (self.mk_token(self.curr.1 + 1), self.curr.1 + 1); | ||
136 | } | 110 | } |
137 | 111 | ||
138 | /// Is the current token a specified keyword? | 112 | /// Is the current token a specified keyword? |
139 | fn is_keyword(&self, kw: &str) -> bool { | 113 | fn is_keyword(&self, kw: &str) -> bool { |
140 | match *self.get(self.curr.1) { | 114 | match self.cached.get(self.curr.1) { |
141 | Some(ref t) => t.text == *kw, | 115 | Some(ref t) => t.text == *kw, |
142 | _ => false, | 116 | _ => false, |
143 | } | 117 | } |
@@ -155,7 +129,7 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { | |||
155 | let idx = closing as usize; | 129 | let idx = closing as usize; |
156 | let kind = kinds[idx]; | 130 | let kind = kinds[idx]; |
157 | let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; | 131 | let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; |
158 | TtToken { kind, is_joint_to_next: false, text: SmolStr::new(text) } | 132 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: SmolStr::new(text) } |
159 | } | 133 | } |
160 | 134 | ||
161 | fn convert_literal(l: &tt::Literal) -> TtToken { | 135 | fn convert_literal(l: &tt::Literal) -> TtToken { |
@@ -169,7 +143,7 @@ fn convert_literal(l: &tt::Literal) -> TtToken { | |||
169 | }) | 143 | }) |
170 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); | 144 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); |
171 | 145 | ||
172 | TtToken { kind, is_joint_to_next: false, text: l.text.clone() } | 146 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: l.text.clone() } |
173 | } | 147 | } |
174 | 148 | ||
175 | fn convert_ident(ident: &tt::Ident) -> TtToken { | 149 | fn convert_ident(ident: &tt::Ident) -> TtToken { |
@@ -180,7 +154,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken { | |||
180 | _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), | 154 | _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), |
181 | }; | 155 | }; |
182 | 156 | ||
183 | TtToken { kind, is_joint_to_next: false, text: ident.text.clone() } | 157 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: ident.text.clone() } |
184 | } | 158 | } |
185 | 159 | ||
186 | fn convert_punct(p: tt::Punct) -> TtToken { | 160 | fn convert_punct(p: tt::Punct) -> TtToken { |
@@ -194,7 +168,7 @@ fn convert_punct(p: tt::Punct) -> TtToken { | |||
194 | let s: &str = p.char.encode_utf8(&mut buf); | 168 | let s: &str = p.char.encode_utf8(&mut buf); |
195 | SmolStr::new(s) | 169 | SmolStr::new(s) |
196 | }; | 170 | }; |
197 | TtToken { kind, is_joint_to_next: p.spacing == tt::Spacing::Joint, text } | 171 | TtToken { tt: Token { kind, is_jointed_to_next: p.spacing == tt::Spacing::Joint }, text } |
198 | } | 172 | } |
199 | 173 | ||
200 | fn convert_leaf(leaf: &tt::Leaf) -> TtToken { | 174 | fn convert_leaf(leaf: &tt::Leaf) -> TtToken { |
@@ -208,6 +182,7 @@ fn convert_leaf(leaf: &tt::Leaf) -> TtToken { | |||
208 | #[cfg(test)] | 182 | #[cfg(test)] |
209 | mod tests { | 183 | mod tests { |
210 | use super::{convert_literal, TtToken}; | 184 | use super::{convert_literal, TtToken}; |
185 | use parser::Token; | ||
211 | use syntax::{SmolStr, SyntaxKind}; | 186 | use syntax::{SmolStr, SyntaxKind}; |
212 | 187 | ||
213 | #[test] | 188 | #[test] |
@@ -218,8 +193,7 @@ mod tests { | |||
218 | text: SmolStr::new("-42.0") | 193 | text: SmolStr::new("-42.0") |
219 | }), | 194 | }), |
220 | TtToken { | 195 | TtToken { |
221 | kind: SyntaxKind::FLOAT_NUMBER, | 196 | tt: Token { kind: SyntaxKind::FLOAT_NUMBER, is_jointed_to_next: false }, |
222 | is_joint_to_next: false, | ||
223 | text: SmolStr::new("-42.0") | 197 | text: SmolStr::new("-42.0") |
224 | } | 198 | } |
225 | ); | 199 | ); |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 265c0d63d..e648519f9 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -70,15 +70,12 @@ pub fn token_tree_to_syntax_node( | |||
70 | tt: &tt::Subtree, | 70 | tt: &tt::Subtree, |
71 | fragment_kind: FragmentKind, | 71 | fragment_kind: FragmentKind, |
72 | ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { | 72 | ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { |
73 | let tmp; | 73 | let buffer = match tt { |
74 | let tokens = match tt { | 74 | tt::Subtree { delimiter: None, token_trees } => { |
75 | tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(), | 75 | TokenBuffer::from_tokens(token_trees.as_slice()) |
76 | _ => { | ||
77 | tmp = [tt.clone().into()]; | ||
78 | &tmp[..] | ||
79 | } | 76 | } |
77 | _ => TokenBuffer::from_subtree(tt), | ||
80 | }; | 78 | }; |
81 | let buffer = TokenBuffer::new(&tokens); | ||
82 | let mut token_source = SubtreeTokenSource::new(&buffer); | 79 | let mut token_source = SubtreeTokenSource::new(&buffer); |
83 | let mut tree_sink = TtTreeSink::new(buffer.begin()); | 80 | let mut tree_sink = TtTreeSink::new(buffer.begin()); |
84 | parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind); | 81 | parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind); |
@@ -152,7 +149,7 @@ impl TokenMap { | |||
152 | } | 149 | } |
153 | 150 | ||
154 | fn remove_delim(&mut self, idx: usize) { | 151 | fn remove_delim(&mut self, idx: usize) { |
155 | // FIXME: This could be accidently quadratic | 152 | // FIXME: This could be accidentally quadratic |
156 | self.entries.remove(idx); | 153 | self.entries.remove(idx); |
157 | } | 154 | } |
158 | } | 155 | } |
@@ -414,7 +411,7 @@ trait TokenConvertor { | |||
414 | fn id_alloc(&mut self) -> &mut TokenIdAlloc; | 411 | fn id_alloc(&mut self) -> &mut TokenIdAlloc; |
415 | } | 412 | } |
416 | 413 | ||
417 | impl<'a> SrcToken for (RawToken, &'a str) { | 414 | impl<'a> SrcToken for (&'a RawToken, &'a str) { |
418 | fn kind(&self) -> SyntaxKind { | 415 | fn kind(&self) -> SyntaxKind { |
419 | self.0.kind | 416 | self.0.kind |
420 | } | 417 | } |
@@ -431,7 +428,7 @@ impl<'a> SrcToken for (RawToken, &'a str) { | |||
431 | impl RawConvertor<'_> {} | 428 | impl RawConvertor<'_> {} |
432 | 429 | ||
433 | impl<'a> TokenConvertor for RawConvertor<'a> { | 430 | impl<'a> TokenConvertor for RawConvertor<'a> { |
434 | type Token = (RawToken, &'a str); | 431 | type Token = (&'a RawToken, &'a str); |
435 | 432 | ||
436 | fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> { | 433 | fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> { |
437 | convert_doc_comment(&doc_comment(token.1)) | 434 | convert_doc_comment(&doc_comment(token.1)) |
@@ -442,11 +439,11 @@ impl<'a> TokenConvertor for RawConvertor<'a> { | |||
442 | let range = TextRange::at(self.offset, token.len); | 439 | let range = TextRange::at(self.offset, token.len); |
443 | self.offset += token.len; | 440 | self.offset += token.len; |
444 | 441 | ||
445 | Some(((*token, &self.text[range]), range)) | 442 | Some(((token, &self.text[range]), range)) |
446 | } | 443 | } |
447 | 444 | ||
448 | fn peek(&self) -> Option<Self::Token> { | 445 | fn peek(&self) -> Option<Self::Token> { |
449 | let token = self.inner.as_slice().get(0).cloned(); | 446 | let token = self.inner.as_slice().get(0); |
450 | 447 | ||
451 | token.map(|it| { | 448 | token.map(|it| { |
452 | let range = TextRange::at(self.offset, it.len); | 449 | let range = TextRange::at(self.offset, it.len); |
@@ -479,14 +476,14 @@ impl Convertor { | |||
479 | 476 | ||
480 | #[derive(Debug)] | 477 | #[derive(Debug)] |
481 | enum SynToken { | 478 | enum SynToken { |
482 | Ordiniary(SyntaxToken), | 479 | Ordinary(SyntaxToken), |
483 | Punch(SyntaxToken, TextSize), | 480 | Punch(SyntaxToken, TextSize), |
484 | } | 481 | } |
485 | 482 | ||
486 | impl SynToken { | 483 | impl SynToken { |
487 | fn token(&self) -> &SyntaxToken { | 484 | fn token(&self) -> &SyntaxToken { |
488 | match self { | 485 | match self { |
489 | SynToken::Ordiniary(it) => it, | 486 | SynToken::Ordinary(it) => it, |
490 | SynToken::Punch(it, _) => it, | 487 | SynToken::Punch(it, _) => it, |
491 | } | 488 | } |
492 | } | 489 | } |
@@ -498,7 +495,7 @@ impl SrcToken for SynToken { | |||
498 | } | 495 | } |
499 | fn to_char(&self) -> Option<char> { | 496 | fn to_char(&self) -> Option<char> { |
500 | match self { | 497 | match self { |
501 | SynToken::Ordiniary(_) => None, | 498 | SynToken::Ordinary(_) => None, |
502 | SynToken::Punch(it, i) => it.text().chars().nth((*i).into()), | 499 | SynToken::Punch(it, i) => it.text().chars().nth((*i).into()), |
503 | } | 500 | } |
504 | } | 501 | } |
@@ -538,7 +535,7 @@ impl TokenConvertor for Convertor { | |||
538 | } else { | 535 | } else { |
539 | self.punct_offset = None; | 536 | self.punct_offset = None; |
540 | let range = curr.text_range(); | 537 | let range = curr.text_range(); |
541 | (SynToken::Ordiniary(curr), range) | 538 | (SynToken::Ordinary(curr), range) |
542 | }; | 539 | }; |
543 | 540 | ||
544 | Some(token) | 541 | Some(token) |
@@ -560,7 +557,7 @@ impl TokenConvertor for Convertor { | |||
560 | let token = if curr.kind().is_punct() { | 557 | let token = if curr.kind().is_punct() { |
561 | SynToken::Punch(curr, 0.into()) | 558 | SynToken::Punch(curr, 0.into()) |
562 | } else { | 559 | } else { |
563 | SynToken::Ordiniary(curr) | 560 | SynToken::Ordinary(curr) |
564 | }; | 561 | }; |
565 | Some(token) | 562 | Some(token) |
566 | } | 563 | } |
@@ -601,17 +598,16 @@ impl<'a> TtTreeSink<'a> { | |||
601 | } | 598 | } |
602 | } | 599 | } |
603 | 600 | ||
604 | fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr { | 601 | fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> &'static str { |
605 | let texts = match d { | 602 | let texts = match d { |
606 | Some(tt::DelimiterKind::Parenthesis) => "()", | 603 | Some(tt::DelimiterKind::Parenthesis) => "()", |
607 | Some(tt::DelimiterKind::Brace) => "{}", | 604 | Some(tt::DelimiterKind::Brace) => "{}", |
608 | Some(tt::DelimiterKind::Bracket) => "[]", | 605 | Some(tt::DelimiterKind::Bracket) => "[]", |
609 | None => return "".into(), | 606 | None => return "", |
610 | }; | 607 | }; |
611 | 608 | ||
612 | let idx = closing as usize; | 609 | let idx = closing as usize; |
613 | let text = &texts[idx..texts.len() - (1 - idx)]; | 610 | &texts[idx..texts.len() - (1 - idx)] |
614 | text.into() | ||
615 | } | 611 | } |
616 | 612 | ||
617 | impl<'a> TreeSink for TtTreeSink<'a> { | 613 | impl<'a> TreeSink for TtTreeSink<'a> { |
@@ -626,29 +622,32 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
626 | 622 | ||
627 | let mut last = self.cursor; | 623 | let mut last = self.cursor; |
628 | for _ in 0..n_tokens { | 624 | for _ in 0..n_tokens { |
625 | let tmp_str: SmolStr; | ||
629 | if self.cursor.eof() { | 626 | if self.cursor.eof() { |
630 | break; | 627 | break; |
631 | } | 628 | } |
632 | last = self.cursor; | 629 | last = self.cursor; |
633 | let text: SmolStr = match self.cursor.token_tree() { | 630 | let text: &str = match self.cursor.token_tree() { |
634 | Some(tt::TokenTree::Leaf(leaf)) => { | 631 | Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { |
635 | // Mark the range if needed | 632 | // Mark the range if needed |
636 | let (text, id) = match leaf { | 633 | let (text, id) = match leaf { |
637 | tt::Leaf::Ident(ident) => (ident.text.clone(), ident.id), | 634 | tt::Leaf::Ident(ident) => (&ident.text, ident.id), |
638 | tt::Leaf::Punct(punct) => { | 635 | tt::Leaf::Punct(punct) => { |
639 | assert!(punct.char.is_ascii()); | 636 | assert!(punct.char.is_ascii()); |
640 | let char = &(punct.char as u8); | 637 | let char = &(punct.char as u8); |
641 | let text = std::str::from_utf8(std::slice::from_ref(char)).unwrap(); | 638 | tmp_str = SmolStr::new_inline( |
642 | (SmolStr::new_inline(text), punct.id) | 639 | std::str::from_utf8(std::slice::from_ref(char)).unwrap(), |
640 | ); | ||
641 | (&tmp_str, punct.id) | ||
643 | } | 642 | } |
644 | tt::Leaf::Literal(lit) => (lit.text.clone(), lit.id), | 643 | tt::Leaf::Literal(lit) => (&lit.text, lit.id), |
645 | }; | 644 | }; |
646 | let range = TextRange::at(self.text_pos, TextSize::of(text.as_str())); | 645 | let range = TextRange::at(self.text_pos, TextSize::of(text.as_str())); |
647 | self.token_map.insert(id, range); | 646 | self.token_map.insert(id, range); |
648 | self.cursor = self.cursor.bump(); | 647 | self.cursor = self.cursor.bump(); |
649 | text | 648 | text |
650 | } | 649 | } |
651 | Some(tt::TokenTree::Subtree(subtree)) => { | 650 | Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { |
652 | self.cursor = self.cursor.subtree().unwrap(); | 651 | self.cursor = self.cursor.subtree().unwrap(); |
653 | if let Some(id) = subtree.delimiter.map(|it| it.id) { | 652 | if let Some(id) = subtree.delimiter.map(|it| it.id) { |
654 | self.open_delims.insert(id, self.text_pos); | 653 | self.open_delims.insert(id, self.text_pos); |
@@ -672,7 +671,7 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
672 | } | 671 | } |
673 | }; | 672 | }; |
674 | self.buf += &text; | 673 | self.buf += &text; |
675 | self.text_pos += TextSize::of(text.as_str()); | 674 | self.text_pos += TextSize::of(text); |
676 | } | 675 | } |
677 | 676 | ||
678 | let text = SmolStr::new(self.buf.as_str()); | 677 | let text = SmolStr::new(self.buf.as_str()); |
@@ -682,8 +681,8 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
682 | // Add whitespace between adjoint puncts | 681 | // Add whitespace between adjoint puncts |
683 | let next = last.bump(); | 682 | let next = last.bump(); |
684 | if let ( | 683 | if let ( |
685 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(curr))), | 684 | Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(curr), _)), |
686 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(_))), | 685 | Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(_), _)), |
687 | ) = (last.token_tree(), next.token_tree()) | 686 | ) = (last.token_tree(), next.token_tree()) |
688 | { | 687 | { |
689 | // Note: We always assume the semi-colon would be the last token in | 688 | // Note: We always assume the semi-colon would be the last token in |
@@ -742,7 +741,7 @@ mod tests { | |||
742 | ) | 741 | ) |
743 | .expand_tt("literals!(foo);"); | 742 | .expand_tt("literals!(foo);"); |
744 | let tts = &[expansion.into()]; | 743 | let tts = &[expansion.into()]; |
745 | let buffer = tt::buffer::TokenBuffer::new(tts); | 744 | let buffer = tt::buffer::TokenBuffer::from_tokens(tts); |
746 | let mut tt_src = SubtreeTokenSource::new(&buffer); | 745 | let mut tt_src = SubtreeTokenSource::new(&buffer); |
747 | let mut tokens = vec![]; | 746 | let mut tokens = vec![]; |
748 | while tt_src.current().kind != EOF { | 747 | while tt_src.current().kind != EOF { |
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 1d9afb4fb..ecea15c11 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -1080,6 +1080,19 @@ fn test_vertical_bar_with_pat() { | |||
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | #[test] | 1082 | #[test] |
1083 | fn test_dollar_crate_lhs_is_not_meta() { | ||
1084 | parse_macro( | ||
1085 | r#" | ||
1086 | macro_rules! foo { | ||
1087 | ($crate) => {}; | ||
1088 | () => {0}; | ||
1089 | } | ||
1090 | "#, | ||
1091 | ) | ||
1092 | .assert_expand_items(r#"foo!{}"#, r#"0"#); | ||
1093 | } | ||
1094 | |||
1095 | #[test] | ||
1083 | fn test_lifetime() { | 1096 | fn test_lifetime() { |
1084 | parse_macro( | 1097 | parse_macro( |
1085 | r#" | 1098 | r#" |
@@ -1954,7 +1967,7 @@ fn test_no_space_after_semi_colon() { | |||
1954 | #[test] | 1967 | #[test] |
1955 | fn test_rustc_issue_57597() { | 1968 | fn test_rustc_issue_57597() { |
1956 | fn test_error(fixture: &str) { | 1969 | fn test_error(fixture: &str) { |
1957 | assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmtpyTokenTree); | 1970 | assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmptyTokenTree); |
1958 | } | 1971 | } |
1959 | 1972 | ||
1960 | test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }"); | 1973 | test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }"); |
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 63cc90027..bb9ffea8b 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs | |||
@@ -66,6 +66,10 @@ pub(crate) mod fragments { | |||
66 | expressions::stmt(p, expressions::StmtWithSemi::No) | 66 | expressions::stmt(p, expressions::StmtWithSemi::No) |
67 | } | 67 | } |
68 | 68 | ||
69 | pub(crate) fn stmt_optional_semi(p: &mut Parser) { | ||
70 | expressions::stmt(p, expressions::StmtWithSemi::Optional) | ||
71 | } | ||
72 | |||
69 | pub(crate) fn opt_visibility(p: &mut Parser) { | 73 | pub(crate) fn opt_visibility(p: &mut Parser) { |
70 | let _ = super::opt_visibility(p); | 74 | let _ = super::opt_visibility(p); |
71 | } | 75 | } |
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index c7a3556a7..d61950b96 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs | |||
@@ -15,8 +15,16 @@ use super::*; | |||
15 | // let _ = b"e"; | 15 | // let _ = b"e"; |
16 | // let _ = br"f"; | 16 | // let _ = br"f"; |
17 | // } | 17 | // } |
18 | pub(crate) const LITERAL_FIRST: TokenSet = | 18 | pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[ |
19 | TokenSet::new(&[TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR, STRING, BYTE_STRING]); | 19 | T![true], |
20 | T![false], | ||
21 | INT_NUMBER, | ||
22 | FLOAT_NUMBER, | ||
23 | BYTE, | ||
24 | CHAR, | ||
25 | STRING, | ||
26 | BYTE_STRING, | ||
27 | ]); | ||
20 | 28 | ||
21 | pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { | 29 | pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { |
22 | if !p.at_ts(LITERAL_FIRST) { | 30 | if !p.at_ts(LITERAL_FIRST) { |
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index cf4168d32..2070ce163 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs | |||
@@ -27,19 +27,19 @@ pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { | |||
27 | } | 27 | } |
28 | 28 | ||
29 | pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ | 29 | pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ |
30 | FN_KW, | 30 | T![fn], |
31 | STRUCT_KW, | 31 | T![struct], |
32 | ENUM_KW, | 32 | T![enum], |
33 | IMPL_KW, | 33 | T![impl], |
34 | TRAIT_KW, | 34 | T![trait], |
35 | CONST_KW, | 35 | T![const], |
36 | STATIC_KW, | 36 | T![static], |
37 | LET_KW, | 37 | T![let], |
38 | MOD_KW, | 38 | T![mod], |
39 | PUB_KW, | 39 | T![pub], |
40 | CRATE_KW, | 40 | T![crate], |
41 | USE_KW, | 41 | T![use], |
42 | MACRO_KW, | 42 | T![macro], |
43 | T![;], | 43 | T![;], |
44 | ]); | 44 | ]); |
45 | 45 | ||
diff --git a/crates/parser/src/grammar/items/traits.rs b/crates/parser/src/grammar/items/traits.rs index ab9a12b4d..d076974ed 100644 --- a/crates/parser/src/grammar/items/traits.rs +++ b/crates/parser/src/grammar/items/traits.rs | |||
@@ -110,7 +110,7 @@ fn choose_type_params_over_qpath(p: &Parser) -> bool { | |||
110 | if !p.at(T![<]) { | 110 | if !p.at(T![<]) { |
111 | return false; | 111 | return false; |
112 | } | 112 | } |
113 | if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW { | 113 | if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == T![const] { |
114 | return true; | 114 | return true; |
115 | } | 115 | } |
116 | (p.nth(1) == LIFETIME_IDENT || p.nth(1) == IDENT) | 116 | (p.nth(1) == LIFETIME_IDENT || p.nth(1) == IDENT) |
diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs index 20e6a13cf..5cb8b08e7 100644 --- a/crates/parser/src/grammar/items/use_item.rs +++ b/crates/parser/src/grammar/items/use_item.rs | |||
@@ -46,7 +46,7 @@ fn use_tree(p: &mut Parser, top_level: bool) { | |||
46 | // test use_tree_list | 46 | // test use_tree_list |
47 | // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) | 47 | // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) |
48 | // use {path::from::root}; // Rust 2015 | 48 | // use {path::from::root}; // Rust 2015 |
49 | // use ::{some::arbritrary::path}; // Rust 2015 | 49 | // use ::{some::arbitrary::path}; // Rust 2015 |
50 | // use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting | 50 | // use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting |
51 | T!['{'] => { | 51 | T!['{'] => { |
52 | use_tree_list(p); | 52 | use_tree_list(p); |
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index b53d5749f..da71498a8 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs | |||
@@ -83,7 +83,7 @@ fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) { | |||
83 | } | 83 | } |
84 | 84 | ||
85 | const PAT_RECOVERY_SET: TokenSet = | 85 | const PAT_RECOVERY_SET: TokenSet = |
86 | TokenSet::new(&[LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]); | 86 | TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,]]); |
87 | 87 | ||
88 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | 88 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { |
89 | let m = match p.nth(0) { | 89 | let m = match p.nth(0) { |
diff --git a/crates/parser/src/grammar/type_args.rs b/crates/parser/src/grammar/type_args.rs index a013c49b9..42cd426bd 100644 --- a/crates/parser/src/grammar/type_args.rs +++ b/crates/parser/src/grammar/type_args.rs | |||
@@ -26,7 +26,7 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser, colon_colon_required: bool) { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | // test type_arg | 28 | // test type_arg |
29 | // type A = B<'static, i32, 1, { 2 }, Item=u64>; | 29 | // type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>; |
30 | fn generic_arg(p: &mut Parser) { | 30 | fn generic_arg(p: &mut Parser) { |
31 | let m = p.start(); | 31 | let m = p.start(); |
32 | match p.current() { | 32 | match p.current() { |
@@ -55,6 +55,10 @@ fn generic_arg(p: &mut Parser) { | |||
55 | expressions::literal(p); | 55 | expressions::literal(p); |
56 | m.complete(p, CONST_ARG); | 56 | m.complete(p, CONST_ARG); |
57 | } | 57 | } |
58 | T![true] | T![false] => { | ||
59 | expressions::literal(p); | ||
60 | m.complete(p, CONST_ARG); | ||
61 | } | ||
58 | _ => { | 62 | _ => { |
59 | types::type_(p); | 63 | types::type_(p); |
60 | m.complete(p, TYPE_ARG); | 64 | m.complete(p, TYPE_ARG); |
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs index 4aeccd193..3de5248da 100644 --- a/crates/parser/src/grammar/type_params.rs +++ b/crates/parser/src/grammar/type_params.rs | |||
@@ -25,7 +25,7 @@ fn generic_param_list(p: &mut Parser) { | |||
25 | match p.current() { | 25 | match p.current() { |
26 | LIFETIME_IDENT => lifetime_param(p, m), | 26 | LIFETIME_IDENT => lifetime_param(p, m), |
27 | IDENT => type_param(p, m), | 27 | IDENT => type_param(p, m), |
28 | CONST_KW => const_param(p, m), | 28 | T![const] => const_param(p, m), |
29 | _ => { | 29 | _ => { |
30 | m.abandon(p); | 30 | m.abandon(p); |
31 | p.err_and_bump("expected type parameter") | 31 | p.err_and_bump("expected type parameter") |
@@ -66,7 +66,7 @@ fn type_param(p: &mut Parser, m: Marker) { | |||
66 | // test const_param | 66 | // test const_param |
67 | // struct S<const N: u32>; | 67 | // struct S<const N: u32>; |
68 | fn const_param(p: &mut Parser, m: Marker) { | 68 | fn const_param(p: &mut Parser, m: Marker) { |
69 | assert!(p.at(CONST_KW)); | 69 | assert!(p.at(T![const])); |
70 | p.bump(T![const]); | 70 | p.bump(T![const]); |
71 | name(p); | 71 | name(p); |
72 | types::ascription(p); | 72 | types::ascription(p); |
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 811e740f9..9dfe63028 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs | |||
@@ -88,6 +88,7 @@ pub enum FragmentKind { | |||
88 | Path, | 88 | Path, |
89 | Expr, | 89 | Expr, |
90 | Statement, | 90 | Statement, |
91 | StatementOptionalSemi, | ||
91 | Type, | 92 | Type, |
92 | Pattern, | 93 | Pattern, |
93 | Item, | 94 | Item, |
@@ -118,6 +119,7 @@ pub fn parse_fragment( | |||
118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, | 119 | FragmentKind::Visibility => grammar::fragments::opt_visibility, |
119 | FragmentKind::MetaItem => grammar::fragments::meta_item, | 120 | FragmentKind::MetaItem => grammar::fragments::meta_item, |
120 | FragmentKind::Statement => grammar::fragments::stmt, | 121 | FragmentKind::Statement => grammar::fragments::stmt, |
122 | FragmentKind::StatementOptionalSemi => grammar::fragments::stmt_optional_semi, | ||
121 | FragmentKind::Items => grammar::fragments::macro_items, | 123 | FragmentKind::Items => grammar::fragments::macro_items, |
122 | FragmentKind::Statements => grammar::fragments::macro_stmts, | 124 | FragmentKind::Statements => grammar::fragments::macro_stmts, |
123 | FragmentKind::Attr => grammar::fragments::attr, | 125 | FragmentKind::Attr => grammar::fragments::attr, |
diff --git a/crates/proc_macro_api/src/msg.rs b/crates/proc_macro_api/src/msg.rs index f84ebdbc5..970f165ed 100644 --- a/crates/proc_macro_api/src/msg.rs +++ b/crates/proc_macro_api/src/msg.rs | |||
@@ -58,7 +58,13 @@ pub trait Message: Serialize + DeserializeOwned { | |||
58 | fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> { | 58 | fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> { |
59 | Ok(match read_json(inp)? { | 59 | Ok(match read_json(inp)? { |
60 | None => None, | 60 | None => None, |
61 | Some(text) => Some(serde_json::from_str(&text)?), | 61 | Some(text) => { |
62 | let mut deserializer = serde_json::Deserializer::from_str(&text); | ||
63 | // Note that some proc-macro generate very deep syntax tree | ||
64 | // We have to disable the current limit of serde here | ||
65 | deserializer.disable_recursion_limit(); | ||
66 | Some(Self::deserialize(&mut deserializer)?) | ||
67 | } | ||
62 | }) | 68 | }) |
63 | } | 69 | } |
64 | fn write(self, out: &mut impl Write) -> io::Result<()> { | 70 | fn write(self, out: &mut impl Write) -> io::Result<()> { |
@@ -73,7 +79,7 @@ impl Message for Response {} | |||
73 | fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> { | 79 | fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> { |
74 | let mut buf = String::new(); | 80 | let mut buf = String::new(); |
75 | inp.read_line(&mut buf)?; | 81 | inp.read_line(&mut buf)?; |
76 | buf.pop(); // Remove traling '\n' | 82 | buf.pop(); // Remove trailing '\n' |
77 | Ok(match buf.len() { | 83 | Ok(match buf.len() { |
78 | 0 => None, | 84 | 0 => None, |
79 | _ => Some(buf), | 85 | _ => Some(buf), |
diff --git a/crates/proc_macro_api/src/process.rs b/crates/proc_macro_api/src/process.rs index d68723ada..6d6ab8888 100644 --- a/crates/proc_macro_api/src/process.rs +++ b/crates/proc_macro_api/src/process.rs | |||
@@ -92,10 +92,11 @@ fn client_loop(task_rx: Receiver<Task>, mut process: Process) { | |||
92 | for Task { req, result_tx } in task_rx { | 92 | for Task { req, result_tx } in task_rx { |
93 | match send_request(&mut stdin, &mut stdout, req) { | 93 | match send_request(&mut stdin, &mut stdout, req) { |
94 | Ok(res) => result_tx.send(res).unwrap(), | 94 | Ok(res) => result_tx.send(res).unwrap(), |
95 | Err(_err) => { | 95 | Err(err) => { |
96 | log::error!( | 96 | log::error!( |
97 | "proc macro server crashed, server process state: {:?}", | 97 | "proc macro server crashed, server process state: {:?}, server request error: {:?}", |
98 | process.child.try_wait() | 98 | process.child.try_wait(), |
99 | err | ||
99 | ); | 100 | ); |
100 | let res = Response::Error(ResponseError { | 101 | let res = Response::Error(ResponseError { |
101 | code: ErrorCode::ServerErrorEnd, | 102 | code: ErrorCode::ServerErrorEnd, |
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml index df9a55c10..83f9ead17 100644 --- a/crates/proc_macro_srv/Cargo.toml +++ b/crates/proc_macro_srv/Cargo.toml | |||
@@ -20,8 +20,7 @@ proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } | |||
20 | test_utils = { path = "../test_utils", version = "0.0.0" } | 20 | test_utils = { path = "../test_utils", version = "0.0.0" } |
21 | 21 | ||
22 | [dev-dependencies] | 22 | [dev-dependencies] |
23 | cargo_metadata = "=0.12.0" | 23 | cargo_metadata = "0.12.2" |
24 | difference = "2.0.0" | ||
25 | 24 | ||
26 | # used as proc macro test targets | 25 | # used as proc macro test targets |
27 | serde_derive = "1.0.106" | 26 | serde_derive = "1.0.106" |
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs b/crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs index 3528d5c99..bd1e7c2fc 100644 --- a/crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs +++ b/crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs | |||
@@ -251,7 +251,7 @@ impl<S> DecodeMut<'_, '_, S> for String { | |||
251 | } | 251 | } |
252 | } | 252 | } |
253 | 253 | ||
254 | /// Simplied version of panic payloads, ignoring | 254 | /// Simplified version of panic payloads, ignoring |
255 | /// types other than `&'static str` and `String`. | 255 | /// types other than `&'static str` and `String`. |
256 | #[derive(Debug)] | 256 | #[derive(Debug)] |
257 | pub enum PanicMessage { | 257 | pub enum PanicMessage { |
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs index 503f4c101..e6006a3c8 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/rustc_server.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | //! The lib-proc-macro server backend is `TokenStream`-agnostic, such that | 4 | //! The lib-proc-macro server backend is `TokenStream`-agnostic, such that |
5 | //! we could provide any TokenStream implementation. | 5 | //! we could provide any TokenStream implementation. |
6 | //! The original idea from fedochet is using proc-macro2 as backend, | 6 | //! The original idea from fedochet is using proc-macro2 as backend, |
7 | //! we use tt instead for better intergation with RA. | 7 | //! we use tt instead for better integration with RA. |
8 | //! | 8 | //! |
9 | //! FIXME: No span and source file information is implemented yet | 9 | //! FIXME: No span and source file information is implemented yet |
10 | 10 | ||
@@ -204,17 +204,18 @@ pub mod token_stream { | |||
204 | let content = subtree | 204 | let content = subtree |
205 | .token_trees | 205 | .token_trees |
206 | .iter() | 206 | .iter() |
207 | .map(|tkn| { | 207 | .fold((String::new(), true), |(last, last_to_joint), tkn| { |
208 | let s = to_text(tkn); | 208 | let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " }); |
209 | let mut is_joint = false; | ||
209 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { | 210 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { |
210 | if punct.spacing == tt::Spacing::Alone { | 211 | if punct.spacing == tt::Spacing::Joint { |
211 | return s + " "; | 212 | is_joint = true; |
212 | } | 213 | } |
213 | } | 214 | } |
214 | s | 215 | (s, is_joint) |
215 | }) | 216 | }) |
216 | .collect::<Vec<_>>() | 217 | .0; |
217 | .concat(); | 218 | |
218 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { | 219 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { |
219 | None => ("", ""), | 220 | None => ("", ""), |
220 | Some(tt::DelimiterKind::Brace) => ("{", "}"), | 221 | Some(tt::DelimiterKind::Brace) => ("{", "}"), |
@@ -710,4 +711,32 @@ mod tests { | |||
710 | assert_eq!(srv.character('c').text, "'c'"); | 711 | assert_eq!(srv.character('c').text, "'c'"); |
711 | assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); | 712 | assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); |
712 | } | 713 | } |
714 | |||
715 | #[test] | ||
716 | fn test_rustc_server_to_string() { | ||
717 | let s = TokenStream { | ||
718 | subtree: tt::Subtree { | ||
719 | delimiter: None, | ||
720 | token_trees: vec![ | ||
721 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | ||
722 | text: "struct".into(), | ||
723 | id: tt::TokenId::unspecified(), | ||
724 | })), | ||
725 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | ||
726 | text: "T".into(), | ||
727 | id: tt::TokenId::unspecified(), | ||
728 | })), | ||
729 | tt::TokenTree::Subtree(tt::Subtree { | ||
730 | delimiter: Some(tt::Delimiter { | ||
731 | id: tt::TokenId::unspecified(), | ||
732 | kind: tt::DelimiterKind::Brace, | ||
733 | }), | ||
734 | token_trees: vec![], | ||
735 | }), | ||
736 | ], | ||
737 | }, | ||
738 | }; | ||
739 | |||
740 | assert_eq!(s.to_string(), "struct T {}"); | ||
741 | } | ||
713 | } | 742 | } |
diff --git a/crates/profile/src/stop_watch.rs b/crates/profile/src/stop_watch.rs index 5e276190e..cb6915d45 100644 --- a/crates/profile/src/stop_watch.rs +++ b/crates/profile/src/stop_watch.rs | |||
@@ -76,7 +76,11 @@ impl fmt::Display for StopWatchSpan { | |||
76 | instructions /= 1000; | 76 | instructions /= 1000; |
77 | prefix = "m" | 77 | prefix = "m" |
78 | } | 78 | } |
79 | write!(f, ", {}{}i", instructions, prefix)?; | 79 | if instructions > 10000 { |
80 | instructions /= 1000; | ||
81 | prefix = "g" | ||
82 | } | ||
83 | write!(f, ", {}{}instr", instructions, prefix)?; | ||
80 | } | 84 | } |
81 | if let Some(memory) = self.memory { | 85 | if let Some(memory) = self.memory { |
82 | write!(f, ", {}", memory)?; | 86 | write!(f, ", {}", memory)?; |
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml index c55e85709..855fb83ea 100644 --- a/crates/project_model/Cargo.toml +++ b/crates/project_model/Cargo.toml | |||
@@ -12,11 +12,11 @@ doctest = false | |||
12 | [dependencies] | 12 | [dependencies] |
13 | log = "0.4.8" | 13 | log = "0.4.8" |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | cargo_metadata = "=0.12.0" | 15 | cargo_metadata = "0.12.2" |
16 | serde = { version = "1.0.106", features = ["derive"] } | 16 | serde = { version = "1.0.106", features = ["derive"] } |
17 | serde_json = "1.0.48" | 17 | serde_json = "1.0.48" |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
19 | itertools = "0.9.0" | 19 | itertools = "0.10.0" |
20 | 20 | ||
21 | arena = { path = "../arena", version = "0.0.0" } | 21 | arena = { path = "../arena", version = "0.0.0" } |
22 | cfg = { path = "../cfg", version = "0.0.0" } | 22 | cfg = { path = "../cfg", version = "0.0.0" } |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index bb3b6f2ef..2ee4e88b2 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -1,10 +1,12 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | convert::TryInto, | ||
4 | ffi::OsStr, | 5 | ffi::OsStr, |
6 | io::BufReader, | ||
5 | ops, | 7 | ops, |
6 | path::{Path, PathBuf}, | 8 | path::{Path, PathBuf}, |
7 | process::Command, | 9 | process::{Command, Stdio}, |
8 | }; | 10 | }; |
9 | 11 | ||
10 | use anyhow::{Context, Result}; | 12 | use anyhow::{Context, Result}; |
@@ -14,6 +16,7 @@ use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId} | |||
14 | use itertools::Itertools; | 16 | use itertools::Itertools; |
15 | use paths::{AbsPath, AbsPathBuf}; | 17 | use paths::{AbsPath, AbsPathBuf}; |
16 | use rustc_hash::FxHashMap; | 18 | use rustc_hash::FxHashMap; |
19 | use stdx::JodChild; | ||
17 | 20 | ||
18 | use crate::cfg_flag::CfgFlag; | 21 | use crate::cfg_flag::CfgFlag; |
19 | use crate::utf8_stdout; | 22 | use crate::utf8_stdout; |
@@ -79,19 +82,35 @@ pub type Package = Idx<PackageData>; | |||
79 | 82 | ||
80 | pub type Target = Idx<TargetData>; | 83 | pub type Target = Idx<TargetData>; |
81 | 84 | ||
85 | /// Information associated with a cargo crate | ||
82 | #[derive(Debug, Clone, Eq, PartialEq)] | 86 | #[derive(Debug, Clone, Eq, PartialEq)] |
83 | pub struct PackageData { | 87 | pub struct PackageData { |
88 | /// Version given in the `Cargo.toml` | ||
84 | pub version: String, | 89 | pub version: String, |
90 | /// Name as given in the `Cargo.toml` | ||
85 | pub name: String, | 91 | pub name: String, |
92 | /// Path containing the `Cargo.toml` | ||
86 | pub manifest: AbsPathBuf, | 93 | pub manifest: AbsPathBuf, |
94 | /// Targets provided by the crate (lib, bin, example, test, ...) | ||
87 | pub targets: Vec<Target>, | 95 | pub targets: Vec<Target>, |
96 | /// Is this package a member of the current workspace | ||
88 | pub is_member: bool, | 97 | pub is_member: bool, |
98 | /// List of packages this package depends on | ||
89 | pub dependencies: Vec<PackageDependency>, | 99 | pub dependencies: Vec<PackageDependency>, |
100 | /// Rust edition for this package | ||
90 | pub edition: Edition, | 101 | pub edition: Edition, |
102 | /// List of features to activate | ||
91 | pub features: Vec<String>, | 103 | pub features: Vec<String>, |
104 | /// List of config flags defined by this package's build script | ||
92 | pub cfgs: Vec<CfgFlag>, | 105 | pub cfgs: Vec<CfgFlag>, |
106 | /// List of cargo-related environment variables with their value | ||
107 | /// | ||
108 | /// If the package has a build script which defines environment variables, | ||
109 | /// they can also be found here. | ||
93 | pub envs: Vec<(String, String)>, | 110 | pub envs: Vec<(String, String)>, |
111 | /// Directory where a build script might place its output | ||
94 | pub out_dir: Option<AbsPathBuf>, | 112 | pub out_dir: Option<AbsPathBuf>, |
113 | /// Path to the proc-macro library file if this package exposes proc-macros | ||
95 | pub proc_macro_dylib_path: Option<AbsPathBuf>, | 114 | pub proc_macro_dylib_path: Option<AbsPathBuf>, |
96 | } | 115 | } |
97 | 116 | ||
@@ -101,12 +120,18 @@ pub struct PackageDependency { | |||
101 | pub name: String, | 120 | pub name: String, |
102 | } | 121 | } |
103 | 122 | ||
123 | /// Information associated with a package's target | ||
104 | #[derive(Debug, Clone, Eq, PartialEq)] | 124 | #[derive(Debug, Clone, Eq, PartialEq)] |
105 | pub struct TargetData { | 125 | pub struct TargetData { |
126 | /// Package that provided this target | ||
106 | pub package: Package, | 127 | pub package: Package, |
128 | /// Name as given in the `Cargo.toml` or generated from the file name | ||
107 | pub name: String, | 129 | pub name: String, |
130 | /// Path to the main source file of the target | ||
108 | pub root: AbsPathBuf, | 131 | pub root: AbsPathBuf, |
132 | /// Kind of target | ||
109 | pub kind: TargetKind, | 133 | pub kind: TargetKind, |
134 | /// Is this target a proc-macro | ||
110 | pub is_proc_macro: bool, | 135 | pub is_proc_macro: bool, |
111 | } | 136 | } |
112 | 137 | ||
@@ -148,6 +173,7 @@ impl CargoWorkspace { | |||
148 | pub fn from_cargo_metadata( | 173 | pub fn from_cargo_metadata( |
149 | cargo_toml: &AbsPath, | 174 | cargo_toml: &AbsPath, |
150 | config: &CargoConfig, | 175 | config: &CargoConfig, |
176 | progress: &dyn Fn(String), | ||
151 | ) -> Result<CargoWorkspace> { | 177 | ) -> Result<CargoWorkspace> { |
152 | let mut meta = MetadataCommand::new(); | 178 | let mut meta = MetadataCommand::new(); |
153 | meta.cargo_path(toolchain::cargo()); | 179 | meta.cargo_path(toolchain::cargo()); |
@@ -196,8 +222,26 @@ impl CargoWorkspace { | |||
196 | if let Some(target) = target { | 222 | if let Some(target) = target { |
197 | meta.other_options(vec![String::from("--filter-platform"), target]); | 223 | meta.other_options(vec![String::from("--filter-platform"), target]); |
198 | } | 224 | } |
225 | |||
226 | // FIXME: Currently MetadataCommand is not based on parse_stream, | ||
227 | // So we just report it as a whole | ||
228 | progress("metadata".to_string()); | ||
199 | let mut meta = meta.exec().with_context(|| { | 229 | let mut meta = meta.exec().with_context(|| { |
200 | format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) | 230 | let cwd: Option<AbsPathBuf> = |
231 | std::env::current_dir().ok().and_then(|p| p.try_into().ok()); | ||
232 | |||
233 | let workdir = cargo_toml | ||
234 | .parent() | ||
235 | .map(|p| p.to_path_buf()) | ||
236 | .or(cwd) | ||
237 | .map(|dir| dir.to_string_lossy().to_string()) | ||
238 | .unwrap_or_else(|| "<failed to get path>".into()); | ||
239 | |||
240 | format!( | ||
241 | "Failed to run `cargo metadata --manifest-path {}` in `{}`", | ||
242 | cargo_toml.display(), | ||
243 | workdir | ||
244 | ) | ||
201 | })?; | 245 | })?; |
202 | 246 | ||
203 | let mut out_dir_by_id = FxHashMap::default(); | 247 | let mut out_dir_by_id = FxHashMap::default(); |
@@ -205,7 +249,7 @@ impl CargoWorkspace { | |||
205 | let mut envs = FxHashMap::default(); | 249 | let mut envs = FxHashMap::default(); |
206 | let mut proc_macro_dylib_paths = FxHashMap::default(); | 250 | let mut proc_macro_dylib_paths = FxHashMap::default(); |
207 | if config.load_out_dirs_from_check { | 251 | if config.load_out_dirs_from_check { |
208 | let resources = load_extern_resources(cargo_toml, config)?; | 252 | let resources = load_extern_resources(cargo_toml, config, progress)?; |
209 | out_dir_by_id = resources.out_dirs; | 253 | out_dir_by_id = resources.out_dirs; |
210 | cfgs = resources.cfgs; | 254 | cfgs = resources.cfgs; |
211 | envs = resources.env; | 255 | envs = resources.env; |
@@ -330,10 +374,16 @@ pub(crate) struct ExternResources { | |||
330 | pub(crate) fn load_extern_resources( | 374 | pub(crate) fn load_extern_resources( |
331 | cargo_toml: &Path, | 375 | cargo_toml: &Path, |
332 | cargo_features: &CargoConfig, | 376 | cargo_features: &CargoConfig, |
377 | progress: &dyn Fn(String), | ||
333 | ) -> Result<ExternResources> { | 378 | ) -> Result<ExternResources> { |
334 | let mut cmd = Command::new(toolchain::cargo()); | 379 | let mut cmd = Command::new(toolchain::cargo()); |
335 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); | 380 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); |
336 | 381 | ||
382 | // --all-targets includes tests, benches and examples in addition to the | ||
383 | // default lib and bins. This is an independent concept from the --targets | ||
384 | // flag below. | ||
385 | cmd.arg("--all-targets"); | ||
386 | |||
337 | if let Some(target) = &cargo_features.target { | 387 | if let Some(target) = &cargo_features.target { |
338 | cmd.args(&["--target", target]); | 388 | cmd.args(&["--target", target]); |
339 | } | 389 | } |
@@ -352,11 +402,14 @@ pub(crate) fn load_extern_resources( | |||
352 | } | 402 | } |
353 | } | 403 | } |
354 | 404 | ||
355 | let output = cmd.output()?; | 405 | cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); |
356 | 406 | ||
357 | let mut res = ExternResources::default(); | 407 | let mut child = cmd.spawn().map(JodChild)?; |
408 | let child_stdout = child.stdout.take().unwrap(); | ||
409 | let stdout = BufReader::new(child_stdout); | ||
358 | 410 | ||
359 | for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) { | 411 | let mut res = ExternResources::default(); |
412 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
360 | if let Ok(message) = message { | 413 | if let Ok(message) = message { |
361 | match message { | 414 | match message { |
362 | Message::BuildScriptExecuted(BuildScript { | 415 | Message::BuildScriptExecuted(BuildScript { |
@@ -389,6 +442,8 @@ pub(crate) fn load_extern_resources( | |||
389 | res.env.insert(package_id, env); | 442 | res.env.insert(package_id, env); |
390 | } | 443 | } |
391 | Message::CompilerArtifact(message) => { | 444 | Message::CompilerArtifact(message) => { |
445 | progress(format!("metadata {}", message.target.name)); | ||
446 | |||
392 | if message.target.kind.contains(&"proc-macro".to_string()) { | 447 | if message.target.kind.contains(&"proc-macro".to_string()) { |
393 | let package_id = message.package_id; | 448 | let package_id = message.package_id; |
394 | // Skip rmeta file | 449 | // Skip rmeta file |
@@ -399,7 +454,9 @@ pub(crate) fn load_extern_resources( | |||
399 | } | 454 | } |
400 | } | 455 | } |
401 | } | 456 | } |
402 | Message::CompilerMessage(_) => (), | 457 | Message::CompilerMessage(message) => { |
458 | progress(message.target.name.clone()); | ||
459 | } | ||
403 | Message::Unknown => (), | 460 | Message::Unknown => (), |
404 | Message::BuildFinished(_) => {} | 461 | Message::BuildFinished(_) => {} |
405 | Message::TextLine(_) => {} | 462 | Message::TextLine(_) => {} |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 24aa9b8fa..aabb7a47d 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | mod cargo_workspace; | 3 | mod cargo_workspace; |
4 | mod cfg_flag; | ||
4 | mod project_json; | 5 | mod project_json; |
5 | mod sysroot; | 6 | mod sysroot; |
6 | mod cfg_flag; | ||
7 | mod workspace; | 7 | mod workspace; |
8 | 8 | ||
9 | use std::{ | 9 | use std::{ |
@@ -17,7 +17,10 @@ use paths::{AbsPath, AbsPathBuf}; | |||
17 | use rustc_hash::FxHashSet; | 17 | use rustc_hash::FxHashSet; |
18 | 18 | ||
19 | pub use crate::{ | 19 | pub use crate::{ |
20 | cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, | 20 | cargo_workspace::{ |
21 | CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, Target, TargetData, | ||
22 | TargetKind, | ||
23 | }, | ||
21 | project_json::{ProjectJson, ProjectJsonData}, | 24 | project_json::{ProjectJson, ProjectJsonData}, |
22 | sysroot::Sysroot, | 25 | sysroot::Sysroot, |
23 | workspace::{PackageRoot, ProjectWorkspace}, | 26 | workspace::{PackageRoot, ProjectWorkspace}, |
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs index aab279223..41a2ac03e 100644 --- a/crates/project_model/src/project_json.rs +++ b/crates/project_model/src/project_json.rs | |||
@@ -110,13 +110,13 @@ impl ProjectJson { | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | #[derive(Deserialize)] | 113 | #[derive(Deserialize, Debug, Clone)] |
114 | pub struct ProjectJsonData { | 114 | pub struct ProjectJsonData { |
115 | sysroot_src: Option<PathBuf>, | 115 | sysroot_src: Option<PathBuf>, |
116 | crates: Vec<CrateData>, | 116 | crates: Vec<CrateData>, |
117 | } | 117 | } |
118 | 118 | ||
119 | #[derive(Deserialize)] | 119 | #[derive(Deserialize, Debug, Clone)] |
120 | struct CrateData { | 120 | struct CrateData { |
121 | display_name: Option<String>, | 121 | display_name: Option<String>, |
122 | root_module: PathBuf, | 122 | root_module: PathBuf, |
@@ -132,13 +132,15 @@ struct CrateData { | |||
132 | source: Option<CrateSource>, | 132 | source: Option<CrateSource>, |
133 | } | 133 | } |
134 | 134 | ||
135 | #[derive(Deserialize)] | 135 | #[derive(Deserialize, Debug, Clone)] |
136 | #[serde(rename = "edition")] | 136 | #[serde(rename = "edition")] |
137 | enum EditionData { | 137 | enum EditionData { |
138 | #[serde(rename = "2015")] | 138 | #[serde(rename = "2015")] |
139 | Edition2015, | 139 | Edition2015, |
140 | #[serde(rename = "2018")] | 140 | #[serde(rename = "2018")] |
141 | Edition2018, | 141 | Edition2018, |
142 | #[serde(rename = "2021")] | ||
143 | Edition2021, | ||
142 | } | 144 | } |
143 | 145 | ||
144 | impl From<EditionData> for Edition { | 146 | impl From<EditionData> for Edition { |
@@ -146,11 +148,12 @@ impl From<EditionData> for Edition { | |||
146 | match data { | 148 | match data { |
147 | EditionData::Edition2015 => Edition::Edition2015, | 149 | EditionData::Edition2015 => Edition::Edition2015, |
148 | EditionData::Edition2018 => Edition::Edition2018, | 150 | EditionData::Edition2018 => Edition::Edition2018, |
151 | EditionData::Edition2021 => Edition::Edition2021, | ||
149 | } | 152 | } |
150 | } | 153 | } |
151 | } | 154 | } |
152 | 155 | ||
153 | #[derive(Deserialize)] | 156 | #[derive(Deserialize, Debug, Clone)] |
154 | struct DepData { | 157 | struct DepData { |
155 | /// Identifies a crate by position in the crates array. | 158 | /// Identifies a crate by position in the crates array. |
156 | #[serde(rename = "crate")] | 159 | #[serde(rename = "crate")] |
@@ -159,7 +162,7 @@ struct DepData { | |||
159 | name: CrateName, | 162 | name: CrateName, |
160 | } | 163 | } |
161 | 164 | ||
162 | #[derive(Deserialize)] | 165 | #[derive(Deserialize, Debug, Clone)] |
163 | struct CrateSource { | 166 | struct CrateSource { |
164 | include_dirs: Vec<PathBuf>, | 167 | include_dirs: Vec<PathBuf>, |
165 | exclude_dirs: Vec<PathBuf>, | 168 | exclude_dirs: Vec<PathBuf>, |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 68a235ce3..06a0be284 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -64,7 +64,11 @@ impl fmt::Debug for ProjectWorkspace { | |||
64 | } | 64 | } |
65 | 65 | ||
66 | impl ProjectWorkspace { | 66 | impl ProjectWorkspace { |
67 | pub fn load(manifest: ProjectManifest, config: &CargoConfig) -> Result<ProjectWorkspace> { | 67 | pub fn load( |
68 | manifest: ProjectManifest, | ||
69 | config: &CargoConfig, | ||
70 | progress: &dyn Fn(String), | ||
71 | ) -> Result<ProjectWorkspace> { | ||
68 | let res = match manifest { | 72 | let res = match manifest { |
69 | ProjectManifest::ProjectJson(project_json) => { | 73 | ProjectManifest::ProjectJson(project_json) => { |
70 | let file = fs::read_to_string(&project_json).with_context(|| { | 74 | let file = fs::read_to_string(&project_json).with_context(|| { |
@@ -84,15 +88,14 @@ impl ProjectWorkspace { | |||
84 | cmd | 88 | cmd |
85 | })?; | 89 | })?; |
86 | 90 | ||
87 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config).with_context( | 91 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress) |
88 | || { | 92 | .with_context(|| { |
89 | format!( | 93 | format!( |
90 | "Failed to read Cargo metadata from Cargo.toml file {}, {}", | 94 | "Failed to read Cargo metadata from Cargo.toml file {}, {}", |
91 | cargo_toml.display(), | 95 | cargo_toml.display(), |
92 | cargo_version | 96 | cargo_version |
93 | ) | 97 | ) |
94 | }, | 98 | })?; |
95 | )?; | ||
96 | let sysroot = if config.no_sysroot { | 99 | let sysroot = if config.no_sysroot { |
97 | Sysroot::default() | 100 | Sysroot::default() |
98 | } else { | 101 | } else { |
@@ -105,9 +108,12 @@ impl ProjectWorkspace { | |||
105 | }; | 108 | }; |
106 | 109 | ||
107 | let rustc = if let Some(rustc_dir) = &config.rustc_source { | 110 | let rustc = if let Some(rustc_dir) = &config.rustc_source { |
108 | Some(CargoWorkspace::from_cargo_metadata(&rustc_dir, config).with_context( | 111 | Some( |
109 | || format!("Failed to read Cargo metadata for Rust sources"), | 112 | CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress) |
110 | )?) | 113 | .with_context(|| { |
114 | format!("Failed to read Cargo metadata for Rust sources") | ||
115 | })?, | ||
116 | ) | ||
111 | } else { | 117 | } else { |
112 | None | 118 | None |
113 | }; | 119 | }; |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 53e70eaf7..af7b86ead 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -17,8 +17,9 @@ path = "src/bin/main.rs" | |||
17 | [dependencies] | 17 | [dependencies] |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
19 | crossbeam-channel = "0.5.0" | 19 | crossbeam-channel = "0.5.0" |
20 | dissimilar = "1.0.2" | ||
20 | env_logger = { version = "0.8.1", default-features = false } | 21 | env_logger = { version = "0.8.1", default-features = false } |
21 | itertools = "0.9.0" | 22 | itertools = "0.10.0" |
22 | jod-thread = "0.1.0" | 23 | jod-thread = "0.1.0" |
23 | log = "0.4.8" | 24 | log = "0.4.8" |
24 | lsp-types = { version = "0.86.0", features = ["proposed"] } | 25 | lsp-types = { version = "0.86.0", features = ["proposed"] } |
@@ -61,7 +62,7 @@ proc_macro_srv = { path = "../proc_macro_srv", version = "0.0.0" } | |||
61 | winapi = "0.3.8" | 62 | winapi = "0.3.8" |
62 | 63 | ||
63 | [dev-dependencies] | 64 | [dev-dependencies] |
64 | expect-test = "1.0" | 65 | expect-test = "1.1" |
65 | test_utils = { path = "../test_utils" } | 66 | test_utils = { path = "../test_utils" } |
66 | mbe = { path = "../mbe" } | 67 | mbe = { path = "../mbe" } |
67 | tt = { path = "../tt" } | 68 | tt = { path = "../tt" } |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index defdcbd74..3af3c59d8 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -8,11 +8,7 @@ use std::{convert::TryFrom, env, fs, path::PathBuf, process}; | |||
8 | 8 | ||
9 | use lsp_server::Connection; | 9 | use lsp_server::Connection; |
10 | use project_model::ProjectManifest; | 10 | use project_model::ProjectManifest; |
11 | use rust_analyzer::{ | 11 | use rust_analyzer::{cli, config::Config, from_json, Result}; |
12 | cli, | ||
13 | config::{Config, LinkedProject}, | ||
14 | from_json, Result, | ||
15 | }; | ||
16 | use vfs::AbsPathBuf; | 12 | use vfs::AbsPathBuf; |
17 | 13 | ||
18 | #[cfg(all(feature = "mimalloc"))] | 14 | #[cfg(all(feature = "mimalloc"))] |
@@ -138,13 +134,12 @@ fn run_server() -> Result<()> { | |||
138 | } | 134 | } |
139 | }; | 135 | }; |
140 | 136 | ||
141 | let mut config = Config::new(root_path); | 137 | let mut config = Config::new(root_path, initialize_params.capabilities); |
142 | if let Some(json) = initialize_params.initialization_options { | 138 | if let Some(json) = initialize_params.initialization_options { |
143 | config.update(json); | 139 | config.update(json); |
144 | } | 140 | } |
145 | config.update_caps(&initialize_params.capabilities); | ||
146 | 141 | ||
147 | if config.linked_projects.is_empty() { | 142 | if config.linked_projects().is_empty() { |
148 | let workspace_roots = initialize_params | 143 | let workspace_roots = initialize_params |
149 | .workspace_folders | 144 | .workspace_folders |
150 | .map(|workspaces| { | 145 | .map(|workspaces| { |
@@ -163,7 +158,7 @@ fn run_server() -> Result<()> { | |||
163 | log::error!("failed to find any projects in {:?}", workspace_roots); | 158 | log::error!("failed to find any projects in {:?}", workspace_roots); |
164 | } | 159 | } |
165 | 160 | ||
166 | config.linked_projects = discovered.into_iter().map(LinkedProject::from).collect(); | 161 | config.discovered_projects = Some(discovered); |
167 | } | 162 | } |
168 | 163 | ||
169 | config | 164 | config |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 80e46bf7f..f148521a2 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | //! Advertizes the capabilities of the LSP Server. | 1 | //! Advertizes the capabilities of the LSP Server. |
2 | use std::env; | 2 | use std::env; |
3 | 3 | ||
4 | use ide::CompletionResolveCapability; | ||
5 | use lsp_types::{ | 4 | use lsp_types::{ |
6 | CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, | 5 | CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, |
7 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, | 6 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, |
@@ -14,7 +13,6 @@ use lsp_types::{ | |||
14 | WorkDoneProgressOptions, WorkspaceFileOperationsServerCapabilities, | 13 | WorkDoneProgressOptions, WorkspaceFileOperationsServerCapabilities, |
15 | WorkspaceServerCapabilities, | 14 | WorkspaceServerCapabilities, |
16 | }; | 15 | }; |
17 | use rustc_hash::FxHashSet; | ||
18 | use serde_json::json; | 16 | use serde_json::json; |
19 | 17 | ||
20 | use crate::semantic_tokens; | 18 | use crate::semantic_tokens; |
@@ -77,14 +75,24 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
77 | will_create: None, | 75 | will_create: None, |
78 | did_rename: None, | 76 | did_rename: None, |
79 | will_rename: Some(FileOperationRegistrationOptions { | 77 | will_rename: Some(FileOperationRegistrationOptions { |
80 | filters: vec![FileOperationFilter { | 78 | filters: vec![ |
81 | scheme: Some(String::from("file")), | 79 | FileOperationFilter { |
82 | pattern: FileOperationPattern { | 80 | scheme: Some(String::from("file")), |
83 | glob: String::from("**/*.rs"), | 81 | pattern: FileOperationPattern { |
84 | matches: Some(FileOperationPatternKind::File), | 82 | glob: String::from("**/*.rs"), |
85 | options: None, | 83 | matches: Some(FileOperationPatternKind::File), |
84 | options: None, | ||
85 | }, | ||
86 | }, | 86 | }, |
87 | }], | 87 | FileOperationFilter { |
88 | scheme: Some(String::from("file")), | ||
89 | pattern: FileOperationPattern { | ||
90 | glob: String::from("**"), | ||
91 | matches: Some(FileOperationPatternKind::Folder), | ||
92 | options: None, | ||
93 | }, | ||
94 | }, | ||
95 | ], | ||
88 | }), | 96 | }), |
89 | did_delete: None, | 97 | did_delete: None, |
90 | will_delete: None, | 98 | will_delete: None, |
@@ -118,37 +126,31 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
118 | } | 126 | } |
119 | 127 | ||
120 | fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option<bool> { | 128 | fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option<bool> { |
121 | if enabled_completions_resolve_capabilities(client_caps)?.is_empty() { | 129 | if completion_item_edit_resolve(client_caps) { |
130 | Some(true) | ||
131 | } else { | ||
122 | log::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled"); | 132 | log::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled"); |
123 | None | 133 | None |
124 | } else { | ||
125 | Some(true) | ||
126 | } | 134 | } |
127 | } | 135 | } |
128 | 136 | ||
129 | /// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports. | 137 | /// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports. |
130 | pub(crate) fn enabled_completions_resolve_capabilities( | 138 | pub(crate) fn completion_item_edit_resolve(caps: &ClientCapabilities) -> bool { |
131 | caps: &ClientCapabilities, | 139 | (|| { |
132 | ) -> Option<FxHashSet<CompletionResolveCapability>> { | 140 | Some( |
133 | Some( | 141 | caps.text_document |
134 | caps.text_document | 142 | .as_ref()? |
135 | .as_ref()? | 143 | .completion |
136 | .completion | 144 | .as_ref()? |
137 | .as_ref()? | 145 | .completion_item |
138 | .completion_item | 146 | .as_ref()? |
139 | .as_ref()? | 147 | .resolve_support |
140 | .resolve_support | 148 | .as_ref()? |
141 | .as_ref()? | 149 | .properties |
142 | .properties | 150 | .iter() |
143 | .iter() | 151 | .any(|cap_string| cap_string.as_str() == "additionalTextEdits"), |
144 | .filter_map(|cap_string| match cap_string.as_str() { | 152 | ) |
145 | "additionalTextEdits" => Some(CompletionResolveCapability::AdditionalTextEdits), | 153 | })() == Some(true) |
146 | "detail" => Some(CompletionResolveCapability::Detail), | ||
147 | "documentation" => Some(CompletionResolveCapability::Documentation), | ||
148 | _unsupported => None, | ||
149 | }) | ||
150 | .collect(), | ||
151 | ) | ||
152 | } | 154 | } |
153 | 155 | ||
154 | fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { | 156 | fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { |
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 8a8b4a32c..5af0802a2 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -84,14 +84,15 @@ impl CargoTargetSpec { | |||
84 | } | 84 | } |
85 | } | 85 | } |
86 | 86 | ||
87 | if snap.config.cargo.all_features { | 87 | let cargo_config = snap.config.cargo(); |
88 | if cargo_config.all_features { | ||
88 | args.push("--all-features".to_string()); | 89 | args.push("--all-features".to_string()); |
89 | } else { | 90 | } else { |
90 | let mut features = Vec::new(); | 91 | let mut features = Vec::new(); |
91 | if let Some(cfg) = cfg.as_ref() { | 92 | if let Some(cfg) = cfg.as_ref() { |
92 | required_features(cfg, &mut features); | 93 | required_features(cfg, &mut features); |
93 | } | 94 | } |
94 | for feature in &snap.config.cargo.features { | 95 | for feature in cargo_config.features { |
95 | features.push(feature.clone()); | 96 | features.push(feature.clone()); |
96 | } | 97 | } |
97 | features.dedup(); | 98 | features.dedup(); |
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index 5a8484c62..7d3fda7a8 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs | |||
@@ -6,9 +6,12 @@ use anyhow::{bail, format_err, Result}; | |||
6 | use ide::{ | 6 | use ide::{ |
7 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, | 7 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, |
8 | }; | 8 | }; |
9 | use ide_db::base_db::{ | 9 | use ide_db::{ |
10 | salsa::{Database, Durability}, | 10 | base_db::{ |
11 | FileId, | 11 | salsa::{Database, Durability}, |
12 | FileId, | ||
13 | }, | ||
14 | helpers::SnippetCap, | ||
12 | }; | 15 | }; |
13 | use vfs::AbsPathBuf; | 16 | use vfs::AbsPathBuf; |
14 | 17 | ||
@@ -87,7 +90,14 @@ impl BenchCmd { | |||
87 | let file_position = FilePosition { file_id, offset }; | 90 | let file_position = FilePosition { file_id, offset }; |
88 | 91 | ||
89 | if is_completion { | 92 | if is_completion { |
90 | let options = CompletionConfig::default(); | 93 | let options = CompletionConfig { |
94 | enable_postfix_completions: true, | ||
95 | enable_autoimport_completions: true, | ||
96 | add_call_parenthesis: true, | ||
97 | add_call_argument_snippets: true, | ||
98 | snippet_cap: SnippetCap::new(true), | ||
99 | merge: None, | ||
100 | }; | ||
91 | let res = do_work(&mut host, file_id, |analysis| { | 101 | let res = do_work(&mut host, file_id, |analysis| { |
92 | analysis.completions(&options, file_position) | 102 | analysis.completions(&options, file_position) |
93 | }); | 103 | }); |
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index a23fb7a33..fd1407e60 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -58,7 +58,7 @@ impl AnalysisStatsCmd { | |||
58 | let mut db_load_sw = self.stop_watch(); | 58 | let mut db_load_sw = self.stop_watch(); |
59 | let (host, vfs) = load_cargo(&self.path, self.load_output_dirs, self.with_proc_macro)?; | 59 | let (host, vfs) = load_cargo(&self.path, self.load_output_dirs, self.with_proc_macro)?; |
60 | let db = host.raw_database(); | 60 | let db = host.raw_database(); |
61 | eprintln!("Database loaded {}", db_load_sw.elapsed()); | 61 | eprintln!("{:<20} {}", "Database loaded:", db_load_sw.elapsed()); |
62 | 62 | ||
63 | let mut analysis_sw = self.stop_watch(); | 63 | let mut analysis_sw = self.stop_watch(); |
64 | let mut num_crates = 0; | 64 | let mut num_crates = 0; |
@@ -85,7 +85,7 @@ impl AnalysisStatsCmd { | |||
85 | shuffle(&mut rng, &mut visit_queue); | 85 | shuffle(&mut rng, &mut visit_queue); |
86 | } | 86 | } |
87 | 87 | ||
88 | eprintln!("Crates in this dir: {}", num_crates); | 88 | eprint!(" crates: {}", num_crates); |
89 | let mut num_decls = 0; | 89 | let mut num_decls = 0; |
90 | let mut funcs = Vec::new(); | 90 | let mut funcs = Vec::new(); |
91 | while let Some(module) = visit_queue.pop() { | 91 | while let Some(module) = visit_queue.pop() { |
@@ -109,10 +109,8 @@ impl AnalysisStatsCmd { | |||
109 | } | 109 | } |
110 | } | 110 | } |
111 | } | 111 | } |
112 | eprintln!("Total modules found: {}", visited_modules.len()); | 112 | eprintln!(", mods: {}, decls: {}, fns: {}", visited_modules.len(), num_decls, funcs.len()); |
113 | eprintln!("Total declarations: {}", num_decls); | 113 | eprintln!("{:<20} {}", "Item Collection:", analysis_sw.elapsed()); |
114 | eprintln!("Total functions: {}", funcs.len()); | ||
115 | eprintln!("Item Collection: {}", analysis_sw.elapsed()); | ||
116 | 114 | ||
117 | if self.randomize { | 115 | if self.randomize { |
118 | shuffle(&mut rng, &mut funcs); | 116 | shuffle(&mut rng, &mut funcs); |
@@ -135,7 +133,7 @@ impl AnalysisStatsCmd { | |||
135 | snap.0.infer(f_id.into()); | 133 | snap.0.infer(f_id.into()); |
136 | }) | 134 | }) |
137 | .count(); | 135 | .count(); |
138 | eprintln!("Parallel Inference: {}", inference_sw.elapsed()); | 136 | eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); |
139 | } | 137 | } |
140 | 138 | ||
141 | let mut inference_sw = self.stop_watch(); | 139 | let mut inference_sw = self.stop_watch(); |
@@ -161,11 +159,12 @@ impl AnalysisStatsCmd { | |||
161 | } | 159 | } |
162 | let mut msg = format!("processing: {}", full_name); | 160 | let mut msg = format!("processing: {}", full_name); |
163 | if verbosity.is_verbose() { | 161 | if verbosity.is_verbose() { |
164 | let src = f.source(db); | 162 | if let Some(src) = f.source(db) { |
165 | let original_file = src.file_id.original_file(db); | 163 | let original_file = src.file_id.original_file(db); |
166 | let path = vfs.file_path(original_file); | 164 | let path = vfs.file_path(original_file); |
167 | let syntax_range = src.value.syntax().text_range(); | 165 | let syntax_range = src.value.syntax().text_range(); |
168 | format_to!(msg, " ({} {:?})", path, syntax_range); | 166 | format_to!(msg, " ({} {:?})", path, syntax_range); |
167 | } | ||
169 | } | 168 | } |
170 | if verbosity.is_spammy() { | 169 | if verbosity.is_spammy() { |
171 | bar.println(msg.to_string()); | 170 | bar.println(msg.to_string()); |
@@ -272,27 +271,22 @@ impl AnalysisStatsCmd { | |||
272 | bar.inc(1); | 271 | bar.inc(1); |
273 | } | 272 | } |
274 | bar.finish_and_clear(); | 273 | bar.finish_and_clear(); |
275 | eprintln!("Total expressions: {}", num_exprs); | ||
276 | eprintln!( | 274 | eprintln!( |
277 | "Expressions of unknown type: {} ({}%)", | 275 | " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}", |
276 | num_exprs, | ||
278 | num_exprs_unknown, | 277 | num_exprs_unknown, |
279 | if num_exprs > 0 { num_exprs_unknown * 100 / num_exprs } else { 100 } | 278 | percentage(num_exprs_unknown, num_exprs), |
280 | ); | ||
281 | report_metric("unknown type", num_exprs_unknown, "#"); | ||
282 | |||
283 | eprintln!( | ||
284 | "Expressions of partially unknown type: {} ({}%)", | ||
285 | num_exprs_partially_unknown, | 279 | num_exprs_partially_unknown, |
286 | if num_exprs > 0 { num_exprs_partially_unknown * 100 / num_exprs } else { 100 } | 280 | percentage(num_exprs_partially_unknown, num_exprs), |
281 | num_type_mismatches | ||
287 | ); | 282 | ); |
288 | 283 | report_metric("unknown type", num_exprs_unknown, "#"); | |
289 | eprintln!("Type mismatches: {}", num_type_mismatches); | ||
290 | report_metric("type mismatches", num_type_mismatches, "#"); | 284 | report_metric("type mismatches", num_type_mismatches, "#"); |
291 | 285 | ||
292 | eprintln!("Inference: {}", inference_sw.elapsed()); | 286 | eprintln!("{:<20} {}", "Inference:", inference_sw.elapsed()); |
293 | 287 | ||
294 | let total_span = analysis_sw.elapsed(); | 288 | let total_span = analysis_sw.elapsed(); |
295 | eprintln!("Total: {}", total_span); | 289 | eprintln!("{:<20} {}", "Total:", total_span); |
296 | report_metric("total time", total_span.time.as_millis() as u64, "ms"); | 290 | report_metric("total time", total_span.time.as_millis() as u64, "ms"); |
297 | if let Some(instructions) = total_span.instructions { | 291 | if let Some(instructions) = total_span.instructions { |
298 | report_metric("total instructions", instructions, "#instr"); | 292 | report_metric("total instructions", instructions, "#instr"); |
@@ -301,7 +295,7 @@ impl AnalysisStatsCmd { | |||
301 | report_metric("total memory", memory.allocated.megabytes() as u64, "MB"); | 295 | report_metric("total memory", memory.allocated.megabytes() as u64, "MB"); |
302 | } | 296 | } |
303 | 297 | ||
304 | if self.memory_usage { | 298 | if self.memory_usage && verbosity.is_verbose() { |
305 | print_memory_usage(host, vfs); | 299 | print_memory_usage(host, vfs); |
306 | } | 300 | } |
307 | 301 | ||
@@ -324,3 +318,7 @@ fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) { | |||
324 | slice.swap(0, idx); | 318 | slice.swap(0, idx); |
325 | } | 319 | } |
326 | } | 320 | } |
321 | |||
322 | fn percentage(n: u64, total: u64) -> u64 { | ||
323 | (n * 100).checked_div(total).unwrap_or(100) | ||
324 | } | ||
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index e5ab6c73b..31a16ca46 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -21,6 +21,7 @@ pub fn load_cargo( | |||
21 | let ws = ProjectWorkspace::load( | 21 | let ws = ProjectWorkspace::load( |
22 | root, | 22 | root, |
23 | &CargoConfig { load_out_dirs_from_check, ..Default::default() }, | 23 | &CargoConfig { load_out_dirs_from_check, ..Default::default() }, |
24 | &|_| {}, | ||
24 | )?; | 25 | )?; |
25 | 26 | ||
26 | let (sender, receiver) = unbounded(); | 27 | let (sender, receiver) = unbounded(); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1db5b4e7d..27b92a5a9 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -7,12 +7,15 @@ | |||
7 | //! configure the server itself, feature flags are passed into analysis, and | 7 | //! configure the server itself, feature flags are passed into analysis, and |
8 | //! tweak things like automatic insertion of `()` in completions. | 8 | //! tweak things like automatic insertion of `()` in completions. |
9 | 9 | ||
10 | use std::{convert::TryFrom, ffi::OsString, path::PathBuf}; | 10 | use std::{convert::TryFrom, ffi::OsString, iter, path::PathBuf}; |
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use hir::PrefixKind; | 13 | use hir::PrefixKind; |
14 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; | 14 | use ide::{ |
15 | use ide_db::helpers::insert_use::MergeBehavior; | 15 | AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig, |
16 | InsertUseConfig, | ||
17 | }; | ||
18 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | ||
16 | use itertools::Itertools; | 19 | use itertools::Itertools; |
17 | use lsp_types::{ClientCapabilities, MarkupKind}; | 20 | use lsp_types::{ClientCapabilities, MarkupKind}; |
18 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
@@ -20,12 +23,13 @@ use rustc_hash::FxHashSet; | |||
20 | use serde::{de::DeserializeOwned, Deserialize}; | 23 | use serde::{de::DeserializeOwned, Deserialize}; |
21 | use vfs::AbsPathBuf; | 24 | use vfs::AbsPathBuf; |
22 | 25 | ||
23 | use crate::{caps::enabled_completions_resolve_capabilities, diagnostics::DiagnosticsMapConfig}; | 26 | use crate::{caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig}; |
24 | 27 | ||
25 | config_data! { | 28 | config_data! { |
26 | struct ConfigData { | 29 | struct ConfigData { |
27 | /// The strategy to use when inserting new imports or merging imports. | 30 | /// The strategy to use when inserting new imports or merging imports. |
28 | assist_importMergeBehaviour: MergeBehaviorDef = "\"full\"", | 31 | assist_importMergeBehavior | |
32 | assist_importMergeBehaviour: MergeBehaviorDef = "\"full\"", | ||
29 | /// The path structure for newly inserted paths to use. | 33 | /// The path structure for newly inserted paths to use. |
30 | assist_importPrefix: ImportPrefixDef = "\"plain\"", | 34 | assist_importPrefix: ImportPrefixDef = "\"plain\"", |
31 | 35 | ||
@@ -148,13 +152,19 @@ config_data! { | |||
148 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, | 152 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, |
149 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. | 153 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. |
150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", | 154 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", |
155 | |||
151 | /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. | 156 | /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. |
152 | lruCapacity: Option<usize> = "null", | 157 | lruCapacity: Option<usize> = "null", |
158 | |||
153 | /// Whether to show `can't find Cargo.toml` error message. | 159 | /// Whether to show `can't find Cargo.toml` error message. |
154 | notifications_cargoTomlNotFound: bool = "true", | 160 | notifications_cargoTomlNotFound: bool = "true", |
161 | |||
155 | /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be | 162 | /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be |
156 | /// enabled. | 163 | /// enabled. |
157 | procMacro_enable: bool = "false", | 164 | procMacro_enable: bool = "false", |
165 | /// Internal config, path to proc-macro server executable (typically, | ||
166 | /// this is rust-analyzer itself, but we override this in tests). | ||
167 | procMacro_server: Option<PathBuf> = "null", | ||
158 | 168 | ||
159 | /// Command to be executed instead of 'cargo' for runnables. | 169 | /// Command to be executed instead of 'cargo' for runnables. |
160 | runnables_overrideCargo: Option<String> = "null", | 170 | runnables_overrideCargo: Option<String> = "null", |
@@ -163,7 +173,7 @@ config_data! { | |||
163 | runnables_cargoExtraArgs: Vec<String> = "[]", | 173 | runnables_cargoExtraArgs: Vec<String> = "[]", |
164 | 174 | ||
165 | /// Path to the rust compiler sources, for usage in rustc_private projects. | 175 | /// Path to the rust compiler sources, for usage in rustc_private projects. |
166 | rustcSource : Option<String> = "null", | 176 | rustcSource : Option<PathBuf> = "null", |
167 | 177 | ||
168 | /// Additional arguments to `rustfmt`. | 178 | /// Additional arguments to `rustfmt`. |
169 | rustfmt_extraArgs: Vec<String> = "[]", | 179 | rustfmt_extraArgs: Vec<String> = "[]", |
@@ -173,34 +183,17 @@ config_data! { | |||
173 | } | 183 | } |
174 | } | 184 | } |
175 | 185 | ||
186 | impl Default for ConfigData { | ||
187 | fn default() -> Self { | ||
188 | ConfigData::from_json(serde_json::Value::Null) | ||
189 | } | ||
190 | } | ||
191 | |||
176 | #[derive(Debug, Clone)] | 192 | #[derive(Debug, Clone)] |
177 | pub struct Config { | 193 | pub struct Config { |
178 | pub client_caps: ClientCapsConfig, | 194 | caps: lsp_types::ClientCapabilities, |
179 | 195 | data: ConfigData, | |
180 | pub publish_diagnostics: bool, | 196 | pub discovered_projects: Option<Vec<ProjectManifest>>, |
181 | pub diagnostics: DiagnosticsConfig, | ||
182 | pub diagnostics_map: DiagnosticsMapConfig, | ||
183 | pub lru_capacity: Option<usize>, | ||
184 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, | ||
185 | pub files: FilesConfig, | ||
186 | pub notifications: NotificationsConfig, | ||
187 | |||
188 | pub cargo_autoreload: bool, | ||
189 | pub cargo: CargoConfig, | ||
190 | pub rustfmt: RustfmtConfig, | ||
191 | pub flycheck: Option<FlycheckConfig>, | ||
192 | pub runnables: RunnablesConfig, | ||
193 | |||
194 | pub inlay_hints: InlayHintsConfig, | ||
195 | pub completion: CompletionConfig, | ||
196 | pub assist: AssistConfig, | ||
197 | pub call_info_full: bool, | ||
198 | pub lens: LensConfig, | ||
199 | pub hover: HoverConfig, | ||
200 | pub semantic_tokens_refresh: bool, | ||
201 | pub code_lens_refresh: bool, | ||
202 | |||
203 | pub linked_projects: Vec<LinkedProject>, | ||
204 | pub root_path: AbsPathBuf, | 197 | pub root_path: AbsPathBuf, |
205 | } | 198 | } |
206 | 199 | ||
@@ -230,12 +223,6 @@ pub struct LensConfig { | |||
230 | pub method_refs: bool, | 223 | pub method_refs: bool, |
231 | } | 224 | } |
232 | 225 | ||
233 | impl Default for LensConfig { | ||
234 | fn default() -> Self { | ||
235 | Self { run: true, debug: true, implementations: true, method_refs: false } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | impl LensConfig { | 226 | impl LensConfig { |
240 | pub fn any(&self) -> bool { | 227 | pub fn any(&self) -> bool { |
241 | self.implementations || self.runnable() || self.references() | 228 | self.implementations || self.runnable() || self.references() |
@@ -278,7 +265,7 @@ pub enum RustfmtConfig { | |||
278 | } | 265 | } |
279 | 266 | ||
280 | /// Configuration for runnable items, such as `main` function or tests. | 267 | /// Configuration for runnable items, such as `main` function or tests. |
281 | #[derive(Debug, Clone, Default)] | 268 | #[derive(Debug, Clone)] |
282 | pub struct RunnablesConfig { | 269 | pub struct RunnablesConfig { |
283 | /// Custom command to be executed instead of `cargo` for runnables. | 270 | /// Custom command to be executed instead of `cargo` for runnables. |
284 | pub override_cargo: Option<String>, | 271 | pub override_cargo: Option<String>, |
@@ -286,325 +273,366 @@ pub struct RunnablesConfig { | |||
286 | pub cargo_extra_args: Vec<String>, | 273 | pub cargo_extra_args: Vec<String>, |
287 | } | 274 | } |
288 | 275 | ||
289 | #[derive(Debug, Clone, Default)] | ||
290 | pub struct ClientCapsConfig { | ||
291 | pub location_link: bool, | ||
292 | pub line_folding_only: bool, | ||
293 | pub hierarchical_symbols: bool, | ||
294 | pub code_action_literals: bool, | ||
295 | pub work_done_progress: bool, | ||
296 | pub code_action_group: bool, | ||
297 | pub code_action_resolve: bool, | ||
298 | pub hover_actions: bool, | ||
299 | pub status_notification: bool, | ||
300 | pub signature_help_label_offsets: bool, | ||
301 | } | ||
302 | |||
303 | impl Config { | 276 | impl Config { |
304 | pub fn new(root_path: AbsPathBuf) -> Self { | 277 | pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { |
305 | // Defaults here don't matter, we'll immediately re-write them with | 278 | Config { caps, data: ConfigData::default(), discovered_projects: None, root_path } |
306 | // ConfigData. | ||
307 | let mut res = Config { | ||
308 | client_caps: ClientCapsConfig::default(), | ||
309 | |||
310 | publish_diagnostics: false, | ||
311 | diagnostics: DiagnosticsConfig::default(), | ||
312 | diagnostics_map: DiagnosticsMapConfig::default(), | ||
313 | lru_capacity: None, | ||
314 | proc_macro_srv: None, | ||
315 | files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, | ||
316 | notifications: NotificationsConfig { cargo_toml_not_found: false }, | ||
317 | |||
318 | cargo_autoreload: false, | ||
319 | cargo: CargoConfig::default(), | ||
320 | rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, | ||
321 | flycheck: Some(FlycheckConfig::CargoCommand { | ||
322 | command: String::new(), | ||
323 | target_triple: None, | ||
324 | no_default_features: false, | ||
325 | all_targets: false, | ||
326 | all_features: false, | ||
327 | extra_args: Vec::new(), | ||
328 | features: Vec::new(), | ||
329 | }), | ||
330 | runnables: RunnablesConfig::default(), | ||
331 | |||
332 | inlay_hints: InlayHintsConfig { | ||
333 | type_hints: false, | ||
334 | parameter_hints: false, | ||
335 | chaining_hints: false, | ||
336 | max_length: None, | ||
337 | }, | ||
338 | completion: CompletionConfig::default(), | ||
339 | assist: AssistConfig::default(), | ||
340 | call_info_full: false, | ||
341 | lens: LensConfig::default(), | ||
342 | hover: HoverConfig::default(), | ||
343 | semantic_tokens_refresh: false, | ||
344 | code_lens_refresh: false, | ||
345 | linked_projects: Vec::new(), | ||
346 | root_path, | ||
347 | }; | ||
348 | res.do_update(serde_json::json!({})); | ||
349 | res | ||
350 | } | 279 | } |
351 | pub fn update(&mut self, json: serde_json::Value) { | 280 | pub fn update(&mut self, json: serde_json::Value) { |
352 | log::info!("updating config from JSON: {:#}", json); | 281 | log::info!("updating config from JSON: {:#}", json); |
353 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { | 282 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { |
354 | return; | 283 | return; |
355 | } | 284 | } |
356 | self.do_update(json); | 285 | self.data = ConfigData::from_json(json); |
357 | log::info!("updated config: {:#?}", self); | ||
358 | } | 286 | } |
359 | fn do_update(&mut self, json: serde_json::Value) { | ||
360 | let data = ConfigData::from_json(json); | ||
361 | |||
362 | self.publish_diagnostics = data.diagnostics_enable; | ||
363 | self.diagnostics = DiagnosticsConfig { | ||
364 | disable_experimental: !data.diagnostics_enableExperimental, | ||
365 | disabled: data.diagnostics_disabled, | ||
366 | }; | ||
367 | self.diagnostics_map = DiagnosticsMapConfig { | ||
368 | warnings_as_info: data.diagnostics_warningsAsInfo, | ||
369 | warnings_as_hint: data.diagnostics_warningsAsHint, | ||
370 | }; | ||
371 | self.lru_capacity = data.lruCapacity; | ||
372 | self.files.watcher = match data.files_watcher.as_str() { | ||
373 | "notify" => FilesWatcher::Notify, | ||
374 | "client" | _ => FilesWatcher::Client, | ||
375 | }; | ||
376 | self.notifications = | ||
377 | NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound }; | ||
378 | self.cargo_autoreload = data.cargo_autoreload; | ||
379 | |||
380 | let rustc_source = if let Some(rustc_source) = data.rustcSource { | ||
381 | let rustpath: PathBuf = rustc_source.into(); | ||
382 | AbsPathBuf::try_from(rustpath) | ||
383 | .map_err(|_| { | ||
384 | log::error!("rustc source directory must be an absolute path"); | ||
385 | }) | ||
386 | .ok() | ||
387 | } else { | ||
388 | None | ||
389 | }; | ||
390 | |||
391 | self.cargo = CargoConfig { | ||
392 | no_default_features: data.cargo_noDefaultFeatures, | ||
393 | all_features: data.cargo_allFeatures, | ||
394 | features: data.cargo_features.clone(), | ||
395 | load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck, | ||
396 | target: data.cargo_target.clone(), | ||
397 | rustc_source: rustc_source, | ||
398 | no_sysroot: data.cargo_noSysroot, | ||
399 | }; | ||
400 | self.runnables = RunnablesConfig { | ||
401 | override_cargo: data.runnables_overrideCargo, | ||
402 | cargo_extra_args: data.runnables_cargoExtraArgs, | ||
403 | }; | ||
404 | 287 | ||
405 | self.proc_macro_srv = if data.procMacro_enable { | 288 | pub fn json_schema() -> serde_json::Value { |
406 | std::env::current_exe().ok().map(|path| (path, vec!["proc-macro".into()])) | 289 | ConfigData::json_schema() |
407 | } else { | 290 | } |
408 | None | 291 | } |
409 | }; | ||
410 | 292 | ||
411 | self.rustfmt = match data.rustfmt_overrideCommand { | 293 | macro_rules! try_ { |
412 | Some(mut args) if !args.is_empty() => { | 294 | ($expr:expr) => { |
413 | let command = args.remove(0); | 295 | || -> _ { Some($expr) }() |
414 | RustfmtConfig::CustomCommand { command, args } | 296 | }; |
415 | } | 297 | } |
416 | Some(_) | None => RustfmtConfig::Rustfmt { extra_args: data.rustfmt_extraArgs }, | 298 | macro_rules! try_or { |
417 | }; | 299 | ($expr:expr, $or:expr) => { |
300 | try_!($expr).unwrap_or($or) | ||
301 | }; | ||
302 | } | ||
418 | 303 | ||
419 | self.flycheck = if data.checkOnSave_enable { | 304 | impl Config { |
420 | let flycheck_config = match data.checkOnSave_overrideCommand { | 305 | pub fn linked_projects(&self) -> Vec<LinkedProject> { |
421 | Some(mut args) if !args.is_empty() => { | 306 | if self.data.linkedProjects.is_empty() { |
422 | let command = args.remove(0); | 307 | self.discovered_projects |
423 | FlycheckConfig::CustomCommand { command, args } | 308 | .as_ref() |
424 | } | 309 | .into_iter() |
425 | Some(_) | None => FlycheckConfig::CargoCommand { | 310 | .flatten() |
426 | command: data.checkOnSave_command, | 311 | .cloned() |
427 | target_triple: data.checkOnSave_target.or(data.cargo_target), | 312 | .map(LinkedProject::from) |
428 | all_targets: data.checkOnSave_allTargets, | 313 | .collect() |
429 | no_default_features: data | ||
430 | .checkOnSave_noDefaultFeatures | ||
431 | .unwrap_or(data.cargo_noDefaultFeatures), | ||
432 | all_features: data.checkOnSave_allFeatures.unwrap_or(data.cargo_allFeatures), | ||
433 | features: data.checkOnSave_features.unwrap_or(data.cargo_features), | ||
434 | extra_args: data.checkOnSave_extraArgs, | ||
435 | }, | ||
436 | }; | ||
437 | Some(flycheck_config) | ||
438 | } else { | 314 | } else { |
439 | None | 315 | self.data |
440 | }; | 316 | .linkedProjects |
441 | 317 | .iter() | |
442 | self.inlay_hints = InlayHintsConfig { | 318 | .filter_map(|linked_project| { |
443 | type_hints: data.inlayHints_typeHints, | 319 | let res = match linked_project { |
444 | parameter_hints: data.inlayHints_parameterHints, | 320 | ManifestOrProjectJson::Manifest(it) => { |
445 | chaining_hints: data.inlayHints_chainingHints, | 321 | let path = self.root_path.join(it); |
446 | max_length: data.inlayHints_maxLength, | 322 | ProjectManifest::from_manifest_file(path) |
447 | }; | 323 | .map_err(|e| log::error!("failed to load linked project: {}", e)) |
448 | 324 | .ok()? | |
449 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { | 325 | .into() |
450 | MergeBehaviorDef::None => None, | ||
451 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | ||
452 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
453 | }; | ||
454 | self.assist.insert_use.prefix_kind = match data.assist_importPrefix { | ||
455 | ImportPrefixDef::Plain => PrefixKind::Plain, | ||
456 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | ||
457 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | ||
458 | }; | ||
459 | |||
460 | self.completion.enable_postfix_completions = data.completion_postfix_enable; | ||
461 | self.completion.enable_autoimport_completions = data.completion_autoimport_enable; | ||
462 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | ||
463 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | ||
464 | self.completion.merge = self.assist.insert_use.merge; | ||
465 | |||
466 | self.call_info_full = data.callInfo_full; | ||
467 | |||
468 | self.lens = LensConfig { | ||
469 | run: data.lens_enable && data.lens_run, | ||
470 | debug: data.lens_enable && data.lens_debug, | ||
471 | implementations: data.lens_enable && data.lens_implementations, | ||
472 | method_refs: data.lens_enable && data.lens_methodReferences, | ||
473 | }; | ||
474 | |||
475 | if !data.linkedProjects.is_empty() { | ||
476 | self.linked_projects.clear(); | ||
477 | for linked_project in data.linkedProjects { | ||
478 | let linked_project = match linked_project { | ||
479 | ManifestOrProjectJson::Manifest(it) => { | ||
480 | let path = self.root_path.join(it); | ||
481 | match ProjectManifest::from_manifest_file(path) { | ||
482 | Ok(it) => it.into(), | ||
483 | Err(e) => { | ||
484 | log::error!("failed to load linked project: {}", e); | ||
485 | continue; | ||
486 | } | ||
487 | } | 326 | } |
488 | } | 327 | ManifestOrProjectJson::ProjectJson(it) => { |
489 | ManifestOrProjectJson::ProjectJson(it) => { | 328 | ProjectJson::new(&self.root_path, it.clone()).into() |
490 | ProjectJson::new(&self.root_path, it).into() | 329 | } |
491 | } | 330 | }; |
492 | }; | 331 | Some(res) |
493 | self.linked_projects.push(linked_project); | 332 | }) |
494 | } | 333 | .collect() |
495 | } | 334 | } |
335 | } | ||
496 | 336 | ||
497 | self.hover = HoverConfig { | 337 | pub fn did_save_text_document_dynamic_registration(&self) -> bool { |
498 | implementations: data.hoverActions_enable && data.hoverActions_implementations, | 338 | let caps = |
499 | run: data.hoverActions_enable && data.hoverActions_run, | 339 | try_or!(self.caps.text_document.as_ref()?.synchronization.clone()?, Default::default()); |
500 | debug: data.hoverActions_enable && data.hoverActions_debug, | 340 | caps.did_save == Some(true) && caps.dynamic_registration == Some(true) |
501 | goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef, | 341 | } |
502 | links_in_hover: data.hoverActions_linksInHover, | 342 | pub fn did_change_watched_files_dynamic_registration(&self) -> bool { |
503 | markdown: true, | 343 | try_or!( |
504 | }; | 344 | self.caps.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration?, |
345 | false | ||
346 | ) | ||
505 | } | 347 | } |
506 | 348 | ||
507 | pub fn update_caps(&mut self, caps: &ClientCapabilities) { | 349 | pub fn location_link(&self) -> bool { |
508 | if let Some(doc_caps) = caps.text_document.as_ref() { | 350 | try_or!(self.caps.text_document.as_ref()?.definition?.link_support?, false) |
509 | if let Some(value) = doc_caps.hover.as_ref().and_then(|it| it.content_format.as_ref()) { | 351 | } |
510 | self.hover.markdown = value.contains(&MarkupKind::Markdown) | 352 | pub fn line_folding_only(&self) -> bool { |
511 | } | 353 | try_or!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?, false) |
512 | if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) { | 354 | } |
513 | self.client_caps.location_link = value; | 355 | pub fn hierarchical_symbols(&self) -> bool { |
514 | } | 356 | try_or!( |
515 | if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only) | 357 | self.caps |
516 | { | 358 | .text_document |
517 | self.client_caps.line_folding_only = value | 359 | .as_ref()? |
518 | } | ||
519 | if let Some(value) = doc_caps | ||
520 | .document_symbol | 360 | .document_symbol |
521 | .as_ref() | 361 | .as_ref()? |
522 | .and_then(|it| it.hierarchical_document_symbol_support) | 362 | .hierarchical_document_symbol_support?, |
523 | { | 363 | false |
524 | self.client_caps.hierarchical_symbols = value | 364 | ) |
525 | } | 365 | } |
526 | if let Some(value) = | 366 | pub fn code_action_literals(&self) -> bool { |
527 | doc_caps.code_action.as_ref().map(|it| it.code_action_literal_support.is_some()) | 367 | try_!(self |
528 | { | 368 | .caps |
529 | self.client_caps.code_action_literals = value; | 369 | .text_document |
530 | } | 370 | .as_ref()? |
531 | if let Some(value) = doc_caps | 371 | .code_action |
372 | .as_ref()? | ||
373 | .code_action_literal_support | ||
374 | .as_ref()?) | ||
375 | .is_some() | ||
376 | } | ||
377 | pub fn work_done_progress(&self) -> bool { | ||
378 | try_or!(self.caps.window.as_ref()?.work_done_progress?, false) | ||
379 | } | ||
380 | pub fn code_action_resolve(&self) -> bool { | ||
381 | try_or!( | ||
382 | self.caps | ||
383 | .text_document | ||
384 | .as_ref()? | ||
385 | .code_action | ||
386 | .as_ref()? | ||
387 | .resolve_support | ||
388 | .as_ref()? | ||
389 | .properties | ||
390 | .as_slice(), | ||
391 | &[] | ||
392 | ) | ||
393 | .iter() | ||
394 | .any(|it| it == "edit") | ||
395 | } | ||
396 | pub fn signature_help_label_offsets(&self) -> bool { | ||
397 | try_or!( | ||
398 | self.caps | ||
399 | .text_document | ||
400 | .as_ref()? | ||
532 | .signature_help | 401 | .signature_help |
533 | .as_ref() | 402 | .as_ref()? |
534 | .and_then(|it| it.signature_information.as_ref()) | 403 | .signature_information |
535 | .and_then(|it| it.parameter_information.as_ref()) | 404 | .as_ref()? |
536 | .and_then(|it| it.label_offset_support) | 405 | .parameter_information |
537 | { | 406 | .as_ref()? |
538 | self.client_caps.signature_help_label_offsets = value; | 407 | .label_offset_support?, |
539 | } | 408 | false |
409 | ) | ||
410 | } | ||
540 | 411 | ||
541 | self.completion.allow_snippets(false); | 412 | fn experimental(&self, index: &'static str) -> bool { |
542 | self.completion.active_resolve_capabilities = | 413 | try_or!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?, false) |
543 | enabled_completions_resolve_capabilities(caps).unwrap_or_default(); | 414 | } |
544 | if let Some(completion) = &doc_caps.completion { | 415 | pub fn code_action_group(&self) -> bool { |
545 | if let Some(completion_item) = &completion.completion_item { | 416 | self.experimental("codeActionGroup") |
546 | if let Some(value) = completion_item.snippet_support { | 417 | } |
547 | self.completion.allow_snippets(value); | 418 | pub fn hover_actions(&self) -> bool { |
548 | } | 419 | self.experimental("hoverActions") |
549 | } | 420 | } |
550 | } | 421 | pub fn status_notification(&self) -> bool { |
422 | self.experimental("statusNotification") | ||
423 | } | ||
551 | 424 | ||
552 | if let Some(code_action) = &doc_caps.code_action { | 425 | pub fn publish_diagnostics(&self) -> bool { |
553 | if let Some(resolve_support) = &code_action.resolve_support { | 426 | self.data.diagnostics_enable |
554 | if resolve_support.properties.iter().any(|it| it == "edit") { | 427 | } |
555 | self.client_caps.code_action_resolve = true; | 428 | pub fn diagnostics(&self) -> DiagnosticsConfig { |
556 | } | 429 | DiagnosticsConfig { |
557 | } | 430 | disable_experimental: !self.data.diagnostics_enableExperimental, |
558 | } | 431 | disabled: self.data.diagnostics_disabled.clone(), |
559 | } | 432 | } |
560 | 433 | } | |
561 | if let Some(window_caps) = caps.window.as_ref() { | 434 | pub fn diagnostics_map(&self) -> DiagnosticsMapConfig { |
562 | if let Some(value) = window_caps.work_done_progress { | 435 | DiagnosticsMapConfig { |
563 | self.client_caps.work_done_progress = value; | 436 | warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(), |
564 | } | 437 | warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(), |
565 | } | 438 | } |
566 | 439 | } | |
567 | self.assist.allow_snippets(false); | 440 | pub fn lru_capacity(&self) -> Option<usize> { |
568 | if let Some(experimental) = &caps.experimental { | 441 | self.data.lruCapacity |
569 | let get_bool = | 442 | } |
570 | |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true); | 443 | pub fn proc_macro_srv(&self) -> Option<(PathBuf, Vec<OsString>)> { |
571 | 444 | if !self.data.procMacro_enable { | |
572 | let snippet_text_edit = get_bool("snippetTextEdit"); | 445 | return None; |
573 | self.assist.allow_snippets(snippet_text_edit); | ||
574 | |||
575 | self.client_caps.code_action_group = get_bool("codeActionGroup"); | ||
576 | self.client_caps.hover_actions = get_bool("hoverActions"); | ||
577 | self.client_caps.status_notification = get_bool("statusNotification"); | ||
578 | } | 446 | } |
579 | 447 | ||
580 | if let Some(workspace_caps) = caps.workspace.as_ref() { | 448 | let path = self.data.procMacro_server.clone().or_else(|| std::env::current_exe().ok())?; |
581 | if let Some(refresh_support) = | 449 | Some((path, vec!["proc-macro".into()])) |
582 | workspace_caps.semantic_tokens.as_ref().and_then(|it| it.refresh_support) | 450 | } |
583 | { | 451 | pub fn files(&self) -> FilesConfig { |
584 | self.semantic_tokens_refresh = refresh_support; | 452 | FilesConfig { |
453 | watcher: match self.data.files_watcher.as_str() { | ||
454 | "notify" => FilesWatcher::Notify, | ||
455 | "client" | _ => FilesWatcher::Client, | ||
456 | }, | ||
457 | exclude: Vec::new(), | ||
458 | } | ||
459 | } | ||
460 | pub fn notifications(&self) -> NotificationsConfig { | ||
461 | NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound } | ||
462 | } | ||
463 | pub fn cargo_autoreload(&self) -> bool { | ||
464 | self.data.cargo_autoreload | ||
465 | } | ||
466 | pub fn cargo(&self) -> CargoConfig { | ||
467 | let rustc_source = self.data.rustcSource.clone().and_then(|it| { | ||
468 | AbsPathBuf::try_from(it) | ||
469 | .map_err(|_| log::error!("rustc source directory must be an absolute path")) | ||
470 | .ok() | ||
471 | }); | ||
472 | |||
473 | CargoConfig { | ||
474 | no_default_features: self.data.cargo_noDefaultFeatures, | ||
475 | all_features: self.data.cargo_allFeatures, | ||
476 | features: self.data.cargo_features.clone(), | ||
477 | load_out_dirs_from_check: self.data.cargo_loadOutDirsFromCheck, | ||
478 | target: self.data.cargo_target.clone(), | ||
479 | rustc_source, | ||
480 | no_sysroot: self.data.cargo_noSysroot, | ||
481 | } | ||
482 | } | ||
483 | pub fn rustfmt(&self) -> RustfmtConfig { | ||
484 | match &self.data.rustfmt_overrideCommand { | ||
485 | Some(args) if !args.is_empty() => { | ||
486 | let mut args = args.clone(); | ||
487 | let command = args.remove(0); | ||
488 | RustfmtConfig::CustomCommand { command, args } | ||
585 | } | 489 | } |
586 | 490 | Some(_) | None => { | |
587 | if let Some(refresh_support) = | 491 | RustfmtConfig::Rustfmt { extra_args: self.data.rustfmt_extraArgs.clone() } |
588 | workspace_caps.code_lens.as_ref().and_then(|it| it.refresh_support) | ||
589 | { | ||
590 | self.code_lens_refresh = refresh_support; | ||
591 | } | 492 | } |
592 | } | 493 | } |
593 | } | 494 | } |
594 | 495 | pub fn flycheck(&self) -> Option<FlycheckConfig> { | |
595 | pub fn json_schema() -> serde_json::Value { | 496 | if !self.data.checkOnSave_enable { |
596 | ConfigData::json_schema() | 497 | return None; |
498 | } | ||
499 | let flycheck_config = match &self.data.checkOnSave_overrideCommand { | ||
500 | Some(args) if !args.is_empty() => { | ||
501 | let mut args = args.clone(); | ||
502 | let command = args.remove(0); | ||
503 | FlycheckConfig::CustomCommand { command, args } | ||
504 | } | ||
505 | Some(_) | None => FlycheckConfig::CargoCommand { | ||
506 | command: self.data.checkOnSave_command.clone(), | ||
507 | target_triple: self | ||
508 | .data | ||
509 | .checkOnSave_target | ||
510 | .clone() | ||
511 | .or(self.data.cargo_target.clone()), | ||
512 | all_targets: self.data.checkOnSave_allTargets, | ||
513 | no_default_features: self | ||
514 | .data | ||
515 | .checkOnSave_noDefaultFeatures | ||
516 | .unwrap_or(self.data.cargo_noDefaultFeatures), | ||
517 | all_features: self | ||
518 | .data | ||
519 | .checkOnSave_allFeatures | ||
520 | .unwrap_or(self.data.cargo_allFeatures), | ||
521 | features: self | ||
522 | .data | ||
523 | .checkOnSave_features | ||
524 | .clone() | ||
525 | .unwrap_or(self.data.cargo_features.clone()), | ||
526 | extra_args: self.data.checkOnSave_extraArgs.clone(), | ||
527 | }, | ||
528 | }; | ||
529 | Some(flycheck_config) | ||
530 | } | ||
531 | pub fn runnables(&self) -> RunnablesConfig { | ||
532 | RunnablesConfig { | ||
533 | override_cargo: self.data.runnables_overrideCargo.clone(), | ||
534 | cargo_extra_args: self.data.runnables_cargoExtraArgs.clone(), | ||
535 | } | ||
536 | } | ||
537 | pub fn inlay_hints(&self) -> InlayHintsConfig { | ||
538 | InlayHintsConfig { | ||
539 | type_hints: self.data.inlayHints_typeHints, | ||
540 | parameter_hints: self.data.inlayHints_parameterHints, | ||
541 | chaining_hints: self.data.inlayHints_chainingHints, | ||
542 | max_length: self.data.inlayHints_maxLength, | ||
543 | } | ||
544 | } | ||
545 | fn merge_behavior(&self) -> Option<MergeBehavior> { | ||
546 | match self.data.assist_importMergeBehavior { | ||
547 | MergeBehaviorDef::None => None, | ||
548 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | ||
549 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
550 | } | ||
551 | } | ||
552 | pub fn completion(&self) -> CompletionConfig { | ||
553 | CompletionConfig { | ||
554 | enable_postfix_completions: self.data.completion_postfix_enable, | ||
555 | enable_autoimport_completions: self.data.completion_autoimport_enable | ||
556 | && completion_item_edit_resolve(&self.caps), | ||
557 | add_call_parenthesis: self.data.completion_addCallParenthesis, | ||
558 | add_call_argument_snippets: self.data.completion_addCallArgumentSnippets, | ||
559 | merge: self.merge_behavior(), | ||
560 | snippet_cap: SnippetCap::new(try_or!( | ||
561 | self.caps | ||
562 | .text_document | ||
563 | .as_ref()? | ||
564 | .completion | ||
565 | .as_ref()? | ||
566 | .completion_item | ||
567 | .as_ref()? | ||
568 | .snippet_support?, | ||
569 | false | ||
570 | )), | ||
571 | } | ||
572 | } | ||
573 | pub fn assist(&self) -> AssistConfig { | ||
574 | AssistConfig { | ||
575 | snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), | ||
576 | allowed: None, | ||
577 | insert_use: InsertUseConfig { | ||
578 | merge: self.merge_behavior(), | ||
579 | prefix_kind: match self.data.assist_importPrefix { | ||
580 | ImportPrefixDef::Plain => PrefixKind::Plain, | ||
581 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | ||
582 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | ||
583 | }, | ||
584 | }, | ||
585 | } | ||
586 | } | ||
587 | pub fn call_info_full(&self) -> bool { | ||
588 | self.data.callInfo_full | ||
589 | } | ||
590 | pub fn lens(&self) -> LensConfig { | ||
591 | LensConfig { | ||
592 | run: self.data.lens_enable && self.data.lens_run, | ||
593 | debug: self.data.lens_enable && self.data.lens_debug, | ||
594 | implementations: self.data.lens_enable && self.data.lens_implementations, | ||
595 | method_refs: self.data.lens_enable && self.data.lens_methodReferences, | ||
596 | } | ||
597 | } | ||
598 | pub fn hover(&self) -> HoverConfig { | ||
599 | HoverConfig { | ||
600 | implementations: self.data.hoverActions_enable | ||
601 | && self.data.hoverActions_implementations, | ||
602 | run: self.data.hoverActions_enable && self.data.hoverActions_run, | ||
603 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, | ||
604 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, | ||
605 | links_in_hover: self.data.hoverActions_linksInHover, | ||
606 | markdown: try_or!( | ||
607 | self.caps | ||
608 | .text_document | ||
609 | .as_ref()? | ||
610 | .hover | ||
611 | .as_ref()? | ||
612 | .content_format | ||
613 | .as_ref()? | ||
614 | .as_slice(), | ||
615 | &[] | ||
616 | ) | ||
617 | .contains(&MarkupKind::Markdown), | ||
618 | } | ||
619 | } | ||
620 | pub fn semantic_tokens_refresh(&self) -> bool { | ||
621 | try_or!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?, false) | ||
622 | } | ||
623 | pub fn code_lens_refresh(&self) -> bool { | ||
624 | try_or!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?, false) | ||
597 | } | 625 | } |
598 | } | 626 | } |
599 | 627 | ||
600 | #[derive(Deserialize)] | 628 | #[derive(Deserialize, Debug, Clone)] |
601 | #[serde(untagged)] | 629 | #[serde(untagged)] |
602 | enum ManifestOrProjectJson { | 630 | enum ManifestOrProjectJson { |
603 | Manifest(PathBuf), | 631 | Manifest(PathBuf), |
604 | ProjectJson(ProjectJsonData), | 632 | ProjectJson(ProjectJsonData), |
605 | } | 633 | } |
606 | 634 | ||
607 | #[derive(Deserialize)] | 635 | #[derive(Deserialize, Debug, Clone)] |
608 | #[serde(rename_all = "snake_case")] | 636 | #[serde(rename_all = "snake_case")] |
609 | enum MergeBehaviorDef { | 637 | enum MergeBehaviorDef { |
610 | None, | 638 | None, |
@@ -612,7 +640,7 @@ enum MergeBehaviorDef { | |||
612 | Last, | 640 | Last, |
613 | } | 641 | } |
614 | 642 | ||
615 | #[derive(Deserialize)] | 643 | #[derive(Deserialize, Debug, Clone)] |
616 | #[serde(rename_all = "snake_case")] | 644 | #[serde(rename_all = "snake_case")] |
617 | enum ImportPrefixDef { | 645 | enum ImportPrefixDef { |
618 | Plain, | 646 | Plain, |
@@ -624,15 +652,21 @@ macro_rules! _config_data { | |||
624 | (struct $name:ident { | 652 | (struct $name:ident { |
625 | $( | 653 | $( |
626 | $(#[doc=$doc:literal])* | 654 | $(#[doc=$doc:literal])* |
627 | $field:ident: $ty:ty = $default:expr, | 655 | $field:ident $(| $alias:ident)?: $ty:ty = $default:expr, |
628 | )* | 656 | )* |
629 | }) => { | 657 | }) => { |
630 | #[allow(non_snake_case)] | 658 | #[allow(non_snake_case)] |
659 | #[derive(Debug, Clone)] | ||
631 | struct $name { $($field: $ty,)* } | 660 | struct $name { $($field: $ty,)* } |
632 | impl $name { | 661 | impl $name { |
633 | fn from_json(mut json: serde_json::Value) -> $name { | 662 | fn from_json(mut json: serde_json::Value) -> $name { |
634 | $name {$( | 663 | $name {$( |
635 | $field: get_field(&mut json, stringify!($field), $default), | 664 | $field: get_field( |
665 | &mut json, | ||
666 | stringify!($field), | ||
667 | None$(.or(Some(stringify!($alias))))?, | ||
668 | $default, | ||
669 | ), | ||
636 | )*} | 670 | )*} |
637 | } | 671 | } |
638 | 672 | ||
@@ -664,14 +698,21 @@ use _config_data as config_data; | |||
664 | fn get_field<T: DeserializeOwned>( | 698 | fn get_field<T: DeserializeOwned>( |
665 | json: &mut serde_json::Value, | 699 | json: &mut serde_json::Value, |
666 | field: &'static str, | 700 | field: &'static str, |
701 | alias: Option<&'static str>, | ||
667 | default: &str, | 702 | default: &str, |
668 | ) -> T { | 703 | ) -> T { |
669 | let default = serde_json::from_str(default).unwrap(); | 704 | let default = serde_json::from_str(default).unwrap(); |
670 | 705 | ||
671 | let mut pointer = field.replace('_', "/"); | 706 | // XXX: check alias first, to work-around the VS Code where it pre-fills the |
672 | pointer.insert(0, '/'); | 707 | // defaults instead of sending an empty object. |
673 | json.pointer_mut(&pointer) | 708 | alias |
674 | .and_then(|it| serde_json::from_value(it.take()).ok()) | 709 | .into_iter() |
710 | .chain(iter::once(field)) | ||
711 | .find_map(move |field| { | ||
712 | let mut pointer = field.replace('_', "/"); | ||
713 | pointer.insert(0, '/'); | ||
714 | json.pointer_mut(&pointer).and_then(|it| serde_json::from_value(it.take()).ok()) | ||
715 | }) | ||
675 | .unwrap_or(default) | 716 | .unwrap_or(default) |
676 | } | 717 | } |
677 | 718 | ||
@@ -679,7 +720,7 @@ fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json: | |||
679 | for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { | 720 | for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { |
680 | fn key(f: &str) -> &str { | 721 | fn key(f: &str) -> &str { |
681 | f.splitn(2, "_").next().unwrap() | 722 | f.splitn(2, "_").next().unwrap() |
682 | }; | 723 | } |
683 | assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); | 724 | assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); |
684 | } | 725 | } |
685 | 726 | ||
@@ -733,6 +774,9 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json | |||
733 | "Option<String>" => set! { | 774 | "Option<String>" => set! { |
734 | "type": ["null", "string"], | 775 | "type": ["null", "string"], |
735 | }, | 776 | }, |
777 | "Option<PathBuf>" => set! { | ||
778 | "type": ["null", "string"], | ||
779 | }, | ||
736 | "Option<bool>" => set! { | 780 | "Option<bool>" => set! { |
737 | "type": ["null", "boolean"], | 781 | "type": ["null", "boolean"], |
738 | }, | 782 | }, |
@@ -777,9 +821,8 @@ fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String { | |||
777 | fields | 821 | fields |
778 | .iter() | 822 | .iter() |
779 | .map(|(field, _ty, doc, default)| { | 823 | .map(|(field, _ty, doc, default)| { |
780 | let name = field.replace("_", "."); | 824 | let name = format!("rust-analyzer.{}", field.replace("_", ".")); |
781 | let name = format!("rust-analyzer.{} (default: `{}`)", name, default); | 825 | format!("[[{}]]{} (default: `{}`)::\n{}\n", name, name, default, doc.join(" ")) |
782 | format!("{}::\n{}\n", name, doc.join(" ")) | ||
783 | }) | 826 | }) |
784 | .collect::<String>() | 827 | .collect::<String>() |
785 | } | 828 | } |
diff --git a/crates/rust-analyzer/src/diff.rs b/crates/rust-analyzer/src/diff.rs new file mode 100644 index 000000000..231be5807 --- /dev/null +++ b/crates/rust-analyzer/src/diff.rs | |||
@@ -0,0 +1,53 @@ | |||
1 | //! Generate minimal `TextEdit`s from different text versions | ||
2 | use dissimilar::Chunk; | ||
3 | use ide::{TextEdit, TextRange, TextSize}; | ||
4 | |||
5 | pub(crate) fn diff(left: &str, right: &str) -> TextEdit { | ||
6 | let chunks = dissimilar::diff(left, right); | ||
7 | textedit_from_chunks(chunks) | ||
8 | } | ||
9 | |||
10 | fn textedit_from_chunks(chunks: Vec<dissimilar::Chunk>) -> TextEdit { | ||
11 | let mut builder = TextEdit::builder(); | ||
12 | let mut pos = TextSize::default(); | ||
13 | |||
14 | let mut chunks = chunks.into_iter().peekable(); | ||
15 | while let Some(chunk) = chunks.next() { | ||
16 | if let (Chunk::Delete(deleted), Some(&Chunk::Insert(inserted))) = (chunk, chunks.peek()) { | ||
17 | chunks.next().unwrap(); | ||
18 | let deleted_len = TextSize::of(deleted); | ||
19 | builder.replace(TextRange::at(pos, deleted_len), inserted.into()); | ||
20 | pos += deleted_len; | ||
21 | continue; | ||
22 | } | ||
23 | |||
24 | match chunk { | ||
25 | Chunk::Equal(text) => { | ||
26 | pos += TextSize::of(text); | ||
27 | } | ||
28 | Chunk::Delete(deleted) => { | ||
29 | let deleted_len = TextSize::of(deleted); | ||
30 | builder.delete(TextRange::at(pos, deleted_len)); | ||
31 | pos += deleted_len; | ||
32 | } | ||
33 | Chunk::Insert(inserted) => { | ||
34 | builder.insert(pos, inserted.into()); | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | builder.finish() | ||
39 | } | ||
40 | |||
41 | #[cfg(test)] | ||
42 | mod tests { | ||
43 | use super::*; | ||
44 | |||
45 | #[test] | ||
46 | fn diff_applies() { | ||
47 | let mut original = String::from("fn foo(a:u32){\n}"); | ||
48 | let result = "fn foo(a: u32) {}"; | ||
49 | let edit = diff(&original, result); | ||
50 | edit.apply(&mut original); | ||
51 | assert_eq!(original, result); | ||
52 | } | ||
53 | } | ||
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 71dc56915..442fbd14c 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -22,6 +22,7 @@ use crate::{ | |||
22 | from_proto, | 22 | from_proto, |
23 | line_endings::LineEndings, | 23 | line_endings::LineEndings, |
24 | main_loop::Task, | 24 | main_loop::Task, |
25 | op_queue::OpQueue, | ||
25 | reload::SourceRootConfig, | 26 | reload::SourceRootConfig, |
26 | request_metrics::{LatestRequests, RequestMetrics}, | 27 | request_metrics::{LatestRequests, RequestMetrics}, |
27 | thread_pool::TaskPool, | 28 | thread_pool::TaskPool, |
@@ -67,7 +68,7 @@ pub(crate) struct GlobalState { | |||
67 | pub(crate) flycheck: Vec<FlycheckHandle>, | 68 | pub(crate) flycheck: Vec<FlycheckHandle>, |
68 | pub(crate) flycheck_sender: Sender<flycheck::Message>, | 69 | pub(crate) flycheck_sender: Sender<flycheck::Message>, |
69 | pub(crate) flycheck_receiver: Receiver<flycheck::Message>, | 70 | pub(crate) flycheck_receiver: Receiver<flycheck::Message>, |
70 | pub(crate) config: Config, | 71 | pub(crate) config: Arc<Config>, |
71 | pub(crate) analysis_host: AnalysisHost, | 72 | pub(crate) analysis_host: AnalysisHost, |
72 | pub(crate) diagnostics: DiagnosticCollection, | 73 | pub(crate) diagnostics: DiagnosticCollection, |
73 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, | 74 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, |
@@ -78,12 +79,13 @@ pub(crate) struct GlobalState { | |||
78 | pub(crate) source_root_config: SourceRootConfig, | 79 | pub(crate) source_root_config: SourceRootConfig, |
79 | pub(crate) proc_macro_client: Option<ProcMacroClient>, | 80 | pub(crate) proc_macro_client: Option<ProcMacroClient>, |
80 | pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, | 81 | pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, |
82 | pub(crate) fetch_workspaces_queue: OpQueue, | ||
81 | latest_requests: Arc<RwLock<LatestRequests>>, | 83 | latest_requests: Arc<RwLock<LatestRequests>>, |
82 | } | 84 | } |
83 | 85 | ||
84 | /// An immutable snapshot of the world's state at a point in time. | 86 | /// An immutable snapshot of the world's state at a point in time. |
85 | pub(crate) struct GlobalStateSnapshot { | 87 | pub(crate) struct GlobalStateSnapshot { |
86 | pub(crate) config: Config, | 88 | pub(crate) config: Arc<Config>, |
87 | pub(crate) analysis: Analysis, | 89 | pub(crate) analysis: Analysis, |
88 | pub(crate) check_fixes: CheckFixes, | 90 | pub(crate) check_fixes: CheckFixes, |
89 | pub(crate) latest_requests: Arc<RwLock<LatestRequests>>, | 91 | pub(crate) latest_requests: Arc<RwLock<LatestRequests>>, |
@@ -109,7 +111,7 @@ impl GlobalState { | |||
109 | Handle { handle, receiver } | 111 | Handle { handle, receiver } |
110 | }; | 112 | }; |
111 | 113 | ||
112 | let analysis_host = AnalysisHost::new(config.lru_capacity); | 114 | let analysis_host = AnalysisHost::new(config.lru_capacity()); |
113 | let (flycheck_sender, flycheck_receiver) = unbounded(); | 115 | let (flycheck_sender, flycheck_receiver) = unbounded(); |
114 | GlobalState { | 116 | GlobalState { |
115 | sender, | 117 | sender, |
@@ -119,7 +121,7 @@ impl GlobalState { | |||
119 | flycheck: Vec::new(), | 121 | flycheck: Vec::new(), |
120 | flycheck_sender, | 122 | flycheck_sender, |
121 | flycheck_receiver, | 123 | flycheck_receiver, |
122 | config, | 124 | config: Arc::new(config), |
123 | analysis_host, | 125 | analysis_host, |
124 | diagnostics: Default::default(), | 126 | diagnostics: Default::default(), |
125 | mem_docs: FxHashMap::default(), | 127 | mem_docs: FxHashMap::default(), |
@@ -130,6 +132,7 @@ impl GlobalState { | |||
130 | source_root_config: SourceRootConfig::default(), | 132 | source_root_config: SourceRootConfig::default(), |
131 | proc_macro_client: None, | 133 | proc_macro_client: None, |
132 | workspaces: Arc::new(Vec::new()), | 134 | workspaces: Arc::new(Vec::new()), |
135 | fetch_workspaces_queue: OpQueue::default(), | ||
133 | latest_requests: Default::default(), | 136 | latest_requests: Default::default(), |
134 | } | 137 | } |
135 | } | 138 | } |
@@ -184,7 +187,7 @@ impl GlobalState { | |||
184 | 187 | ||
185 | pub(crate) fn snapshot(&self) -> GlobalStateSnapshot { | 188 | pub(crate) fn snapshot(&self) -> GlobalStateSnapshot { |
186 | GlobalStateSnapshot { | 189 | GlobalStateSnapshot { |
187 | config: self.config.clone(), | 190 | config: Arc::clone(&self.config), |
188 | workspaces: Arc::clone(&self.workspaces), | 191 | workspaces: Arc::clone(&self.workspaces), |
189 | analysis: self.analysis_host.analysis(), | 192 | analysis: self.analysis_host.analysis(), |
190 | vfs: Arc::clone(&self.vfs), | 193 | vfs: Arc::clone(&self.vfs), |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 23f323f55..dc81f55d6 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -9,9 +9,8 @@ use std::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use ide::{ | 11 | use ide::{ |
12 | AssistConfig, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, | 12 | FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, NavigationTarget, |
13 | HoverGotoTypeData, LineIndex, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, | 13 | Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, SymbolKind, TextEdit, |
14 | SearchScope, SourceChange, SymbolKind, TextEdit, | ||
15 | }; | 14 | }; |
16 | use itertools::Itertools; | 15 | use itertools::Itertools; |
17 | use lsp_server::ErrorCode; | 16 | use lsp_server::ErrorCode; |
@@ -19,8 +18,8 @@ use lsp_types::{ | |||
19 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 18 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
20 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, | 19 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, |
21 | CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag, | 20 | CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DiagnosticTag, |
22 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, | 21 | DocumentFormattingParams, DocumentHighlight, FoldingRange, FoldingRangeParams, HoverContents, |
23 | HoverContents, Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams, | 22 | Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams, |
24 | SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, | 23 | SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, |
25 | SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, | 24 | SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, |
26 | SymbolTag, TextDocumentIdentifier, TextDocumentPositionParams, Url, WorkspaceEdit, | 25 | SymbolTag, TextDocumentIdentifier, TextDocumentPositionParams, Url, WorkspaceEdit, |
@@ -34,8 +33,10 @@ use syntax::{algo, ast, AstNode, TextRange, TextSize}; | |||
34 | use crate::{ | 33 | use crate::{ |
35 | cargo_target_spec::CargoTargetSpec, | 34 | cargo_target_spec::CargoTargetSpec, |
36 | config::RustfmtConfig, | 35 | config::RustfmtConfig, |
36 | diff::diff, | ||
37 | from_json, from_proto, | 37 | from_json, from_proto, |
38 | global_state::{GlobalState, GlobalStateSnapshot}, | 38 | global_state::{GlobalState, GlobalStateSnapshot}, |
39 | line_endings::LineEndings, | ||
39 | lsp_ext::{self, InlayHint, InlayHintsParams}, | 40 | lsp_ext::{self, InlayHint, InlayHintsParams}, |
40 | lsp_utils::all_edits_are_disjoint, | 41 | lsp_utils::all_edits_are_disjoint, |
41 | to_proto, LspError, Result, | 42 | to_proto, LspError, Result, |
@@ -104,6 +105,16 @@ pub(crate) fn handle_syntax_tree( | |||
104 | Ok(res) | 105 | Ok(res) |
105 | } | 106 | } |
106 | 107 | ||
108 | pub(crate) fn handle_view_hir( | ||
109 | snap: GlobalStateSnapshot, | ||
110 | params: lsp_types::TextDocumentPositionParams, | ||
111 | ) -> Result<String> { | ||
112 | let _p = profile::span("handle_view_hir"); | ||
113 | let position = from_proto::file_position(&snap, params)?; | ||
114 | let res = snap.analysis.view_hir(position)?; | ||
115 | Ok(res) | ||
116 | } | ||
117 | |||
107 | pub(crate) fn handle_expand_macro( | 118 | pub(crate) fn handle_expand_macro( |
108 | snap: GlobalStateSnapshot, | 119 | snap: GlobalStateSnapshot, |
109 | params: lsp_ext::ExpandMacroParams, | 120 | params: lsp_ext::ExpandMacroParams, |
@@ -269,7 +280,7 @@ pub(crate) fn handle_document_symbol( | |||
269 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; | 280 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
270 | let line_index = snap.analysis.file_line_index(file_id)?; | 281 | let line_index = snap.analysis.file_line_index(file_id)?; |
271 | 282 | ||
272 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); | 283 | let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new(); |
273 | 284 | ||
274 | for symbol in snap.analysis.file_structure(file_id)? { | 285 | for symbol in snap.analysis.file_structure(file_id)? { |
275 | let mut tags = Vec::new(); | 286 | let mut tags = Vec::new(); |
@@ -278,7 +289,7 @@ pub(crate) fn handle_document_symbol( | |||
278 | }; | 289 | }; |
279 | 290 | ||
280 | #[allow(deprecated)] | 291 | #[allow(deprecated)] |
281 | let doc_symbol = DocumentSymbol { | 292 | let doc_symbol = lsp_types::DocumentSymbol { |
282 | name: symbol.label, | 293 | name: symbol.label, |
283 | detail: symbol.detail, | 294 | detail: symbol.detail, |
284 | kind: to_proto::symbol_kind(symbol.kind), | 295 | kind: to_proto::symbol_kind(symbol.kind), |
@@ -309,7 +320,7 @@ pub(crate) fn handle_document_symbol( | |||
309 | acc | 320 | acc |
310 | }; | 321 | }; |
311 | 322 | ||
312 | let res = if snap.config.client_caps.hierarchical_symbols { | 323 | let res = if snap.config.hierarchical_symbols() { |
313 | document_symbols.into() | 324 | document_symbols.into() |
314 | } else { | 325 | } else { |
315 | let url = to_proto::url(&snap, file_id); | 326 | let url = to_proto::url(&snap, file_id); |
@@ -322,7 +333,7 @@ pub(crate) fn handle_document_symbol( | |||
322 | return Ok(Some(res)); | 333 | return Ok(Some(res)); |
323 | 334 | ||
324 | fn flatten_document_symbol( | 335 | fn flatten_document_symbol( |
325 | symbol: &DocumentSymbol, | 336 | symbol: &lsp_types::DocumentSymbol, |
326 | container_name: Option<String>, | 337 | container_name: Option<String>, |
327 | url: &Url, | 338 | url: &Url, |
328 | res: &mut Vec<SymbolInformation>, | 339 | res: &mut Vec<SymbolInformation>, |
@@ -421,9 +432,27 @@ pub(crate) fn handle_will_rename_files( | |||
421 | // Limit to single-level moves for now. | 432 | // Limit to single-level moves for now. |
422 | match (from_path.parent(), to_path.parent()) { | 433 | match (from_path.parent(), to_path.parent()) { |
423 | (Some(p1), Some(p2)) if p1 == p2 => { | 434 | (Some(p1), Some(p2)) if p1 == p2 => { |
424 | let new_name = to_path.file_stem()?; | 435 | if from_path.is_dir() { |
425 | let new_name = new_name.to_str()?; | 436 | // add '/' to end of url -- from `file://path/to/folder` to `file://path/to/folder/` |
426 | Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())) | 437 | let mut old_folder_name = from_path.file_stem()?.to_str()?.to_string(); |
438 | old_folder_name.push('/'); | ||
439 | let from_with_trailing_slash = from.join(&old_folder_name).ok()?; | ||
440 | |||
441 | let imitate_from_url = from_with_trailing_slash.join("mod.rs").ok()?; | ||
442 | let new_file_name = to_path.file_name()?.to_str()?; | ||
443 | Some(( | ||
444 | snap.url_to_file_id(&imitate_from_url).ok()?, | ||
445 | new_file_name.to_string(), | ||
446 | )) | ||
447 | } else { | ||
448 | let old_name = from_path.file_stem()?.to_str()?; | ||
449 | let new_name = to_path.file_stem()?.to_str()?; | ||
450 | match (old_name, new_name) { | ||
451 | ("mod", _) => None, | ||
452 | (_, "mod") => None, | ||
453 | _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())), | ||
454 | } | ||
455 | } | ||
427 | } | 456 | } |
428 | _ => None, | 457 | _ => None, |
429 | } | 458 | } |
@@ -536,7 +565,7 @@ pub(crate) fn handle_runnables( | |||
536 | } | 565 | } |
537 | 566 | ||
538 | // Add `cargo check` and `cargo test` for all targets of the whole package | 567 | // Add `cargo check` and `cargo test` for all targets of the whole package |
539 | let config = &snap.config.runnables; | 568 | let config = snap.config.runnables(); |
540 | match cargo_spec { | 569 | match cargo_spec { |
541 | Some(spec) => { | 570 | Some(spec) => { |
542 | for &cmd in ["check", "test"].iter() { | 571 | for &cmd in ["check", "test"].iter() { |
@@ -567,9 +596,9 @@ pub(crate) fn handle_runnables( | |||
567 | kind: lsp_ext::RunnableKind::Cargo, | 596 | kind: lsp_ext::RunnableKind::Cargo, |
568 | args: lsp_ext::CargoRunnable { | 597 | args: lsp_ext::CargoRunnable { |
569 | workspace_root: None, | 598 | workspace_root: None, |
570 | override_cargo: config.override_cargo.clone(), | 599 | override_cargo: config.override_cargo, |
571 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], | 600 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], |
572 | cargo_extra_args: config.cargo_extra_args.clone(), | 601 | cargo_extra_args: config.cargo_extra_args, |
573 | executable_args: Vec::new(), | 602 | executable_args: Vec::new(), |
574 | expect_test: None, | 603 | expect_test: None, |
575 | }, | 604 | }, |
@@ -608,7 +637,8 @@ pub(crate) fn handle_completion( | |||
608 | return Ok(None); | 637 | return Ok(None); |
609 | } | 638 | } |
610 | 639 | ||
611 | let items = match snap.analysis.completions(&snap.config.completion, position)? { | 640 | let completion_config = &snap.config.completion(); |
641 | let items = match snap.analysis.completions(completion_config, position)? { | ||
612 | None => return Ok(None), | 642 | None => return Ok(None), |
613 | Some(items) => items, | 643 | Some(items) => items, |
614 | }; | 644 | }; |
@@ -621,10 +651,9 @@ pub(crate) fn handle_completion( | |||
621 | let mut new_completion_items = | 651 | let mut new_completion_items = |
622 | to_proto::completion_item(&line_index, line_endings, item.clone()); | 652 | to_proto::completion_item(&line_index, line_endings, item.clone()); |
623 | 653 | ||
624 | if snap.config.completion.resolve_additional_edits_lazily() { | 654 | if completion_config.enable_autoimport_completions { |
625 | for new_item in &mut new_completion_items { | 655 | for new_item in &mut new_completion_items { |
626 | let _ = fill_resolve_data(&mut new_item.data, &item, &text_document_position) | 656 | fill_resolve_data(&mut new_item.data, &item, &text_document_position); |
627 | .take(); | ||
628 | } | 657 | } |
629 | } | 658 | } |
630 | 659 | ||
@@ -650,16 +679,6 @@ pub(crate) fn handle_completion_resolve( | |||
650 | .into()); | 679 | .into()); |
651 | } | 680 | } |
652 | 681 | ||
653 | // FIXME resolve the other capabilities also? | ||
654 | if !snap | ||
655 | .config | ||
656 | .completion | ||
657 | .active_resolve_capabilities | ||
658 | .contains(&CompletionResolveCapability::AdditionalTextEdits) | ||
659 | { | ||
660 | return Ok(original_completion); | ||
661 | } | ||
662 | |||
663 | let resolve_data = match original_completion | 682 | let resolve_data = match original_completion |
664 | .data | 683 | .data |
665 | .take() | 684 | .take() |
@@ -678,7 +697,7 @@ pub(crate) fn handle_completion_resolve( | |||
678 | let additional_edits = snap | 697 | let additional_edits = snap |
679 | .analysis | 698 | .analysis |
680 | .resolve_completion_edits( | 699 | .resolve_completion_edits( |
681 | &snap.config.completion, | 700 | &snap.config.completion(), |
682 | FilePosition { file_id, offset }, | 701 | FilePosition { file_id, offset }, |
683 | &resolve_data.full_import_path, | 702 | &resolve_data.full_import_path, |
684 | resolve_data.imported_name, | 703 | resolve_data.imported_name, |
@@ -716,7 +735,7 @@ pub(crate) fn handle_folding_range( | |||
716 | let folds = snap.analysis.folding_ranges(file_id)?; | 735 | let folds = snap.analysis.folding_ranges(file_id)?; |
717 | let text = snap.analysis.file_text(file_id)?; | 736 | let text = snap.analysis.file_text(file_id)?; |
718 | let line_index = snap.analysis.file_line_index(file_id)?; | 737 | let line_index = snap.analysis.file_line_index(file_id)?; |
719 | let line_folding_only = snap.config.client_caps.line_folding_only; | 738 | let line_folding_only = snap.config.line_folding_only(); |
720 | let res = folds | 739 | let res = folds |
721 | .into_iter() | 740 | .into_iter() |
722 | .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) | 741 | .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) |
@@ -734,12 +753,9 @@ pub(crate) fn handle_signature_help( | |||
734 | Some(it) => it, | 753 | Some(it) => it, |
735 | None => return Ok(None), | 754 | None => return Ok(None), |
736 | }; | 755 | }; |
737 | let concise = !snap.config.call_info_full; | 756 | let concise = !snap.config.call_info_full(); |
738 | let res = to_proto::signature_help( | 757 | let res = |
739 | call_info, | 758 | to_proto::signature_help(call_info, concise, snap.config.signature_help_label_offsets()); |
740 | concise, | ||
741 | snap.config.client_caps.signature_help_label_offsets, | ||
742 | ); | ||
743 | Ok(Some(res)) | 759 | Ok(Some(res)) |
744 | } | 760 | } |
745 | 761 | ||
@@ -749,14 +765,12 @@ pub(crate) fn handle_hover( | |||
749 | ) -> Result<Option<lsp_ext::Hover>> { | 765 | ) -> Result<Option<lsp_ext::Hover>> { |
750 | let _p = profile::span("handle_hover"); | 766 | let _p = profile::span("handle_hover"); |
751 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; | 767 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
752 | let info = match snap.analysis.hover( | 768 | let hover_config = snap.config.hover(); |
753 | position, | 769 | let info = |
754 | snap.config.hover.links_in_hover, | 770 | match snap.analysis.hover(position, hover_config.links_in_hover, hover_config.markdown)? { |
755 | snap.config.hover.markdown, | 771 | None => return Ok(None), |
756 | )? { | 772 | Some(info) => info, |
757 | None => return Ok(None), | 773 | }; |
758 | Some(info) => info, | ||
759 | }; | ||
760 | let line_index = snap.analysis.file_line_index(position.file_id)?; | 774 | let line_index = snap.analysis.file_line_index(position.file_id)?; |
761 | let range = to_proto::range(&line_index, info.range); | 775 | let range = to_proto::range(&line_index, info.range); |
762 | let hover = lsp_ext::Hover { | 776 | let hover = lsp_ext::Hover { |
@@ -777,7 +791,8 @@ pub(crate) fn handle_prepare_rename( | |||
777 | let _p = profile::span("handle_prepare_rename"); | 791 | let _p = profile::span("handle_prepare_rename"); |
778 | let position = from_proto::file_position(&snap, params)?; | 792 | let position = from_proto::file_position(&snap, params)?; |
779 | 793 | ||
780 | let change = snap.analysis.prepare_rename(position)??; | 794 | let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?; |
795 | |||
781 | let line_index = snap.analysis.file_line_index(position.file_id)?; | 796 | let line_index = snap.analysis.file_line_index(position.file_id)?; |
782 | let range = to_proto::range(&line_index, change.range); | 797 | let range = to_proto::range(&line_index, change.range); |
783 | Ok(Some(PrepareRenameResponse::Range(range))) | 798 | Ok(Some(PrepareRenameResponse::Range(range))) |
@@ -790,15 +805,8 @@ pub(crate) fn handle_rename( | |||
790 | let _p = profile::span("handle_rename"); | 805 | let _p = profile::span("handle_rename"); |
791 | let position = from_proto::file_position(&snap, params.text_document_position)?; | 806 | let position = from_proto::file_position(&snap, params.text_document_position)?; |
792 | 807 | ||
793 | if params.new_name.is_empty() { | 808 | let change = |
794 | return Err(LspError::new( | 809 | snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?; |
795 | ErrorCode::InvalidParams as i32, | ||
796 | "New Name cannot be empty".into(), | ||
797 | ) | ||
798 | .into()); | ||
799 | } | ||
800 | |||
801 | let change = snap.analysis.rename(position, &*params.new_name)??; | ||
802 | let workspace_edit = to_proto::workspace_edit(&snap, change.info)?; | 810 | let workspace_edit = to_proto::workspace_edit(&snap, change.info)?; |
803 | Ok(Some(workspace_edit)) | 811 | Ok(Some(workspace_edit)) |
804 | } | 812 | } |
@@ -816,14 +824,15 @@ pub(crate) fn handle_references( | |||
816 | }; | 824 | }; |
817 | 825 | ||
818 | let locations = if params.context.include_declaration { | 826 | let locations = if params.context.include_declaration { |
819 | refs.into_iter() | 827 | refs.references_with_declaration() |
820 | .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) | 828 | .file_ranges() |
829 | .filter_map(|frange| to_proto::location(&snap, frange).ok()) | ||
821 | .collect() | 830 | .collect() |
822 | } else { | 831 | } else { |
823 | // Only iterate over the references if include_declaration was false | 832 | // Only iterate over the references if include_declaration was false |
824 | refs.references() | 833 | refs.references() |
825 | .iter() | 834 | .file_ranges() |
826 | .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) | 835 | .filter_map(|frange| to_proto::location(&snap, frange).ok()) |
827 | .collect() | 836 | .collect() |
828 | }; | 837 | }; |
829 | 838 | ||
@@ -840,9 +849,9 @@ pub(crate) fn handle_formatting( | |||
840 | let crate_ids = snap.analysis.crate_for(file_id)?; | 849 | let crate_ids = snap.analysis.crate_for(file_id)?; |
841 | 850 | ||
842 | let file_line_index = snap.analysis.file_line_index(file_id)?; | 851 | let file_line_index = snap.analysis.file_line_index(file_id)?; |
843 | let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str())); | 852 | let file_line_endings = snap.file_line_endings(file_id); |
844 | 853 | ||
845 | let mut rustfmt = match &snap.config.rustfmt { | 854 | let mut rustfmt = match snap.config.rustfmt() { |
846 | RustfmtConfig::Rustfmt { extra_args } => { | 855 | RustfmtConfig::Rustfmt { extra_args } => { |
847 | let mut cmd = process::Command::new(toolchain::rustfmt()); | 856 | let mut cmd = process::Command::new(toolchain::rustfmt()); |
848 | cmd.args(extra_args); | 857 | cmd.args(extra_args); |
@@ -861,16 +870,18 @@ pub(crate) fn handle_formatting( | |||
861 | } | 870 | } |
862 | }; | 871 | }; |
863 | 872 | ||
864 | let mut rustfmt = rustfmt.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?; | 873 | let mut rustfmt = |
874 | rustfmt.stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?; | ||
865 | 875 | ||
866 | rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; | 876 | rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; |
867 | 877 | ||
868 | let output = rustfmt.wait_with_output()?; | 878 | let output = rustfmt.wait_with_output()?; |
869 | let captured_stdout = String::from_utf8(output.stdout)?; | 879 | let captured_stdout = String::from_utf8(output.stdout)?; |
880 | let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default(); | ||
870 | 881 | ||
871 | if !output.status.success() { | 882 | if !output.status.success() { |
872 | match output.status.code() { | 883 | match output.status.code() { |
873 | Some(1) => { | 884 | Some(1) if !captured_stderr.contains("not installed") => { |
874 | // While `rustfmt` doesn't have a specific exit code for parse errors this is the | 885 | // While `rustfmt` doesn't have a specific exit code for parse errors this is the |
875 | // likely cause exiting with 1. Most Language Servers swallow parse errors on | 886 | // likely cause exiting with 1. Most Language Servers swallow parse errors on |
876 | // formatting because otherwise an error is surfaced to the user on top of the | 887 | // formatting because otherwise an error is surfaced to the user on top of the |
@@ -886,8 +897,9 @@ pub(crate) fn handle_formatting( | |||
886 | format!( | 897 | format!( |
887 | r#"rustfmt exited with: | 898 | r#"rustfmt exited with: |
888 | Status: {} | 899 | Status: {} |
889 | stdout: {}"#, | 900 | stdout: {} |
890 | output.status, captured_stdout, | 901 | stderr: {}"#, |
902 | output.status, captured_stdout, captured_stderr, | ||
891 | ), | 903 | ), |
892 | ) | 904 | ) |
893 | .into()); | 905 | .into()); |
@@ -895,14 +907,26 @@ pub(crate) fn handle_formatting( | |||
895 | } | 907 | } |
896 | } | 908 | } |
897 | 909 | ||
898 | if *file == captured_stdout { | 910 | let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout); |
911 | |||
912 | if file_line_endings != new_line_endings { | ||
913 | // If line endings are different, send the entire file. | ||
914 | // Diffing would not work here, as the line endings might be the only | ||
915 | // difference. | ||
916 | Ok(Some(to_proto::text_edit_vec( | ||
917 | &file_line_index, | ||
918 | new_line_endings, | ||
919 | TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text), | ||
920 | ))) | ||
921 | } else if *file == new_text { | ||
899 | // The document is already formatted correctly -- no edits needed. | 922 | // The document is already formatted correctly -- no edits needed. |
900 | Ok(None) | 923 | Ok(None) |
901 | } else { | 924 | } else { |
902 | Ok(Some(vec![lsp_types::TextEdit { | 925 | Ok(Some(to_proto::text_edit_vec( |
903 | range: Range::new(Position::new(0, 0), end_position), | 926 | &file_line_index, |
904 | new_text: captured_stdout, | 927 | file_line_endings, |
905 | }])) | 928 | diff(&file, &new_text), |
929 | ))) | ||
906 | } | 930 | } |
907 | } | 931 | } |
908 | 932 | ||
@@ -914,7 +938,7 @@ pub(crate) fn handle_code_action( | |||
914 | // We intentionally don't support command-based actions, as those either | 938 | // We intentionally don't support command-based actions, as those either |
915 | // requires custom client-code anyway, or requires server-initiated edits. | 939 | // requires custom client-code anyway, or requires server-initiated edits. |
916 | // Server initiated edits break causality, so we avoid those as well. | 940 | // Server initiated edits break causality, so we avoid those as well. |
917 | if !snap.config.client_caps.code_action_literals { | 941 | if !snap.config.code_action_literals() { |
918 | return Ok(None); | 942 | return Ok(None); |
919 | } | 943 | } |
920 | 944 | ||
@@ -923,14 +947,12 @@ pub(crate) fn handle_code_action( | |||
923 | let range = from_proto::text_range(&line_index, params.range); | 947 | let range = from_proto::text_range(&line_index, params.range); |
924 | let frange = FileRange { file_id, range }; | 948 | let frange = FileRange { file_id, range }; |
925 | 949 | ||
926 | let assists_config = AssistConfig { | 950 | let mut assists_config = snap.config.assist(); |
927 | allowed: params | 951 | assists_config.allowed = params |
928 | .clone() | 952 | .clone() |
929 | .context | 953 | .context |
930 | .only | 954 | .only |
931 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()), | 955 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); |
932 | ..snap.config.assist | ||
933 | }; | ||
934 | 956 | ||
935 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | 957 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); |
936 | 958 | ||
@@ -944,7 +966,7 @@ pub(crate) fn handle_code_action( | |||
944 | add_quick_fixes(&snap, frange, &line_index, &mut res)?; | 966 | add_quick_fixes(&snap, frange, &line_index, &mut res)?; |
945 | } | 967 | } |
946 | 968 | ||
947 | if snap.config.client_caps.code_action_resolve { | 969 | if snap.config.code_action_resolve() { |
948 | for (index, assist) in | 970 | for (index, assist) in |
949 | snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate() | 971 | snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate() |
950 | { | 972 | { |
@@ -965,7 +987,7 @@ fn add_quick_fixes( | |||
965 | line_index: &Arc<LineIndex>, | 987 | line_index: &Arc<LineIndex>, |
966 | acc: &mut Vec<lsp_ext::CodeAction>, | 988 | acc: &mut Vec<lsp_ext::CodeAction>, |
967 | ) -> Result<()> { | 989 | ) -> Result<()> { |
968 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, frange.file_id)?; | 990 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?; |
969 | 991 | ||
970 | for fix in diagnostics | 992 | for fix in diagnostics |
971 | .into_iter() | 993 | .into_iter() |
@@ -994,7 +1016,7 @@ fn add_quick_fixes( | |||
994 | } | 1016 | } |
995 | 1017 | ||
996 | pub(crate) fn handle_code_action_resolve( | 1018 | pub(crate) fn handle_code_action_resolve( |
997 | mut snap: GlobalStateSnapshot, | 1019 | snap: GlobalStateSnapshot, |
998 | mut code_action: lsp_ext::CodeAction, | 1020 | mut code_action: lsp_ext::CodeAction, |
999 | ) -> Result<lsp_ext::CodeAction> { | 1021 | ) -> Result<lsp_ext::CodeAction> { |
1000 | let _p = profile::span("handle_code_action_resolve"); | 1022 | let _p = profile::span("handle_code_action_resolve"); |
@@ -1008,13 +1030,14 @@ pub(crate) fn handle_code_action_resolve( | |||
1008 | let range = from_proto::text_range(&line_index, params.code_action_params.range); | 1030 | let range = from_proto::text_range(&line_index, params.code_action_params.range); |
1009 | let frange = FileRange { file_id, range }; | 1031 | let frange = FileRange { file_id, range }; |
1010 | 1032 | ||
1011 | snap.config.assist.allowed = params | 1033 | let mut assists_config = snap.config.assist(); |
1034 | assists_config.allowed = params | ||
1012 | .code_action_params | 1035 | .code_action_params |
1013 | .context | 1036 | .context |
1014 | .only | 1037 | .only |
1015 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); | 1038 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); |
1016 | 1039 | ||
1017 | let assists = snap.analysis.assists(&snap.config.assist, true, frange)?; | 1040 | let assists = snap.analysis.assists(&assists_config, true, frange)?; |
1018 | let (id, index) = split_once(¶ms.id, ':').unwrap(); | 1041 | let (id, index) = split_once(¶ms.id, ':').unwrap(); |
1019 | let index = index.parse::<usize>().unwrap(); | 1042 | let index = index.parse::<usize>().unwrap(); |
1020 | let assist = &assists[index]; | 1043 | let assist = &assists[index]; |
@@ -1031,7 +1054,8 @@ pub(crate) fn handle_code_lens( | |||
1031 | let _p = profile::span("handle_code_lens"); | 1054 | let _p = profile::span("handle_code_lens"); |
1032 | let mut lenses: Vec<CodeLens> = Default::default(); | 1055 | let mut lenses: Vec<CodeLens> = Default::default(); |
1033 | 1056 | ||
1034 | if snap.config.lens.none() { | 1057 | let lens_config = snap.config.lens(); |
1058 | if lens_config.none() { | ||
1035 | // early return before any db query! | 1059 | // early return before any db query! |
1036 | return Ok(Some(lenses)); | 1060 | return Ok(Some(lenses)); |
1037 | } | 1061 | } |
@@ -1040,7 +1064,7 @@ pub(crate) fn handle_code_lens( | |||
1040 | let line_index = snap.analysis.file_line_index(file_id)?; | 1064 | let line_index = snap.analysis.file_line_index(file_id)?; |
1041 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; | 1065 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; |
1042 | 1066 | ||
1043 | if snap.config.lens.runnable() { | 1067 | if lens_config.runnable() { |
1044 | // Gather runnables | 1068 | // Gather runnables |
1045 | for runnable in snap.analysis.runnables(file_id)? { | 1069 | for runnable in snap.analysis.runnables(file_id)? { |
1046 | if should_skip_target(&runnable, cargo_spec.as_ref()) { | 1070 | if should_skip_target(&runnable, cargo_spec.as_ref()) { |
@@ -1050,7 +1074,7 @@ pub(crate) fn handle_code_lens( | |||
1050 | let action = runnable.action(); | 1074 | let action = runnable.action(); |
1051 | let range = to_proto::range(&line_index, runnable.nav.full_range); | 1075 | let range = to_proto::range(&line_index, runnable.nav.full_range); |
1052 | let r = to_proto::runnable(&snap, file_id, runnable)?; | 1076 | let r = to_proto::runnable(&snap, file_id, runnable)?; |
1053 | if snap.config.lens.run { | 1077 | if lens_config.run { |
1054 | let lens = CodeLens { | 1078 | let lens = CodeLens { |
1055 | range, | 1079 | range, |
1056 | command: Some(run_single_command(&r, action.run_title)), | 1080 | command: Some(run_single_command(&r, action.run_title)), |
@@ -1059,7 +1083,7 @@ pub(crate) fn handle_code_lens( | |||
1059 | lenses.push(lens); | 1083 | lenses.push(lens); |
1060 | } | 1084 | } |
1061 | 1085 | ||
1062 | if action.debugee && snap.config.lens.debug { | 1086 | if action.debugee && lens_config.debug { |
1063 | let debug_lens = | 1087 | let debug_lens = |
1064 | CodeLens { range, command: Some(debug_single_command(&r)), data: None }; | 1088 | CodeLens { range, command: Some(debug_single_command(&r)), data: None }; |
1065 | lenses.push(debug_lens); | 1089 | lenses.push(debug_lens); |
@@ -1067,7 +1091,7 @@ pub(crate) fn handle_code_lens( | |||
1067 | } | 1091 | } |
1068 | } | 1092 | } |
1069 | 1093 | ||
1070 | if snap.config.lens.implementations { | 1094 | if lens_config.implementations { |
1071 | // Handle impls | 1095 | // Handle impls |
1072 | lenses.extend( | 1096 | lenses.extend( |
1073 | snap.analysis | 1097 | snap.analysis |
@@ -1102,7 +1126,7 @@ pub(crate) fn handle_code_lens( | |||
1102 | ); | 1126 | ); |
1103 | } | 1127 | } |
1104 | 1128 | ||
1105 | if snap.config.lens.references() { | 1129 | if lens_config.references() { |
1106 | lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| { | 1130 | lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| { |
1107 | let range = to_proto::range(&line_index, it.range); | 1131 | let range = to_proto::range(&line_index, it.range); |
1108 | let position = to_proto::position(&line_index, it.range.start()); | 1132 | let position = to_proto::position(&line_index, it.range.start()); |
@@ -1164,8 +1188,8 @@ pub(crate) fn handle_code_lens_resolve( | |||
1164 | .unwrap_or(None) | 1188 | .unwrap_or(None) |
1165 | .map(|r| { | 1189 | .map(|r| { |
1166 | r.references() | 1190 | r.references() |
1167 | .iter() | 1191 | .file_ranges() |
1168 | .filter_map(|it| to_proto::location(&snap, it.file_range).ok()) | 1192 | .filter_map(|frange| to_proto::location(&snap, frange).ok()) |
1169 | .collect_vec() | 1193 | .collect_vec() |
1170 | }) | 1194 | }) |
1171 | .unwrap_or_default(); | 1195 | .unwrap_or_default(); |
@@ -1209,13 +1233,19 @@ pub(crate) fn handle_document_highlight( | |||
1209 | }; | 1233 | }; |
1210 | 1234 | ||
1211 | let res = refs | 1235 | let res = refs |
1212 | .into_iter() | 1236 | .references_with_declaration() |
1213 | .filter(|reference| reference.file_range.file_id == position.file_id) | 1237 | .references |
1214 | .map(|reference| DocumentHighlight { | 1238 | .get(&position.file_id) |
1215 | range: to_proto::range(&line_index, reference.file_range.range), | 1239 | .map(|file_refs| { |
1216 | kind: reference.access.map(to_proto::document_highlight_kind), | 1240 | file_refs |
1241 | .into_iter() | ||
1242 | .map(|r| DocumentHighlight { | ||
1243 | range: to_proto::range(&line_index, r.range), | ||
1244 | kind: r.access.map(to_proto::document_highlight_kind), | ||
1245 | }) | ||
1246 | .collect() | ||
1217 | }) | 1247 | }) |
1218 | .collect(); | 1248 | .unwrap_or_default(); |
1219 | Ok(Some(res)) | 1249 | Ok(Some(res)) |
1220 | } | 1250 | } |
1221 | 1251 | ||
@@ -1248,7 +1278,7 @@ pub(crate) fn publish_diagnostics( | |||
1248 | 1278 | ||
1249 | let diagnostics: Vec<Diagnostic> = snap | 1279 | let diagnostics: Vec<Diagnostic> = snap |
1250 | .analysis | 1280 | .analysis |
1251 | .diagnostics(&snap.config.diagnostics, file_id)? | 1281 | .diagnostics(&snap.config.diagnostics(), file_id)? |
1252 | .into_iter() | 1282 | .into_iter() |
1253 | .map(|d| Diagnostic { | 1283 | .map(|d| Diagnostic { |
1254 | range: to_proto::range(&line_index, d.range), | 1284 | range: to_proto::range(&line_index, d.range), |
@@ -1281,7 +1311,7 @@ pub(crate) fn handle_inlay_hints( | |||
1281 | let line_index = snap.analysis.file_line_index(file_id)?; | 1311 | let line_index = snap.analysis.file_line_index(file_id)?; |
1282 | Ok(snap | 1312 | Ok(snap |
1283 | .analysis | 1313 | .analysis |
1284 | .inlay_hints(file_id, &snap.config.inlay_hints)? | 1314 | .inlay_hints(file_id, &snap.config.inlay_hints())? |
1285 | .into_iter() | 1315 | .into_iter() |
1286 | .map(|it| to_proto::inlay_hint(&line_index, it)) | 1316 | .map(|it| to_proto::inlay_hint(&line_index, it)) |
1287 | .collect()) | 1317 | .collect()) |
@@ -1527,7 +1557,7 @@ fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command { | |||
1527 | } | 1557 | } |
1528 | 1558 | ||
1529 | fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> { | 1559 | fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> { |
1530 | let value = if snap.config.client_caps.location_link { | 1560 | let value = if snap.config.location_link() { |
1531 | let link = to_proto::location_link(snap, None, nav.clone()).ok()?; | 1561 | let link = to_proto::location_link(snap, None, nav.clone()).ok()?; |
1532 | to_value(link).ok()? | 1562 | to_value(link).ok()? |
1533 | } else { | 1563 | } else { |
@@ -1551,7 +1581,7 @@ fn show_impl_command_link( | |||
1551 | snap: &GlobalStateSnapshot, | 1581 | snap: &GlobalStateSnapshot, |
1552 | position: &FilePosition, | 1582 | position: &FilePosition, |
1553 | ) -> Option<lsp_ext::CommandLinkGroup> { | 1583 | ) -> Option<lsp_ext::CommandLinkGroup> { |
1554 | if snap.config.hover.implementations { | 1584 | if snap.config.hover().implementations { |
1555 | if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { | 1585 | if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { |
1556 | let uri = to_proto::url(snap, position.file_id); | 1586 | let uri = to_proto::url(snap, position.file_id); |
1557 | let line_index = snap.analysis.file_line_index(position.file_id).ok()?; | 1587 | let line_index = snap.analysis.file_line_index(position.file_id).ok()?; |
@@ -1579,7 +1609,8 @@ fn runnable_action_links( | |||
1579 | runnable: Runnable, | 1609 | runnable: Runnable, |
1580 | ) -> Option<lsp_ext::CommandLinkGroup> { | 1610 | ) -> Option<lsp_ext::CommandLinkGroup> { |
1581 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; | 1611 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; |
1582 | if !snap.config.hover.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { | 1612 | let hover_config = snap.config.hover(); |
1613 | if !hover_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { | ||
1583 | return None; | 1614 | return None; |
1584 | } | 1615 | } |
1585 | 1616 | ||
@@ -1587,12 +1618,12 @@ fn runnable_action_links( | |||
1587 | to_proto::runnable(snap, file_id, runnable).ok().map(|r| { | 1618 | to_proto::runnable(snap, file_id, runnable).ok().map(|r| { |
1588 | let mut group = lsp_ext::CommandLinkGroup::default(); | 1619 | let mut group = lsp_ext::CommandLinkGroup::default(); |
1589 | 1620 | ||
1590 | if snap.config.hover.run { | 1621 | if hover_config.run { |
1591 | let run_command = run_single_command(&r, action.run_title); | 1622 | let run_command = run_single_command(&r, action.run_title); |
1592 | group.commands.push(to_command_link(run_command, r.label.clone())); | 1623 | group.commands.push(to_command_link(run_command, r.label.clone())); |
1593 | } | 1624 | } |
1594 | 1625 | ||
1595 | if snap.config.hover.debug { | 1626 | if hover_config.debug { |
1596 | let dbg_command = debug_single_command(&r); | 1627 | let dbg_command = debug_single_command(&r); |
1597 | group.commands.push(to_command_link(dbg_command, r.label)); | 1628 | group.commands.push(to_command_link(dbg_command, r.label)); |
1598 | } | 1629 | } |
@@ -1605,7 +1636,7 @@ fn goto_type_action_links( | |||
1605 | snap: &GlobalStateSnapshot, | 1636 | snap: &GlobalStateSnapshot, |
1606 | nav_targets: &[HoverGotoTypeData], | 1637 | nav_targets: &[HoverGotoTypeData], |
1607 | ) -> Option<lsp_ext::CommandLinkGroup> { | 1638 | ) -> Option<lsp_ext::CommandLinkGroup> { |
1608 | if !snap.config.hover.goto_type_def || nav_targets.is_empty() { | 1639 | if !snap.config.hover().goto_type_def || nav_targets.is_empty() { |
1609 | return None; | 1640 | return None; |
1610 | } | 1641 | } |
1611 | 1642 | ||
@@ -1626,14 +1657,14 @@ fn prepare_hover_actions( | |||
1626 | file_id: FileId, | 1657 | file_id: FileId, |
1627 | actions: &[HoverAction], | 1658 | actions: &[HoverAction], |
1628 | ) -> Vec<lsp_ext::CommandLinkGroup> { | 1659 | ) -> Vec<lsp_ext::CommandLinkGroup> { |
1629 | if snap.config.hover.none() || !snap.config.client_caps.hover_actions { | 1660 | if snap.config.hover().none() || !snap.config.hover_actions() { |
1630 | return Vec::new(); | 1661 | return Vec::new(); |
1631 | } | 1662 | } |
1632 | 1663 | ||
1633 | actions | 1664 | actions |
1634 | .iter() | 1665 | .iter() |
1635 | .filter_map(|it| match it { | 1666 | .filter_map(|it| match it { |
1636 | HoverAction::Implementaion(position) => show_impl_command_link(snap, position), | 1667 | HoverAction::Implementation(position) => show_impl_command_link(snap, position), |
1637 | HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()), | 1668 | HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()), |
1638 | HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), | 1669 | HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), |
1639 | }) | 1670 | }) |
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index d538ad69a..2207b9a87 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -34,6 +34,8 @@ mod request_metrics; | |||
34 | mod lsp_utils; | 34 | mod lsp_utils; |
35 | mod thread_pool; | 35 | mod thread_pool; |
36 | mod document; | 36 | mod document; |
37 | mod diff; | ||
38 | mod op_queue; | ||
37 | pub mod lsp_ext; | 39 | pub mod lsp_ext; |
38 | pub mod config; | 40 | pub mod config; |
39 | 41 | ||
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 93ac45415..a85978737 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -53,6 +53,14 @@ pub struct SyntaxTreeParams { | |||
53 | pub range: Option<Range>, | 53 | pub range: Option<Range>, |
54 | } | 54 | } |
55 | 55 | ||
56 | pub enum ViewHir {} | ||
57 | |||
58 | impl Request for ViewHir { | ||
59 | type Params = lsp_types::TextDocumentPositionParams; | ||
60 | type Result = String; | ||
61 | const METHOD: &'static str = "rust-analyzer/viewHir"; | ||
62 | } | ||
63 | |||
56 | pub enum ExpandMacro {} | 64 | pub enum ExpandMacro {} |
57 | 65 | ||
58 | impl Request for ExpandMacro { | 66 | impl Request for ExpandMacro { |
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 60c12e4e2..2d06fe538 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs | |||
@@ -46,7 +46,7 @@ impl GlobalState { | |||
46 | message: Option<String>, | 46 | message: Option<String>, |
47 | fraction: Option<f64>, | 47 | fraction: Option<f64>, |
48 | ) { | 48 | ) { |
49 | if !self.config.client_caps.work_done_progress { | 49 | if !self.config.work_done_progress() { |
50 | return; | 50 | return; |
51 | } | 51 | } |
52 | let percentage = fraction.map(|f| { | 52 | let percentage = fraction.map(|f| { |
@@ -130,7 +130,7 @@ pub(crate) fn apply_document_changes( | |||
130 | } | 130 | } |
131 | 131 | ||
132 | /// Checks that the edits inside the completion and the additional edits do not overlap. | 132 | /// Checks that the edits inside the completion and the additional edits do not overlap. |
133 | /// LSP explicitly forbits the additional edits to overlap both with the main edit and themselves. | 133 | /// LSP explicitly forbids the additional edits to overlap both with the main edit and themselves. |
134 | pub(crate) fn all_edits_are_disjoint( | 134 | pub(crate) fn all_edits_are_disjoint( |
135 | completion: &lsp_types::CompletionItem, | 135 | completion: &lsp_types::CompletionItem, |
136 | additional_edits: &[lsp_types::TextEdit], | 136 | additional_edits: &[lsp_types::TextEdit], |
@@ -290,7 +290,7 @@ mod tests { | |||
290 | Some(vec![disjoint_edit.clone(), joint_edit.clone()]); | 290 | Some(vec![disjoint_edit.clone(), joint_edit.clone()]); |
291 | assert!( | 291 | assert!( |
292 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), | 292 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), |
293 | "Completion with disjoint edits fails the validaton even with empty extra edits" | 293 | "Completion with disjoint edits fails the validation even with empty extra edits" |
294 | ); | 294 | ); |
295 | 295 | ||
296 | completion_with_joint_edits.text_edit = | 296 | completion_with_joint_edits.text_edit = |
@@ -298,7 +298,7 @@ mod tests { | |||
298 | completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit.clone()]); | 298 | completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit.clone()]); |
299 | assert!( | 299 | assert!( |
300 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), | 300 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), |
301 | "Completion with disjoint edits fails the validaton even with empty extra edits" | 301 | "Completion with disjoint edits fails the validation even with empty extra edits" |
302 | ); | 302 | ); |
303 | 303 | ||
304 | completion_with_joint_edits.text_edit = | 304 | completion_with_joint_edits.text_edit = |
@@ -310,7 +310,7 @@ mod tests { | |||
310 | completion_with_joint_edits.additional_text_edits = None; | 310 | completion_with_joint_edits.additional_text_edits = None; |
311 | assert!( | 311 | assert!( |
312 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), | 312 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), |
313 | "Completion with disjoint edits fails the validaton even with empty extra edits" | 313 | "Completion with disjoint edits fails the validation even with empty extra edits" |
314 | ); | 314 | ); |
315 | 315 | ||
316 | completion_with_joint_edits.text_edit = | 316 | completion_with_joint_edits.text_edit = |
@@ -322,7 +322,7 @@ mod tests { | |||
322 | completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit]); | 322 | completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit]); |
323 | assert!( | 323 | assert!( |
324 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), | 324 | !all_edits_are_disjoint(&completion_with_joint_edits, &[]), |
325 | "Completion with disjoint edits fails the validaton even with empty extra edits" | 325 | "Completion with disjoint edits fails the validation even with empty extra edits" |
326 | ); | 326 | ); |
327 | } | 327 | } |
328 | 328 | ||
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 5d55dc96e..6d2475a59 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -11,7 +11,6 @@ use ide::{Canceled, FileId}; | |||
11 | use ide_db::base_db::VfsPath; | 11 | use ide_db::base_db::VfsPath; |
12 | use lsp_server::{Connection, Notification, Request, Response}; | 12 | use lsp_server::{Connection, Notification, Request, Response}; |
13 | use lsp_types::notification::Notification as _; | 13 | use lsp_types::notification::Notification as _; |
14 | use project_model::ProjectWorkspace; | ||
15 | use vfs::ChangeKind; | 14 | use vfs::ChangeKind; |
16 | 15 | ||
17 | use crate::{ | 16 | use crate::{ |
@@ -22,6 +21,7 @@ use crate::{ | |||
22 | global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, | 21 | global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, |
23 | handlers, lsp_ext, | 22 | handlers, lsp_ext, |
24 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, | 23 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, |
24 | reload::ProjectWorkspaceProgress, | ||
25 | Result, | 25 | Result, |
26 | }; | 26 | }; |
27 | 27 | ||
@@ -61,8 +61,8 @@ enum Event { | |||
61 | pub(crate) enum Task { | 61 | pub(crate) enum Task { |
62 | Response(Response), | 62 | Response(Response), |
63 | Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), | 63 | Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), |
64 | Workspaces(Vec<anyhow::Result<ProjectWorkspace>>), | ||
65 | PrimeCaches(PrimeCachesProgress), | 64 | PrimeCaches(PrimeCachesProgress), |
65 | FetchWorkspace(ProjectWorkspaceProgress), | ||
66 | } | 66 | } |
67 | 67 | ||
68 | impl fmt::Debug for Event { | 68 | impl fmt::Debug for Event { |
@@ -99,7 +99,8 @@ impl fmt::Debug for Event { | |||
99 | 99 | ||
100 | impl GlobalState { | 100 | impl GlobalState { |
101 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { | 101 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { |
102 | if self.config.linked_projects.is_empty() && self.config.notifications.cargo_toml_not_found | 102 | if self.config.linked_projects().is_empty() |
103 | && self.config.notifications().cargo_toml_not_found | ||
103 | { | 104 | { |
104 | self.show_message( | 105 | self.show_message( |
105 | lsp_types::MessageType::Error, | 106 | lsp_types::MessageType::Error, |
@@ -107,40 +108,43 @@ impl GlobalState { | |||
107 | ); | 108 | ); |
108 | }; | 109 | }; |
109 | 110 | ||
110 | let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions { | 111 | if self.config.did_save_text_document_dynamic_registration() { |
111 | include_text: Some(false), | 112 | let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions { |
112 | text_document_registration_options: lsp_types::TextDocumentRegistrationOptions { | 113 | include_text: Some(false), |
113 | document_selector: Some(vec![ | 114 | text_document_registration_options: lsp_types::TextDocumentRegistrationOptions { |
114 | lsp_types::DocumentFilter { | 115 | document_selector: Some(vec![ |
115 | language: None, | 116 | lsp_types::DocumentFilter { |
116 | scheme: None, | 117 | language: None, |
117 | pattern: Some("**/*.rs".into()), | 118 | scheme: None, |
118 | }, | 119 | pattern: Some("**/*.rs".into()), |
119 | lsp_types::DocumentFilter { | 120 | }, |
120 | language: None, | 121 | lsp_types::DocumentFilter { |
121 | scheme: None, | 122 | language: None, |
122 | pattern: Some("**/Cargo.toml".into()), | 123 | scheme: None, |
123 | }, | 124 | pattern: Some("**/Cargo.toml".into()), |
124 | lsp_types::DocumentFilter { | 125 | }, |
125 | language: None, | 126 | lsp_types::DocumentFilter { |
126 | scheme: None, | 127 | language: None, |
127 | pattern: Some("**/Cargo.lock".into()), | 128 | scheme: None, |
128 | }, | 129 | pattern: Some("**/Cargo.lock".into()), |
129 | ]), | 130 | }, |
130 | }, | 131 | ]), |
131 | }; | 132 | }, |
132 | 133 | }; | |
133 | let registration = lsp_types::Registration { | 134 | |
134 | id: "textDocument/didSave".to_string(), | 135 | let registration = lsp_types::Registration { |
135 | method: "textDocument/didSave".to_string(), | 136 | id: "textDocument/didSave".to_string(), |
136 | register_options: Some(serde_json::to_value(save_registration_options).unwrap()), | 137 | method: "textDocument/didSave".to_string(), |
137 | }; | 138 | register_options: Some(serde_json::to_value(save_registration_options).unwrap()), |
138 | self.send_request::<lsp_types::request::RegisterCapability>( | 139 | }; |
139 | lsp_types::RegistrationParams { registrations: vec![registration] }, | 140 | self.send_request::<lsp_types::request::RegisterCapability>( |
140 | |_, _| (), | 141 | lsp_types::RegistrationParams { registrations: vec![registration] }, |
141 | ); | 142 | |_, _| (), |
143 | ); | ||
144 | } | ||
142 | 145 | ||
143 | self.fetch_workspaces(); | 146 | self.fetch_workspaces_request(); |
147 | self.fetch_workspaces_if_needed(); | ||
144 | 148 | ||
145 | while let Some(event) = self.next_event(&inbox) { | 149 | while let Some(event) = self.next_event(&inbox) { |
146 | if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { | 150 | if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { |
@@ -201,7 +205,6 @@ impl GlobalState { | |||
201 | self.diagnostics.set_native_diagnostics(file_id, diagnostics) | 205 | self.diagnostics.set_native_diagnostics(file_id, diagnostics) |
202 | } | 206 | } |
203 | } | 207 | } |
204 | Task::Workspaces(workspaces) => self.switch_workspaces(workspaces), | ||
205 | Task::PrimeCaches(progress) => match progress { | 208 | Task::PrimeCaches(progress) => match progress { |
206 | PrimeCachesProgress::Started => prime_caches_progress.push(progress), | 209 | PrimeCachesProgress::Started => prime_caches_progress.push(progress), |
207 | PrimeCachesProgress::StartedOnCrate { .. } => { | 210 | PrimeCachesProgress::StartedOnCrate { .. } => { |
@@ -215,6 +218,20 @@ impl GlobalState { | |||
215 | } | 218 | } |
216 | PrimeCachesProgress::Finished => prime_caches_progress.push(progress), | 219 | PrimeCachesProgress::Finished => prime_caches_progress.push(progress), |
217 | }, | 220 | }, |
221 | Task::FetchWorkspace(progress) => { | ||
222 | let (state, msg) = match progress { | ||
223 | ProjectWorkspaceProgress::Begin => (Progress::Begin, None), | ||
224 | ProjectWorkspaceProgress::Report(msg) => { | ||
225 | (Progress::Report, Some(msg)) | ||
226 | } | ||
227 | ProjectWorkspaceProgress::End(workspaces) => { | ||
228 | self.fetch_workspaces_completed(); | ||
229 | self.switch_workspaces(workspaces); | ||
230 | (Progress::End, None) | ||
231 | } | ||
232 | }; | ||
233 | self.report_progress("fetching", state, msg, None); | ||
234 | } | ||
218 | } | 235 | } |
219 | // Coalesce multiple task events into one loop turn | 236 | // Coalesce multiple task events into one loop turn |
220 | task = match self.task_pool.receiver.try_recv() { | 237 | task = match self.task_pool.receiver.try_recv() { |
@@ -296,7 +313,7 @@ impl GlobalState { | |||
296 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { | 313 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { |
297 | let diagnostics = | 314 | let diagnostics = |
298 | crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( | 315 | crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( |
299 | &self.config.diagnostics_map, | 316 | &self.config.diagnostics_map(), |
300 | &diagnostic, | 317 | &diagnostic, |
301 | &workspace_root, | 318 | &workspace_root, |
302 | ); | 319 | ); |
@@ -365,13 +382,13 @@ impl GlobalState { | |||
365 | self.update_file_notifications_on_threadpool(); | 382 | self.update_file_notifications_on_threadpool(); |
366 | 383 | ||
367 | // Refresh semantic tokens if the client supports it. | 384 | // Refresh semantic tokens if the client supports it. |
368 | if self.config.semantic_tokens_refresh { | 385 | if self.config.semantic_tokens_refresh() { |
369 | self.semantic_tokens_cache.lock().clear(); | 386 | self.semantic_tokens_cache.lock().clear(); |
370 | self.send_request::<lsp_types::request::SemanticTokensRefesh>((), |_, _| ()); | 387 | self.send_request::<lsp_types::request::SemanticTokensRefesh>((), |_, _| ()); |
371 | } | 388 | } |
372 | 389 | ||
373 | // Refresh code lens if the client supports it. | 390 | // Refresh code lens if the client supports it. |
374 | if self.config.code_lens_refresh { | 391 | if self.config.code_lens_refresh() { |
375 | self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ()); | 392 | self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ()); |
376 | } | 393 | } |
377 | } | 394 | } |
@@ -390,6 +407,8 @@ impl GlobalState { | |||
390 | } | 407 | } |
391 | } | 408 | } |
392 | 409 | ||
410 | self.fetch_workspaces_if_needed(); | ||
411 | |||
393 | let loop_duration = loop_start.elapsed(); | 412 | let loop_duration = loop_start.elapsed(); |
394 | if loop_duration > Duration::from_millis(100) { | 413 | if loop_duration > Duration::from_millis(100) { |
395 | log::warn!("overly long loop turn: {:?}", loop_duration); | 414 | log::warn!("overly long loop turn: {:?}", loop_duration); |
@@ -427,7 +446,7 @@ impl GlobalState { | |||
427 | } | 446 | } |
428 | 447 | ||
429 | RequestDispatcher { req: Some(req), global_state: self } | 448 | RequestDispatcher { req: Some(req), global_state: self } |
430 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))? | 449 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))? |
431 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? | 450 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? |
432 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? | 451 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? |
433 | .on_sync::<lsp_types::request::Shutdown>(|s, ()| { | 452 | .on_sync::<lsp_types::request::Shutdown>(|s, ()| { |
@@ -443,6 +462,7 @@ impl GlobalState { | |||
443 | .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? | 462 | .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? |
444 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) | 463 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) |
445 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) | 464 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) |
465 | .on::<lsp_ext::ViewHir>(handlers::handle_view_hir) | ||
446 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) | 466 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) |
447 | .on::<lsp_ext::ParentModule>(handlers::handle_parent_module) | 467 | .on::<lsp_ext::ParentModule>(handlers::handle_parent_module) |
448 | .on::<lsp_ext::Runnables>(handlers::handle_runnables) | 468 | .on::<lsp_ext::Runnables>(handlers::handle_runnables) |
@@ -607,7 +627,7 @@ impl GlobalState { | |||
607 | if let Some(json) = configs.get_mut(0) { | 627 | if let Some(json) = configs.get_mut(0) { |
608 | // Note that json can be null according to the spec if the client can't | 628 | // Note that json can be null according to the spec if the client can't |
609 | // provide a configuration. This is handled in Config::update below. | 629 | // provide a configuration. This is handled in Config::update below. |
610 | let mut config = this.config.clone(); | 630 | let mut config = Config::clone(&*this.config); |
611 | config.update(json.take()); | 631 | config.update(json.take()); |
612 | this.update_configuration(config); | 632 | this.update_configuration(config); |
613 | } | 633 | } |
@@ -657,7 +677,7 @@ impl GlobalState { | |||
657 | .collect::<Vec<_>>(); | 677 | .collect::<Vec<_>>(); |
658 | 678 | ||
659 | log::trace!("updating notifications for {:?}", subscriptions); | 679 | log::trace!("updating notifications for {:?}", subscriptions); |
660 | if self.config.publish_diagnostics { | 680 | if self.config.publish_diagnostics() { |
661 | let snapshot = self.snapshot(); | 681 | let snapshot = self.snapshot(); |
662 | self.task_pool.handle.spawn(move || { | 682 | self.task_pool.handle.spawn(move || { |
663 | let diagnostics = subscriptions | 683 | let diagnostics = subscriptions |
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs index 968ea55f0..865eaae9b 100644 --- a/crates/rust-analyzer/src/markdown.rs +++ b/crates/rust-analyzer/src/markdown.rs | |||
@@ -1,8 +1,17 @@ | |||
1 | //! Transforms markdown | 1 | //! Transforms markdown |
2 | 2 | ||
3 | const RUSTDOC_FENCE: &str = "```"; | 3 | const RUSTDOC_FENCE: &str = "```"; |
4 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = | 4 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = &[ |
5 | &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; | 5 | "", |
6 | "rust", | ||
7 | "should_panic", | ||
8 | "ignore", | ||
9 | "no_run", | ||
10 | "compile_fail", | ||
11 | "edition2015", | ||
12 | "edition2018", | ||
13 | "edition2021", | ||
14 | ]; | ||
6 | 15 | ||
7 | pub(crate) fn format_docs(src: &str) -> String { | 16 | pub(crate) fn format_docs(src: &str) -> String { |
8 | let mut processed_lines = Vec::new(); | 17 | let mut processed_lines = Vec::new(); |
@@ -97,7 +106,7 @@ mod tests { | |||
97 | 106 | ||
98 | #[test] | 107 | #[test] |
99 | fn test_format_docs_preserves_newlines() { | 108 | fn test_format_docs_preserves_newlines() { |
100 | let comment = "this\nis\nultiline"; | 109 | let comment = "this\nis\nmultiline"; |
101 | assert_eq!(format_docs(comment), comment); | 110 | assert_eq!(format_docs(comment), comment); |
102 | } | 111 | } |
103 | 112 | ||
diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs new file mode 100644 index 000000000..51d66f4b3 --- /dev/null +++ b/crates/rust-analyzer/src/op_queue.rs | |||
@@ -0,0 +1,25 @@ | |||
1 | //! Bookkeeping to make sure only one long-running operation is executed. | ||
2 | |||
3 | #[derive(Default)] | ||
4 | pub(crate) struct OpQueue { | ||
5 | op_scheduled: bool, | ||
6 | op_in_progress: bool, | ||
7 | } | ||
8 | |||
9 | impl OpQueue { | ||
10 | pub(crate) fn request_op(&mut self) { | ||
11 | self.op_scheduled = true; | ||
12 | } | ||
13 | pub(crate) fn should_start_op(&mut self) -> bool { | ||
14 | if !self.op_in_progress && self.op_scheduled { | ||
15 | self.op_in_progress = true; | ||
16 | self.op_scheduled = false; | ||
17 | return true; | ||
18 | } | ||
19 | false | ||
20 | } | ||
21 | pub(crate) fn op_completed(&mut self) { | ||
22 | assert!(self.op_in_progress); | ||
23 | self.op_in_progress = false; | ||
24 | } | ||
25 | } | ||
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 79e39e3a5..97e20362f 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -15,16 +15,23 @@ use crate::{ | |||
15 | }; | 15 | }; |
16 | use lsp_ext::StatusParams; | 16 | use lsp_ext::StatusParams; |
17 | 17 | ||
18 | #[derive(Debug)] | ||
19 | pub(crate) enum ProjectWorkspaceProgress { | ||
20 | Begin, | ||
21 | Report(String), | ||
22 | End(Vec<anyhow::Result<ProjectWorkspace>>), | ||
23 | } | ||
24 | |||
18 | impl GlobalState { | 25 | impl GlobalState { |
19 | pub(crate) fn update_configuration(&mut self, config: Config) { | 26 | pub(crate) fn update_configuration(&mut self, config: Config) { |
20 | let _p = profile::span("GlobalState::update_configuration"); | 27 | let _p = profile::span("GlobalState::update_configuration"); |
21 | let old_config = mem::replace(&mut self.config, config); | 28 | let old_config = mem::replace(&mut self.config, Arc::new(config)); |
22 | if self.config.lru_capacity != old_config.lru_capacity { | 29 | if self.config.lru_capacity() != old_config.lru_capacity() { |
23 | self.analysis_host.update_lru_capacity(old_config.lru_capacity); | 30 | self.analysis_host.update_lru_capacity(self.config.lru_capacity()); |
24 | } | 31 | } |
25 | if self.config.linked_projects != old_config.linked_projects { | 32 | if self.config.linked_projects() != old_config.linked_projects() { |
26 | self.fetch_workspaces() | 33 | self.fetch_workspaces_request() |
27 | } else if self.config.flycheck != old_config.flycheck { | 34 | } else if self.config.flycheck() != old_config.flycheck() { |
28 | self.reload_flycheck(); | 35 | self.reload_flycheck(); |
29 | } | 36 | } |
30 | } | 37 | } |
@@ -36,8 +43,8 @@ impl GlobalState { | |||
36 | Status::Loading | Status::NeedsReload => return, | 43 | Status::Loading | Status::NeedsReload => return, |
37 | Status::Ready | Status::Invalid => (), | 44 | Status::Ready | Status::Invalid => (), |
38 | } | 45 | } |
39 | if self.config.cargo_autoreload { | 46 | if self.config.cargo_autoreload() { |
40 | self.fetch_workspaces(); | 47 | self.fetch_workspaces_request(); |
41 | } else { | 48 | } else { |
42 | self.transition(Status::NeedsReload); | 49 | self.transition(Status::NeedsReload); |
43 | } | 50 | } |
@@ -79,7 +86,7 @@ impl GlobalState { | |||
79 | } | 86 | } |
80 | pub(crate) fn transition(&mut self, new_status: Status) { | 87 | pub(crate) fn transition(&mut self, new_status: Status) { |
81 | self.status = new_status; | 88 | self.status = new_status; |
82 | if self.config.client_caps.status_notification { | 89 | if self.config.status_notification() { |
83 | let lsp_status = match new_status { | 90 | let lsp_status = match new_status { |
84 | Status::Loading => lsp_ext::Status::Loading, | 91 | Status::Loading => lsp_ext::Status::Loading, |
85 | Status::Ready => lsp_ext::Status::Ready, | 92 | Status::Ready => lsp_ext::Status::Ready, |
@@ -91,28 +98,59 @@ impl GlobalState { | |||
91 | }); | 98 | }); |
92 | } | 99 | } |
93 | } | 100 | } |
94 | pub(crate) fn fetch_workspaces(&mut self) { | 101 | |
102 | pub(crate) fn fetch_workspaces_request(&mut self) { | ||
103 | self.fetch_workspaces_queue.request_op() | ||
104 | } | ||
105 | pub(crate) fn fetch_workspaces_if_needed(&mut self) { | ||
95 | log::info!("will fetch workspaces"); | 106 | log::info!("will fetch workspaces"); |
96 | self.task_pool.handle.spawn({ | 107 | if !self.fetch_workspaces_queue.should_start_op() { |
97 | let linked_projects = self.config.linked_projects.clone(); | 108 | return; |
98 | let cargo_config = self.config.cargo.clone(); | 109 | } |
99 | move || { | 110 | |
111 | self.task_pool.handle.spawn_with_sender({ | ||
112 | let linked_projects = self.config.linked_projects(); | ||
113 | let cargo_config = self.config.cargo(); | ||
114 | |||
115 | move |sender| { | ||
116 | let progress = { | ||
117 | let sender = sender.clone(); | ||
118 | move |msg| { | ||
119 | sender | ||
120 | .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg))) | ||
121 | .unwrap() | ||
122 | } | ||
123 | }; | ||
124 | |||
125 | sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap(); | ||
126 | |||
100 | let workspaces = linked_projects | 127 | let workspaces = linked_projects |
101 | .iter() | 128 | .iter() |
102 | .map(|project| match project { | 129 | .map(|project| match project { |
103 | LinkedProject::ProjectManifest(manifest) => { | 130 | LinkedProject::ProjectManifest(manifest) => { |
104 | project_model::ProjectWorkspace::load(manifest.clone(), &cargo_config) | 131 | project_model::ProjectWorkspace::load( |
132 | manifest.clone(), | ||
133 | &cargo_config, | ||
134 | &progress, | ||
135 | ) | ||
105 | } | 136 | } |
106 | LinkedProject::InlineJsonProject(it) => { | 137 | LinkedProject::InlineJsonProject(it) => { |
107 | project_model::ProjectWorkspace::load_inline(it.clone()) | 138 | project_model::ProjectWorkspace::load_inline(it.clone()) |
108 | } | 139 | } |
109 | }) | 140 | }) |
110 | .collect::<Vec<_>>(); | 141 | .collect::<Vec<_>>(); |
142 | |||
111 | log::info!("did fetch workspaces {:?}", workspaces); | 143 | log::info!("did fetch workspaces {:?}", workspaces); |
112 | Task::Workspaces(workspaces) | 144 | sender |
145 | .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces))) | ||
146 | .unwrap(); | ||
113 | } | 147 | } |
114 | }); | 148 | }); |
115 | } | 149 | } |
150 | pub(crate) fn fetch_workspaces_completed(&mut self) { | ||
151 | self.fetch_workspaces_queue.op_completed() | ||
152 | } | ||
153 | |||
116 | pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) { | 154 | pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) { |
117 | let _p = profile::span("GlobalState::switch_workspaces"); | 155 | let _p = profile::span("GlobalState::switch_workspaces"); |
118 | log::info!("will switch workspaces: {:?}", workspaces); | 156 | log::info!("will switch workspaces: {:?}", workspaces); |
@@ -143,36 +181,41 @@ impl GlobalState { | |||
143 | return; | 181 | return; |
144 | } | 182 | } |
145 | 183 | ||
146 | if let FilesWatcher::Client = self.config.files.watcher { | 184 | if let FilesWatcher::Client = self.config.files().watcher { |
147 | let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { | 185 | if self.config.did_change_watched_files_dynamic_registration() { |
148 | watchers: workspaces | 186 | let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { |
149 | .iter() | 187 | watchers: workspaces |
150 | .flat_map(ProjectWorkspace::to_roots) | 188 | .iter() |
151 | .filter(|it| it.is_member) | 189 | .flat_map(ProjectWorkspace::to_roots) |
152 | .flat_map(|root| { | 190 | .filter(|it| it.is_member) |
153 | root.include.into_iter().map(|it| format!("{}/**/*.rs", it.display())) | 191 | .flat_map(|root| { |
154 | }) | 192 | root.include.into_iter().map(|it| format!("{}/**/*.rs", it.display())) |
155 | .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None }) | 193 | }) |
156 | .collect(), | 194 | .map(|glob_pattern| lsp_types::FileSystemWatcher { |
157 | }; | 195 | glob_pattern, |
158 | let registration = lsp_types::Registration { | 196 | kind: None, |
159 | id: "workspace/didChangeWatchedFiles".to_string(), | 197 | }) |
160 | method: "workspace/didChangeWatchedFiles".to_string(), | 198 | .collect(), |
161 | register_options: Some(serde_json::to_value(registration_options).unwrap()), | 199 | }; |
162 | }; | 200 | let registration = lsp_types::Registration { |
163 | self.send_request::<lsp_types::request::RegisterCapability>( | 201 | id: "workspace/didChangeWatchedFiles".to_string(), |
164 | lsp_types::RegistrationParams { registrations: vec![registration] }, | 202 | method: "workspace/didChangeWatchedFiles".to_string(), |
165 | |_, _| (), | 203 | register_options: Some(serde_json::to_value(registration_options).unwrap()), |
166 | ); | 204 | }; |
205 | self.send_request::<lsp_types::request::RegisterCapability>( | ||
206 | lsp_types::RegistrationParams { registrations: vec![registration] }, | ||
207 | |_, _| (), | ||
208 | ); | ||
209 | } | ||
167 | } | 210 | } |
168 | 211 | ||
169 | let mut change = Change::new(); | 212 | let mut change = Change::new(); |
170 | 213 | ||
171 | let project_folders = ProjectFolders::new(&workspaces); | 214 | let project_folders = ProjectFolders::new(&workspaces); |
172 | 215 | ||
173 | self.proc_macro_client = match &self.config.proc_macro_srv { | 216 | self.proc_macro_client = match self.config.proc_macro_srv() { |
174 | None => None, | 217 | None => None, |
175 | Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { | 218 | Some((path, args)) => match ProcMacroClient::extern_process(path.clone(), args) { |
176 | Ok(it) => Some(it), | 219 | Ok(it) => Some(it), |
177 | Err(err) => { | 220 | Err(err) => { |
178 | log::error!( | 221 | log::error!( |
@@ -185,7 +228,7 @@ impl GlobalState { | |||
185 | }, | 228 | }, |
186 | }; | 229 | }; |
187 | 230 | ||
188 | let watch = match self.config.files.watcher { | 231 | let watch = match self.config.files().watcher { |
189 | FilesWatcher::Client => vec![], | 232 | FilesWatcher::Client => vec![], |
190 | FilesWatcher::Notify => project_folders.watch, | 233 | FilesWatcher::Notify => project_folders.watch, |
191 | }; | 234 | }; |
@@ -211,7 +254,7 @@ impl GlobalState { | |||
211 | }; | 254 | }; |
212 | for ws in workspaces.iter() { | 255 | for ws in workspaces.iter() { |
213 | crate_graph.extend(ws.to_crate_graph( | 256 | crate_graph.extend(ws.to_crate_graph( |
214 | self.config.cargo.target.as_deref(), | 257 | self.config.cargo().target.as_deref(), |
215 | self.proc_macro_client.as_ref(), | 258 | self.proc_macro_client.as_ref(), |
216 | &mut load, | 259 | &mut load, |
217 | )); | 260 | )); |
@@ -231,7 +274,7 @@ impl GlobalState { | |||
231 | } | 274 | } |
232 | 275 | ||
233 | fn reload_flycheck(&mut self) { | 276 | fn reload_flycheck(&mut self) { |
234 | let config = match self.config.flycheck.clone() { | 277 | let config = match self.config.flycheck() { |
235 | Some(it) => it, | 278 | Some(it) => it, |
236 | None => { | 279 | None => { |
237 | self.flycheck = Vec::new(); | 280 | self.flycheck = Vec::new(); |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index c2f6a655d..7ce9a4ab6 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -38,16 +38,25 @@ macro_rules! define_semantic_token_types { | |||
38 | } | 38 | } |
39 | 39 | ||
40 | define_semantic_token_types![ | 40 | define_semantic_token_types![ |
41 | (ANGLE, "angle"), | ||
41 | (ATTRIBUTE, "attribute"), | 42 | (ATTRIBUTE, "attribute"), |
42 | (BOOLEAN, "boolean"), | 43 | (BOOLEAN, "boolean"), |
44 | (BRACE, "brace"), | ||
45 | (BRACKET, "bracket"), | ||
43 | (BUILTIN_TYPE, "builtinType"), | 46 | (BUILTIN_TYPE, "builtinType"), |
47 | (COMMA, "comma"), | ||
48 | (COLON, "colon"), | ||
49 | (DOT, "dot"), | ||
44 | (ESCAPE_SEQUENCE, "escapeSequence"), | 50 | (ESCAPE_SEQUENCE, "escapeSequence"), |
45 | (FORMAT_SPECIFIER, "formatSpecifier"), | 51 | (FORMAT_SPECIFIER, "formatSpecifier"), |
46 | (GENERIC, "generic"), | 52 | (GENERIC, "generic"), |
53 | (CONST_PARAMETER, "constParameter"), | ||
47 | (LIFETIME, "lifetime"), | 54 | (LIFETIME, "lifetime"), |
48 | (LABEL, "label"), | 55 | (LABEL, "label"), |
56 | (PARENTHESIS, "parenthesis"), | ||
49 | (PUNCTUATION, "punctuation"), | 57 | (PUNCTUATION, "punctuation"), |
50 | (SELF_KEYWORD, "selfKeyword"), | 58 | (SELF_KEYWORD, "selfKeyword"), |
59 | (SEMICOLON, "semicolon"), | ||
51 | (TYPE_ALIAS, "typeAlias"), | 60 | (TYPE_ALIAS, "typeAlias"), |
52 | (UNION, "union"), | 61 | (UNION, "union"), |
53 | (UNRESOLVED_REFERENCE, "unresolvedReference"), | 62 | (UNRESOLVED_REFERENCE, "unresolvedReference"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 1a38e79f0..a7ff8975a 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -6,10 +6,10 @@ use std::{ | |||
6 | 6 | ||
7 | use ide::{ | 7 | use ide::{ |
8 | Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId, | 8 | Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId, |
9 | FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, | 9 | FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, HlRange, HlTag, Indel, |
10 | HighlightedRange, Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, | 10 | InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, ReferenceAccess, |
11 | NavigationTarget, ReferenceAccess, Runnable, Severity, SourceChange, SourceFileEdit, | 11 | RenameError, Runnable, Severity, SourceChange, SourceFileEdit, SymbolKind, TextEdit, TextRange, |
12 | SymbolKind, TextEdit, TextRange, TextSize, | 12 | TextSize, |
13 | }; | 13 | }; |
14 | use itertools::Itertools; | 14 | use itertools::Itertools; |
15 | 15 | ||
@@ -42,6 +42,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { | |||
42 | SymbolKind::Field => lsp_types::SymbolKind::Field, | 42 | SymbolKind::Field => lsp_types::SymbolKind::Field, |
43 | SymbolKind::Static => lsp_types::SymbolKind::Constant, | 43 | SymbolKind::Static => lsp_types::SymbolKind::Constant, |
44 | SymbolKind::Const => lsp_types::SymbolKind::Constant, | 44 | SymbolKind::Const => lsp_types::SymbolKind::Constant, |
45 | SymbolKind::ConstParam => lsp_types::SymbolKind::Constant, | ||
45 | SymbolKind::Impl => lsp_types::SymbolKind::Object, | 46 | SymbolKind::Impl => lsp_types::SymbolKind::Object, |
46 | SymbolKind::Local | 47 | SymbolKind::Local |
47 | | SymbolKind::SelfParam | 48 | | SymbolKind::SelfParam |
@@ -336,12 +337,15 @@ static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); | |||
336 | pub(crate) fn semantic_tokens( | 337 | pub(crate) fn semantic_tokens( |
337 | text: &str, | 338 | text: &str, |
338 | line_index: &LineIndex, | 339 | line_index: &LineIndex, |
339 | highlights: Vec<HighlightedRange>, | 340 | highlights: Vec<HlRange>, |
340 | ) -> lsp_types::SemanticTokens { | 341 | ) -> lsp_types::SemanticTokens { |
341 | let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); | 342 | let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); |
342 | let mut builder = semantic_tokens::SemanticTokensBuilder::new(id); | 343 | let mut builder = semantic_tokens::SemanticTokensBuilder::new(id); |
343 | 344 | ||
344 | for highlight_range in highlights { | 345 | for highlight_range in highlights { |
346 | if highlight_range.highlight.is_empty() { | ||
347 | continue; | ||
348 | } | ||
345 | let (type_, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); | 349 | let (type_, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); |
346 | let token_index = semantic_tokens::type_index(type_); | 350 | let token_index = semantic_tokens::type_index(type_); |
347 | let modifier_bitset = mods.0; | 351 | let modifier_bitset = mods.0; |
@@ -373,18 +377,19 @@ fn semantic_token_type_and_modifiers( | |||
373 | ) -> (lsp_types::SemanticTokenType, semantic_tokens::ModifierSet) { | 377 | ) -> (lsp_types::SemanticTokenType, semantic_tokens::ModifierSet) { |
374 | let mut mods = semantic_tokens::ModifierSet::default(); | 378 | let mut mods = semantic_tokens::ModifierSet::default(); |
375 | let type_ = match highlight.tag { | 379 | let type_ = match highlight.tag { |
376 | HighlightTag::Symbol(symbol) => match symbol { | 380 | HlTag::Symbol(symbol) => match symbol { |
377 | SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, | 381 | SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, |
378 | SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE, | 382 | SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE, |
379 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, | 383 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, |
380 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, | 384 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, |
385 | SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER, | ||
381 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, | 386 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, |
382 | SymbolKind::Label => semantic_tokens::LABEL, | 387 | SymbolKind::Label => semantic_tokens::LABEL, |
383 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, | 388 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, |
384 | SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD, | 389 | SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD, |
385 | SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE, | 390 | SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE, |
386 | SymbolKind::Function => { | 391 | SymbolKind::Function => { |
387 | if highlight.modifiers.contains(HighlightModifier::Associated) { | 392 | if highlight.mods.contains(HlMod::Associated) { |
388 | lsp_types::SemanticTokenType::METHOD | 393 | lsp_types::SemanticTokenType::METHOD |
389 | } else { | 394 | } else { |
390 | lsp_types::SemanticTokenType::FUNCTION | 395 | lsp_types::SemanticTokenType::FUNCTION |
@@ -407,38 +412,44 @@ fn semantic_token_type_and_modifiers( | |||
407 | SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE, | 412 | SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE, |
408 | SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO, | 413 | SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO, |
409 | }, | 414 | }, |
410 | HighlightTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, | 415 | HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, |
411 | HighlightTag::Dummy => semantic_tokens::GENERIC, | 416 | HlTag::None => semantic_tokens::GENERIC, |
412 | HighlightTag::ByteLiteral | HighlightTag::NumericLiteral => { | 417 | HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, |
413 | lsp_types::SemanticTokenType::NUMBER | 418 | HlTag::BoolLiteral => semantic_tokens::BOOLEAN, |
414 | } | 419 | HlTag::CharLiteral | HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, |
415 | HighlightTag::BoolLiteral => semantic_tokens::BOOLEAN, | 420 | HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, |
416 | HighlightTag::CharLiteral | HighlightTag::StringLiteral => { | 421 | HlTag::Attribute => semantic_tokens::ATTRIBUTE, |
417 | lsp_types::SemanticTokenType::STRING | 422 | HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, |
418 | } | 423 | HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, |
419 | HighlightTag::Comment => lsp_types::SemanticTokenType::COMMENT, | 424 | HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, |
420 | HighlightTag::Attribute => semantic_tokens::ATTRIBUTE, | 425 | HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR, |
421 | HighlightTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, | 426 | HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, |
422 | HighlightTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, | 427 | HlTag::Punctuation(punct) => match punct { |
423 | HighlightTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, | 428 | HlPunct::Bracket => semantic_tokens::BRACKET, |
424 | HighlightTag::Operator => lsp_types::SemanticTokenType::OPERATOR, | 429 | HlPunct::Brace => semantic_tokens::BRACE, |
425 | HighlightTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, | 430 | HlPunct::Parenthesis => semantic_tokens::PARENTHESIS, |
426 | HighlightTag::Punctuation => semantic_tokens::PUNCTUATION, | 431 | HlPunct::Angle => semantic_tokens::ANGLE, |
432 | HlPunct::Comma => semantic_tokens::COMMA, | ||
433 | HlPunct::Dot => semantic_tokens::DOT, | ||
434 | HlPunct::Colon => semantic_tokens::COLON, | ||
435 | HlPunct::Semi => semantic_tokens::SEMICOLON, | ||
436 | HlPunct::Other => semantic_tokens::PUNCTUATION, | ||
437 | }, | ||
427 | }; | 438 | }; |
428 | 439 | ||
429 | for modifier in highlight.modifiers.iter() { | 440 | for modifier in highlight.mods.iter() { |
430 | let modifier = match modifier { | 441 | let modifier = match modifier { |
431 | HighlightModifier::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER, | 442 | HlMod::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER, |
432 | HighlightModifier::Definition => lsp_types::SemanticTokenModifier::DECLARATION, | 443 | HlMod::Definition => lsp_types::SemanticTokenModifier::DECLARATION, |
433 | HighlightModifier::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION, | 444 | HlMod::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION, |
434 | HighlightModifier::Injected => semantic_tokens::INJECTED, | 445 | HlMod::Injected => semantic_tokens::INJECTED, |
435 | HighlightModifier::ControlFlow => semantic_tokens::CONTROL_FLOW, | 446 | HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW, |
436 | HighlightModifier::Mutable => semantic_tokens::MUTABLE, | 447 | HlMod::Mutable => semantic_tokens::MUTABLE, |
437 | HighlightModifier::Consuming => semantic_tokens::CONSUMING, | 448 | HlMod::Consuming => semantic_tokens::CONSUMING, |
438 | HighlightModifier::Unsafe => semantic_tokens::UNSAFE, | 449 | HlMod::Unsafe => semantic_tokens::UNSAFE, |
439 | HighlightModifier::Callable => semantic_tokens::CALLABLE, | 450 | HlMod::Callable => semantic_tokens::CALLABLE, |
440 | HighlightModifier::Static => lsp_types::SemanticTokenModifier::STATIC, | 451 | HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, |
441 | HighlightModifier::Associated => continue, | 452 | HlMod::Associated => continue, |
442 | }; | 453 | }; |
443 | mods |= modifier; | 454 | mods |= modifier; |
444 | } | 455 | } |
@@ -603,7 +614,7 @@ pub(crate) fn goto_definition_response( | |||
603 | src: Option<FileRange>, | 614 | src: Option<FileRange>, |
604 | targets: Vec<NavigationTarget>, | 615 | targets: Vec<NavigationTarget>, |
605 | ) -> Result<lsp_types::GotoDefinitionResponse> { | 616 | ) -> Result<lsp_types::GotoDefinitionResponse> { |
606 | if snap.config.client_caps.location_link { | 617 | if snap.config.location_link() { |
607 | let links = targets | 618 | let links = targets |
608 | .into_iter() | 619 | .into_iter() |
609 | .map(|nav| location_link(snap, src, nav)) | 620 | .map(|nav| location_link(snap, src, nav)) |
@@ -783,7 +794,7 @@ pub(crate) fn unresolved_code_action( | |||
783 | assert!(assist.source_change.is_none()); | 794 | assert!(assist.source_change.is_none()); |
784 | let res = lsp_ext::CodeAction { | 795 | let res = lsp_ext::CodeAction { |
785 | title: assist.label.to_string(), | 796 | title: assist.label.to_string(), |
786 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | 797 | group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), |
787 | kind: Some(code_action_kind(assist.id.1)), | 798 | kind: Some(code_action_kind(assist.id.1)), |
788 | edit: None, | 799 | edit: None, |
789 | is_preferred: None, | 800 | is_preferred: None, |
@@ -803,7 +814,7 @@ pub(crate) fn resolved_code_action( | |||
803 | let res = lsp_ext::CodeAction { | 814 | let res = lsp_ext::CodeAction { |
804 | edit: Some(snippet_workspace_edit(snap, change)?), | 815 | edit: Some(snippet_workspace_edit(snap, change)?), |
805 | title: assist.label.to_string(), | 816 | title: assist.label.to_string(), |
806 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | 817 | group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), |
807 | kind: Some(code_action_kind(assist.id.1)), | 818 | kind: Some(code_action_kind(assist.id.1)), |
808 | is_preferred: None, | 819 | is_preferred: None, |
809 | data: None, | 820 | data: None, |
@@ -816,7 +827,7 @@ pub(crate) fn runnable( | |||
816 | file_id: FileId, | 827 | file_id: FileId, |
817 | runnable: Runnable, | 828 | runnable: Runnable, |
818 | ) -> Result<lsp_ext::Runnable> { | 829 | ) -> Result<lsp_ext::Runnable> { |
819 | let config = &snap.config.runnables; | 830 | let config = snap.config.runnables(); |
820 | let spec = CargoTargetSpec::for_file(snap, file_id)?; | 831 | let spec = CargoTargetSpec::for_file(snap, file_id)?; |
821 | let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); | 832 | let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); |
822 | let target = spec.as_ref().map(|s| s.target.clone()); | 833 | let target = spec.as_ref().map(|s| s.target.clone()); |
@@ -831,9 +842,9 @@ pub(crate) fn runnable( | |||
831 | kind: lsp_ext::RunnableKind::Cargo, | 842 | kind: lsp_ext::RunnableKind::Cargo, |
832 | args: lsp_ext::CargoRunnable { | 843 | args: lsp_ext::CargoRunnable { |
833 | workspace_root: workspace_root.map(|it| it.into()), | 844 | workspace_root: workspace_root.map(|it| it.into()), |
834 | override_cargo: config.override_cargo.clone(), | 845 | override_cargo: config.override_cargo, |
835 | cargo_args, | 846 | cargo_args, |
836 | cargo_extra_args: config.cargo_extra_args.clone(), | 847 | cargo_extra_args: config.cargo_extra_args, |
837 | executable_args, | 848 | executable_args, |
838 | expect_test: None, | 849 | expect_test: None, |
839 | }, | 850 | }, |
@@ -845,9 +856,14 @@ pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent { | |||
845 | lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value } | 856 | lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value } |
846 | } | 857 | } |
847 | 858 | ||
859 | pub(crate) fn rename_error(err: RenameError) -> crate::LspError { | ||
860 | crate::LspError { code: lsp_server::ErrorCode::InvalidParams as i32, message: err.to_string() } | ||
861 | } | ||
862 | |||
848 | #[cfg(test)] | 863 | #[cfg(test)] |
849 | mod tests { | 864 | mod tests { |
850 | use ide::Analysis; | 865 | use ide::Analysis; |
866 | use ide_db::helpers::SnippetCap; | ||
851 | 867 | ||
852 | use super::*; | 868 | use super::*; |
853 | 869 | ||
@@ -858,7 +874,7 @@ mod tests { | |||
858 | fn foo(arg: &Foo) {} | 874 | fn foo(arg: &Foo) {} |
859 | fn main() { | 875 | fn main() { |
860 | let arg = Foo; | 876 | let arg = Foo; |
861 | foo(<|>) | 877 | foo($0) |
862 | }"#; | 878 | }"#; |
863 | 879 | ||
864 | let (offset, text) = test_utils::extract_offset(fixture); | 880 | let (offset, text) = test_utils::extract_offset(fixture); |
@@ -866,7 +882,14 @@ mod tests { | |||
866 | let (analysis, file_id) = Analysis::from_single_file(text); | 882 | let (analysis, file_id) = Analysis::from_single_file(text); |
867 | let completions: Vec<(String, Option<String>)> = analysis | 883 | let completions: Vec<(String, Option<String>)> = analysis |
868 | .completions( | 884 | .completions( |
869 | &ide::CompletionConfig::default(), | 885 | &ide::CompletionConfig { |
886 | enable_postfix_completions: true, | ||
887 | enable_autoimport_completions: true, | ||
888 | add_call_parenthesis: true, | ||
889 | add_call_argument_snippets: true, | ||
890 | snippet_cap: SnippetCap::new(true), | ||
891 | merge: None, | ||
892 | }, | ||
870 | ide_db::base_db::FilePosition { file_id, offset }, | 893 | ide_db::base_db::FilePosition { file_id, offset }, |
871 | ) | 894 | ) |
872 | .unwrap() | 895 | .unwrap() |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs index e51eb2626..80bde29b9 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/main.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs | |||
@@ -13,13 +13,17 @@ mod support; | |||
13 | 13 | ||
14 | use std::{collections::HashMap, path::PathBuf, time::Instant}; | 14 | use std::{collections::HashMap, path::PathBuf, time::Instant}; |
15 | 15 | ||
16 | use expect_test::expect; | ||
16 | use lsp_types::{ | 17 | use lsp_types::{ |
17 | notification::DidOpenTextDocument, | 18 | notification::DidOpenTextDocument, |
18 | request::{CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest}, | 19 | request::{ |
20 | CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest, | ||
21 | WillRenameFiles, | ||
22 | }, | ||
19 | CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, | 23 | CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, |
20 | DocumentFormattingParams, FormattingOptions, GotoDefinitionParams, HoverParams, | 24 | DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams, |
21 | PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams, | 25 | PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem, |
22 | WorkDoneProgressParams, | 26 | TextDocumentPositionParams, WorkDoneProgressParams, |
23 | }; | 27 | }; |
24 | use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams}; | 28 | use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams}; |
25 | use serde_json::json; | 29 | use serde_json::json; |
@@ -190,15 +194,10 @@ pub use std::collections::HashMap; | |||
190 | }, | 194 | }, |
191 | json!([ | 195 | json!([ |
192 | { | 196 | { |
193 | "newText": r#"mod bar; | 197 | "newText": "", |
194 | |||
195 | fn main() {} | ||
196 | |||
197 | pub use std::collections::HashMap; | ||
198 | "#, | ||
199 | "range": { | 198 | "range": { |
200 | "end": { "character": 0, "line": 6 }, | 199 | "end": { "character": 0, "line": 3 }, |
201 | "start": { "character": 0, "line": 0 } | 200 | "start": { "character": 11, "line": 2 } |
202 | } | 201 | } |
203 | } | 202 | } |
204 | ]), | 203 | ]), |
@@ -248,17 +247,17 @@ pub use std::collections::HashMap; | |||
248 | }, | 247 | }, |
249 | json!([ | 248 | json!([ |
250 | { | 249 | { |
251 | "newText": r#"mod bar; | 250 | "newText": "", |
252 | 251 | "range": { | |
253 | async fn test() {} | 252 | "end": { "character": 0, "line": 3 }, |
254 | 253 | "start": { "character": 17, "line": 2 } | |
255 | fn main() {} | 254 | } |
256 | 255 | }, | |
257 | pub use std::collections::HashMap; | 256 | { |
258 | "#, | 257 | "newText": "", |
259 | "range": { | 258 | "range": { |
260 | "end": { "character": 0, "line": 9 }, | 259 | "end": { "character": 0, "line": 6 }, |
261 | "start": { "character": 0, "line": 0 } | 260 | "start": { "character": 11, "line": 5 } |
262 | } | 261 | } |
263 | } | 262 | } |
264 | ]), | 263 | ]), |
@@ -574,9 +573,9 @@ fn main() { | |||
574 | } | 573 | } |
575 | "###, | 574 | "###, |
576 | ) | 575 | ) |
577 | .with_config(|config| { | 576 | .with_config(serde_json::json!({ |
578 | config.cargo.load_out_dirs_from_check = true; | 577 | "cargo": { "loadOutDirsFromCheck": true } |
579 | }) | 578 | })) |
580 | .server() | 579 | .server() |
581 | .wait_until_workspace_is_loaded(); | 580 | .wait_until_workspace_is_loaded(); |
582 | 581 | ||
@@ -717,12 +716,13 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
717 | 716 | ||
718 | "###, | 717 | "###, |
719 | ) | 718 | ) |
720 | .with_config(|config| { | 719 | .with_config(serde_json::json!({ |
721 | let macro_srv_path = PathBuf::from(env!("CARGO_BIN_EXE_rust-analyzer")); | 720 | "cargo": { "loadOutDirsFromCheck": true }, |
722 | 721 | "procMacro": { | |
723 | config.cargo.load_out_dirs_from_check = true; | 722 | "enable": true, |
724 | config.proc_macro_srv = Some((macro_srv_path, vec!["proc-macro".into()])); | 723 | "server": PathBuf::from(env!("CARGO_BIN_EXE_rust-analyzer")), |
725 | }) | 724 | } |
725 | })) | ||
726 | .root("foo") | 726 | .root("foo") |
727 | .root("bar") | 727 | .root("bar") |
728 | .server() | 728 | .server() |
@@ -735,6 +735,149 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
735 | ), | 735 | ), |
736 | work_done_progress_params: Default::default(), | 736 | work_done_progress_params: Default::default(), |
737 | }); | 737 | }); |
738 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); | 738 | let value = res.get("contents").unwrap().get("value").unwrap().as_str().unwrap(); |
739 | assert_eq!(value, r#""\n```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#) | 739 | |
740 | expect![[r#" | ||
741 | |||
742 | ```rust | ||
743 | foo::Bar | ||
744 | ``` | ||
745 | |||
746 | ```rust | ||
747 | fn bar() | ||
748 | ```"#]] | ||
749 | .assert_eq(&value); | ||
750 | } | ||
751 | |||
752 | #[test] | ||
753 | fn test_will_rename_files_same_level() { | ||
754 | if skip_slow_tests() { | ||
755 | return; | ||
756 | } | ||
757 | |||
758 | let tmp_dir = TestDir::new(); | ||
759 | let tmp_dir_path = tmp_dir.path().to_owned(); | ||
760 | let tmp_dir_str = tmp_dir_path.to_str().unwrap(); | ||
761 | let base_path = PathBuf::from(format!("file://{}", tmp_dir_str)); | ||
762 | |||
763 | let code = r#" | ||
764 | //- /Cargo.toml | ||
765 | [package] | ||
766 | name = "foo" | ||
767 | version = "0.0.0" | ||
768 | |||
769 | //- /src/lib.rs | ||
770 | mod old_file; | ||
771 | mod from_mod; | ||
772 | mod to_mod; | ||
773 | mod old_folder; | ||
774 | fn main() {} | ||
775 | |||
776 | //- /src/old_file.rs | ||
777 | |||
778 | //- /src/old_folder/mod.rs | ||
779 | |||
780 | //- /src/from_mod/mod.rs | ||
781 | |||
782 | //- /src/to_mod/foo.rs | ||
783 | |||
784 | "#; | ||
785 | let server = | ||
786 | Project::with_fixture(&code).tmp_dir(tmp_dir).server().wait_until_workspace_is_loaded(); | ||
787 | |||
788 | //rename same level file | ||
789 | server.request::<WillRenameFiles>( | ||
790 | RenameFilesParams { | ||
791 | files: vec![FileRename { | ||
792 | old_uri: base_path.join("src/old_file.rs").to_str().unwrap().to_string(), | ||
793 | new_uri: base_path.join("src/new_file.rs").to_str().unwrap().to_string(), | ||
794 | }], | ||
795 | }, | ||
796 | json!({ | ||
797 | "documentChanges": [ | ||
798 | { | ||
799 | "textDocument": { | ||
800 | "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace("\\", "/")), | ||
801 | "version": null | ||
802 | }, | ||
803 | "edits": [ | ||
804 | { | ||
805 | "range": { | ||
806 | "start": { | ||
807 | "line": 0, | ||
808 | "character": 4 | ||
809 | }, | ||
810 | "end": { | ||
811 | "line": 0, | ||
812 | "character": 12 | ||
813 | } | ||
814 | }, | ||
815 | "newText": "new_file" | ||
816 | } | ||
817 | ] | ||
818 | } | ||
819 | ] | ||
820 | }), | ||
821 | ); | ||
822 | |||
823 | //rename file from mod.rs to foo.rs | ||
824 | server.request::<WillRenameFiles>( | ||
825 | RenameFilesParams { | ||
826 | files: vec![FileRename { | ||
827 | old_uri: base_path.join("src/from_mod/mod.rs").to_str().unwrap().to_string(), | ||
828 | new_uri: base_path.join("src/from_mod/foo.rs").to_str().unwrap().to_string(), | ||
829 | }], | ||
830 | }, | ||
831 | json!({ | ||
832 | "documentChanges": [] | ||
833 | }), | ||
834 | ); | ||
835 | |||
836 | //rename file from foo.rs to mod.rs | ||
837 | server.request::<WillRenameFiles>( | ||
838 | RenameFilesParams { | ||
839 | files: vec![FileRename { | ||
840 | old_uri: base_path.join("src/to_mod/foo.rs").to_str().unwrap().to_string(), | ||
841 | new_uri: base_path.join("src/to_mod/mod.rs").to_str().unwrap().to_string(), | ||
842 | }], | ||
843 | }, | ||
844 | json!({ | ||
845 | "documentChanges": [] | ||
846 | }), | ||
847 | ); | ||
848 | |||
849 | //rename same level file | ||
850 | server.request::<WillRenameFiles>( | ||
851 | RenameFilesParams { | ||
852 | files: vec![FileRename { | ||
853 | old_uri: base_path.join("src/old_folder").to_str().unwrap().to_string(), | ||
854 | new_uri: base_path.join("src/new_folder").to_str().unwrap().to_string(), | ||
855 | }], | ||
856 | }, | ||
857 | json!({ | ||
858 | "documentChanges": [ | ||
859 | { | ||
860 | "textDocument": { | ||
861 | "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace("\\", "/")), | ||
862 | "version": null | ||
863 | }, | ||
864 | "edits": [ | ||
865 | { | ||
866 | "range": { | ||
867 | "start": { | ||
868 | "line": 3, | ||
869 | "character": 4 | ||
870 | }, | ||
871 | "end": { | ||
872 | "line": 3, | ||
873 | "character": 14 | ||
874 | } | ||
875 | }, | ||
876 | "newText": "new_folder" | ||
877 | } | ||
878 | ] | ||
879 | } | ||
880 | ] | ||
881 | }), | ||
882 | ); | ||
740 | } | 883 | } |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs index 456125789..2658ee185 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/support.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs | |||
@@ -12,11 +12,8 @@ use lsp_types::{ | |||
12 | notification::Exit, request::Shutdown, TextDocumentIdentifier, Url, WorkDoneProgress, | 12 | notification::Exit, request::Shutdown, TextDocumentIdentifier, Url, WorkDoneProgress, |
13 | }; | 13 | }; |
14 | use lsp_types::{ProgressParams, ProgressParamsValue}; | 14 | use lsp_types::{ProgressParams, ProgressParamsValue}; |
15 | use project_model::{CargoConfig, ProjectManifest}; | 15 | use project_model::ProjectManifest; |
16 | use rust_analyzer::{ | 16 | use rust_analyzer::{config::Config, main_loop}; |
17 | config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject}, | ||
18 | main_loop, | ||
19 | }; | ||
20 | use serde::Serialize; | 17 | use serde::Serialize; |
21 | use serde_json::{to_string_pretty, Value}; | 18 | use serde_json::{to_string_pretty, Value}; |
22 | use test_utils::{find_mismatch, Fixture}; | 19 | use test_utils::{find_mismatch, Fixture}; |
@@ -29,12 +26,18 @@ pub(crate) struct Project<'a> { | |||
29 | with_sysroot: bool, | 26 | with_sysroot: bool, |
30 | tmp_dir: Option<TestDir>, | 27 | tmp_dir: Option<TestDir>, |
31 | roots: Vec<PathBuf>, | 28 | roots: Vec<PathBuf>, |
32 | config: Option<Box<dyn Fn(&mut Config)>>, | 29 | config: serde_json::Value, |
33 | } | 30 | } |
34 | 31 | ||
35 | impl<'a> Project<'a> { | 32 | impl<'a> Project<'a> { |
36 | pub(crate) fn with_fixture(fixture: &str) -> Project { | 33 | pub(crate) fn with_fixture(fixture: &str) -> Project { |
37 | Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false, config: None } | 34 | Project { |
35 | fixture, | ||
36 | tmp_dir: None, | ||
37 | roots: vec![], | ||
38 | with_sysroot: false, | ||
39 | config: serde_json::Value::Null, | ||
40 | } | ||
38 | } | 41 | } |
39 | 42 | ||
40 | pub(crate) fn tmp_dir(mut self, tmp_dir: TestDir) -> Project<'a> { | 43 | pub(crate) fn tmp_dir(mut self, tmp_dir: TestDir) -> Project<'a> { |
@@ -52,8 +55,8 @@ impl<'a> Project<'a> { | |||
52 | self | 55 | self |
53 | } | 56 | } |
54 | 57 | ||
55 | pub(crate) fn with_config(mut self, config: impl Fn(&mut Config) + 'static) -> Project<'a> { | 58 | pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> { |
56 | self.config = Some(Box::new(config)); | 59 | self.config = config; |
57 | self | 60 | self |
58 | } | 61 | } |
59 | 62 | ||
@@ -77,27 +80,40 @@ impl<'a> Project<'a> { | |||
77 | if roots.is_empty() { | 80 | if roots.is_empty() { |
78 | roots.push(tmp_dir_path.clone()); | 81 | roots.push(tmp_dir_path.clone()); |
79 | } | 82 | } |
80 | let linked_projects = roots | 83 | let discovered_projects = roots |
81 | .into_iter() | 84 | .into_iter() |
82 | .map(|it| ProjectManifest::discover_single(&it).unwrap()) | 85 | .map(|it| ProjectManifest::discover_single(&it).unwrap()) |
83 | .map(LinkedProject::from) | ||
84 | .collect::<Vec<_>>(); | 86 | .collect::<Vec<_>>(); |
85 | 87 | ||
86 | let mut config = Config { | 88 | let mut config = Config::new( |
87 | client_caps: ClientCapsConfig { | 89 | tmp_dir_path, |
88 | location_link: true, | 90 | lsp_types::ClientCapabilities { |
89 | code_action_literals: true, | 91 | text_document: Some(lsp_types::TextDocumentClientCapabilities { |
90 | work_done_progress: true, | 92 | definition: Some(lsp_types::GotoCapability { |
93 | link_support: Some(true), | ||
94 | ..Default::default() | ||
95 | }), | ||
96 | code_action: Some(lsp_types::CodeActionClientCapabilities { | ||
97 | code_action_literal_support: Some( | ||
98 | lsp_types::CodeActionLiteralSupport::default(), | ||
99 | ), | ||
100 | ..Default::default() | ||
101 | }), | ||
102 | hover: Some(lsp_types::HoverClientCapabilities { | ||
103 | content_format: Some(vec![lsp_types::MarkupKind::Markdown]), | ||
104 | ..Default::default() | ||
105 | }), | ||
106 | ..Default::default() | ||
107 | }), | ||
108 | window: Some(lsp_types::WindowClientCapabilities { | ||
109 | work_done_progress: Some(true), | ||
110 | ..Default::default() | ||
111 | }), | ||
91 | ..Default::default() | 112 | ..Default::default() |
92 | }, | 113 | }, |
93 | cargo: CargoConfig { no_sysroot: !self.with_sysroot, ..Default::default() }, | 114 | ); |
94 | linked_projects, | 115 | config.discovered_projects = Some(discovered_projects); |
95 | files: FilesConfig { watcher: FilesWatcher::Client, exclude: Vec::new() }, | 116 | config.update(self.config); |
96 | ..Config::new(tmp_dir_path) | ||
97 | }; | ||
98 | if let Some(f) = &self.config { | ||
99 | f(&mut config) | ||
100 | } | ||
101 | 117 | ||
102 | Server::new(tmp_dir, config) | 118 | Server::new(tmp_dir, config) |
103 | } | 119 | } |
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml index 98ed25fb6..cc8136d22 100644 --- a/crates/ssr/Cargo.toml +++ b/crates/ssr/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | itertools = "0.9.0" | 15 | itertools = "0.10.0" |
16 | 16 | ||
17 | text_edit = { path = "../text_edit", version = "0.0.0" } | 17 | text_edit = { path = "../text_edit", version = "0.0.0" } |
18 | syntax = { path = "../syntax", version = "0.0.0" } | 18 | syntax = { path = "../syntax", version = "0.0.0" } |
@@ -21,4 +21,4 @@ hir = { path = "../hir", version = "0.0.0" } | |||
21 | test_utils = { path = "../test_utils", version = "0.0.0" } | 21 | test_utils = { path = "../test_utils", version = "0.0.0" } |
22 | 22 | ||
23 | [dev-dependencies] | 23 | [dev-dependencies] |
24 | expect-test = "1.0" | 24 | expect-test = "1.1" |
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs index 99b187311..6cf831431 100644 --- a/crates/ssr/src/matching.rs +++ b/crates/ssr/src/matching.rs | |||
@@ -473,7 +473,9 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
473 | } | 473 | } |
474 | SyntaxElement::Node(n) => { | 474 | SyntaxElement::Node(n) => { |
475 | if let Some(first_token) = n.first_token() { | 475 | if let Some(first_token) = n.first_token() { |
476 | if Some(first_token.to_string()) == next_pattern_token { | 476 | if Some(first_token.text().as_str()) |
477 | == next_pattern_token.as_deref() | ||
478 | { | ||
477 | if let Some(SyntaxElement::Node(p)) = pattern.next() { | 479 | if let Some(SyntaxElement::Node(p)) = pattern.next() { |
478 | // We have a subtree that starts with the next token in our pattern. | 480 | // We have a subtree that starts with the next token in our pattern. |
479 | self.attempt_match_token_tree(phase, &p, &n)?; | 481 | self.attempt_match_token_tree(phase, &p, &n)?; |
diff --git a/crates/ssr/src/parsing.rs b/crates/ssr/src/parsing.rs index f3b084baf..3d5e4feb7 100644 --- a/crates/ssr/src/parsing.rs +++ b/crates/ssr/src/parsing.rs | |||
@@ -73,11 +73,18 @@ impl ParsedRule { | |||
73 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), | 73 | placeholders_by_stand_in: pattern.placeholders_by_stand_in(), |
74 | rules: Vec::new(), | 74 | rules: Vec::new(), |
75 | }; | 75 | }; |
76 | builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse)); | 76 | |
77 | let raw_template_stmt = raw_template.map(ast::Stmt::parse); | ||
78 | if let raw_template_expr @ Some(Ok(_)) = raw_template.map(ast::Expr::parse) { | ||
79 | builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_expr); | ||
80 | } else { | ||
81 | builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone()); | ||
82 | } | ||
77 | builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse)); | 83 | builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse)); |
78 | builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); | 84 | builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); |
79 | builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); | 85 | builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); |
80 | builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); | 86 | builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); |
87 | builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt); | ||
81 | builder.build() | 88 | builder.build() |
82 | } | 89 | } |
83 | } | 90 | } |
@@ -88,7 +95,11 @@ struct RuleBuilder { | |||
88 | } | 95 | } |
89 | 96 | ||
90 | impl RuleBuilder { | 97 | impl RuleBuilder { |
91 | fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<Result<T, ()>>) { | 98 | fn try_add<T: AstNode, T2: AstNode>( |
99 | &mut self, | ||
100 | pattern: Result<T, ()>, | ||
101 | template: Option<Result<T2, ()>>, | ||
102 | ) { | ||
92 | match (pattern, template) { | 103 | match (pattern, template) { |
93 | (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { | 104 | (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule { |
94 | placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), | 105 | placeholders_by_stand_in: self.placeholders_by_stand_in.clone(), |
diff --git a/crates/ssr/src/search.rs b/crates/ssr/src/search.rs index 44b5db029..836eb94b2 100644 --- a/crates/ssr/src/search.rs +++ b/crates/ssr/src/search.rs | |||
@@ -5,10 +5,10 @@ use crate::{ | |||
5 | resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, | 5 | resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, |
6 | Match, MatchFinder, | 6 | Match, MatchFinder, |
7 | }; | 7 | }; |
8 | use ide_db::base_db::{FileId, FileRange}; | ||
9 | use ide_db::{ | 8 | use ide_db::{ |
9 | base_db::{FileId, FileRange}, | ||
10 | defs::Definition, | 10 | defs::Definition, |
11 | search::{Reference, SearchScope}, | 11 | search::{SearchScope, UsageSearchResult}, |
12 | }; | 12 | }; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; | 14 | use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; |
@@ -20,7 +20,7 @@ use test_utils::mark; | |||
20 | /// them more than once. | 20 | /// them more than once. |
21 | #[derive(Default)] | 21 | #[derive(Default)] |
22 | pub(crate) struct UsageCache { | 22 | pub(crate) struct UsageCache { |
23 | usages: Vec<(Definition, Vec<Reference>)>, | 23 | usages: Vec<(Definition, UsageSearchResult)>, |
24 | } | 24 | } |
25 | 25 | ||
26 | impl<'db> MatchFinder<'db> { | 26 | impl<'db> MatchFinder<'db> { |
@@ -58,8 +58,8 @@ impl<'db> MatchFinder<'db> { | |||
58 | ) { | 58 | ) { |
59 | if let Some(resolved_path) = pick_path_for_usages(pattern) { | 59 | if let Some(resolved_path) = pick_path_for_usages(pattern) { |
60 | let definition: Definition = resolved_path.resolution.clone().into(); | 60 | let definition: Definition = resolved_path.resolution.clone().into(); |
61 | for reference in self.find_usages(usage_cache, definition) { | 61 | for file_range in self.find_usages(usage_cache, definition).file_ranges() { |
62 | if let Some(node_to_match) = self.find_node_to_match(resolved_path, reference) { | 62 | if let Some(node_to_match) = self.find_node_to_match(resolved_path, file_range) { |
63 | if !is_search_permitted_ancestors(&node_to_match) { | 63 | if !is_search_permitted_ancestors(&node_to_match) { |
64 | mark::hit!(use_declaration_with_braces); | 64 | mark::hit!(use_declaration_with_braces); |
65 | continue; | 65 | continue; |
@@ -73,11 +73,11 @@ impl<'db> MatchFinder<'db> { | |||
73 | fn find_node_to_match( | 73 | fn find_node_to_match( |
74 | &self, | 74 | &self, |
75 | resolved_path: &ResolvedPath, | 75 | resolved_path: &ResolvedPath, |
76 | reference: &Reference, | 76 | file_range: FileRange, |
77 | ) -> Option<SyntaxNode> { | 77 | ) -> Option<SyntaxNode> { |
78 | let file = self.sema.parse(reference.file_range.file_id); | 78 | let file = self.sema.parse(file_range.file_id); |
79 | let depth = resolved_path.depth as usize; | 79 | let depth = resolved_path.depth as usize; |
80 | let offset = reference.file_range.range.start(); | 80 | let offset = file_range.range.start(); |
81 | if let Some(path) = | 81 | if let Some(path) = |
82 | self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset) | 82 | self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset) |
83 | { | 83 | { |
@@ -108,7 +108,7 @@ impl<'db> MatchFinder<'db> { | |||
108 | &self, | 108 | &self, |
109 | usage_cache: &'a mut UsageCache, | 109 | usage_cache: &'a mut UsageCache, |
110 | definition: Definition, | 110 | definition: Definition, |
111 | ) -> &'a [Reference] { | 111 | ) -> &'a UsageSearchResult { |
112 | // Logically if a lookup succeeds we should just return it. Unfortunately returning it would | 112 | // Logically if a lookup succeeds we should just return it. Unfortunately returning it would |
113 | // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a | 113 | // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a |
114 | // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two | 114 | // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two |
@@ -250,7 +250,7 @@ fn is_search_permitted(node: &SyntaxNode) -> bool { | |||
250 | } | 250 | } |
251 | 251 | ||
252 | impl UsageCache { | 252 | impl UsageCache { |
253 | fn find(&mut self, definition: &Definition) -> Option<&[Reference]> { | 253 | fn find(&mut self, definition: &Definition) -> Option<&UsageSearchResult> { |
254 | // We expect a very small number of cache entries (generally 1), so a linear scan should be | 254 | // We expect a very small number of cache entries (generally 1), so a linear scan should be |
255 | // fast enough and avoids the need to implement Hash for Definition. | 255 | // fast enough and avoids the need to implement Hash for Definition. |
256 | for (d, refs) in &self.usages { | 256 | for (d, refs) in &self.usages { |
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs index 63131f6ca..d6918c22d 100644 --- a/crates/ssr/src/tests.rs +++ b/crates/ssr/src/tests.rs | |||
@@ -59,7 +59,7 @@ fn parser_undefined_placeholder_in_replacement() { | |||
59 | ); | 59 | ); |
60 | } | 60 | } |
61 | 61 | ||
62 | /// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be | 62 | /// `code` may optionally contain a cursor marker `$0`. If it doesn't, then the position will be |
63 | /// the start of the file. If there's a second cursor marker, then we'll return a single range. | 63 | /// the start of the file. If there's a second cursor marker, then we'll return a single range. |
64 | pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) { | 64 | pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) { |
65 | use ide_db::base_db::fixture::WithFixture; | 65 | use ide_db::base_db::fixture::WithFixture; |
@@ -160,6 +160,97 @@ fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expecte | |||
160 | } | 160 | } |
161 | 161 | ||
162 | #[test] | 162 | #[test] |
163 | fn ssr_let_stmt_in_macro_match() { | ||
164 | assert_matches( | ||
165 | "let a = 0", | ||
166 | r#" | ||
167 | macro_rules! m1 { ($a:stmt) => {$a}; } | ||
168 | fn f() {m1!{ let a = 0 };}"#, | ||
169 | // FIXME: Whitespace is not part of the matched block | ||
170 | &["leta=0"], | ||
171 | ); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn ssr_let_stmt_in_fn_match() { | ||
176 | assert_matches("let $a = 10;", "fn main() { let x = 10; x }", &["let x = 10;"]); | ||
177 | assert_matches("let $a = $b;", "fn main() { let x = 10; x }", &["let x = 10;"]); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn ssr_block_expr_match() { | ||
182 | assert_matches("{ let $a = $b; }", "fn main() { let x = 10; }", &["{ let x = 10; }"]); | ||
183 | assert_matches("{ let $a = $b; $c }", "fn main() { let x = 10; x }", &["{ let x = 10; x }"]); | ||
184 | } | ||
185 | |||
186 | #[test] | ||
187 | fn ssr_let_stmt_replace() { | ||
188 | // Pattern and template with trailing semicolon | ||
189 | assert_ssr_transform( | ||
190 | "let $a = $b; ==>> let $a = 11;", | ||
191 | "fn main() { let x = 10; x }", | ||
192 | expect![["fn main() { let x = 11; x }"]], | ||
193 | ); | ||
194 | } | ||
195 | |||
196 | #[test] | ||
197 | fn ssr_let_stmt_replace_expr() { | ||
198 | // Trailing semicolon should be dropped from the new expression | ||
199 | assert_ssr_transform( | ||
200 | "let $a = $b; ==>> $b", | ||
201 | "fn main() { let x = 10; }", | ||
202 | expect![["fn main() { 10 }"]], | ||
203 | ); | ||
204 | } | ||
205 | |||
206 | #[test] | ||
207 | fn ssr_blockexpr_replace_stmt_with_stmt() { | ||
208 | assert_ssr_transform( | ||
209 | "if $a() {$b;} ==>> $b;", | ||
210 | "{ | ||
211 | if foo() { | ||
212 | bar(); | ||
213 | } | ||
214 | Ok(()) | ||
215 | }", | ||
216 | expect![[r#"{ | ||
217 | bar(); | ||
218 | Ok(()) | ||
219 | }"#]], | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn ssr_blockexpr_match_trailing_expr() { | ||
225 | assert_matches( | ||
226 | "if $a() {$b;}", | ||
227 | "{ | ||
228 | if foo() { | ||
229 | bar(); | ||
230 | } | ||
231 | }", | ||
232 | &["if foo() { | ||
233 | bar(); | ||
234 | }"], | ||
235 | ); | ||
236 | } | ||
237 | |||
238 | #[test] | ||
239 | fn ssr_blockexpr_replace_trailing_expr_with_stmt() { | ||
240 | assert_ssr_transform( | ||
241 | "if $a() {$b;} ==>> $b;", | ||
242 | "{ | ||
243 | if foo() { | ||
244 | bar(); | ||
245 | } | ||
246 | }", | ||
247 | expect![["{ | ||
248 | bar(); | ||
249 | }"]], | ||
250 | ); | ||
251 | } | ||
252 | |||
253 | #[test] | ||
163 | fn ssr_function_to_method() { | 254 | fn ssr_function_to_method() { |
164 | assert_ssr_transform( | 255 | assert_ssr_transform( |
165 | "my_function($a, $b) ==>> ($a).my_method($b)", | 256 | "my_function($a, $b) ==>> ($a).my_method($b)", |
@@ -505,7 +596,7 @@ fn replace_function_call() { | |||
505 | // This test also makes sure that we ignore empty-ranges. | 596 | // This test also makes sure that we ignore empty-ranges. |
506 | assert_ssr_transform( | 597 | assert_ssr_transform( |
507 | "foo() ==>> bar()", | 598 | "foo() ==>> bar()", |
508 | "fn foo() {<|><|>} fn bar() {} fn f1() {foo(); foo();}", | 599 | "fn foo() {$0$0} fn bar() {} fn f1() {foo(); foo();}", |
509 | expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], | 600 | expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], |
510 | ); | 601 | ); |
511 | } | 602 | } |
@@ -615,7 +706,7 @@ fn replace_associated_trait_constant() { | |||
615 | 706 | ||
616 | #[test] | 707 | #[test] |
617 | fn replace_path_in_different_contexts() { | 708 | fn replace_path_in_different_contexts() { |
618 | // Note the <|> inside module a::b which marks the point where the rule is interpreted. We | 709 | // Note the $0 inside module a::b which marks the point where the rule is interpreted. We |
619 | // replace foo with bar, but both need different path qualifiers in different contexts. In f4, | 710 | // replace foo with bar, but both need different path qualifiers in different contexts. In f4, |
620 | // foo is unqualified because of a use statement, however the replacement needs to be fully | 711 | // foo is unqualified because of a use statement, however the replacement needs to be fully |
621 | // qualified. | 712 | // qualified. |
@@ -623,7 +714,7 @@ fn replace_path_in_different_contexts() { | |||
623 | "c::foo() ==>> c::bar()", | 714 | "c::foo() ==>> c::bar()", |
624 | r#" | 715 | r#" |
625 | mod a { | 716 | mod a { |
626 | pub mod b {<|> | 717 | pub mod b {$0 |
627 | pub mod c { | 718 | pub mod c { |
628 | pub fn foo() {} | 719 | pub fn foo() {} |
629 | pub fn bar() {} | 720 | pub fn bar() {} |
@@ -1005,7 +1096,7 @@ fn pattern_is_a_single_segment_path() { | |||
1005 | fn f1() -> i32 { | 1096 | fn f1() -> i32 { |
1006 | let foo = 1; | 1097 | let foo = 1; |
1007 | let bar = 2; | 1098 | let bar = 2; |
1008 | foo<|> | 1099 | foo$0 |
1009 | } | 1100 | } |
1010 | "#, | 1101 | "#, |
1011 | expect![[r#" | 1102 | expect![[r#" |
@@ -1037,7 +1128,7 @@ fn replace_local_variable_reference() { | |||
1037 | let foo = 5; | 1128 | let foo = 5; |
1038 | res += foo + 1; | 1129 | res += foo + 1; |
1039 | let foo = 10; | 1130 | let foo = 10; |
1040 | res += foo + 2;<|> | 1131 | res += foo + 2;$0 |
1041 | res += foo + 3; | 1132 | res += foo + 3; |
1042 | let foo = 15; | 1133 | let foo = 15; |
1043 | res += foo + 4; | 1134 | res += foo + 4; |
@@ -1069,9 +1160,9 @@ fn replace_path_within_selection() { | |||
1069 | let foo = 41; | 1160 | let foo = 41; |
1070 | let bar = 42; | 1161 | let bar = 42; |
1071 | do_stuff(foo); | 1162 | do_stuff(foo); |
1072 | do_stuff(foo);<|> | 1163 | do_stuff(foo);$0 |
1073 | do_stuff(foo); | 1164 | do_stuff(foo); |
1074 | do_stuff(foo);<|> | 1165 | do_stuff(foo);$0 |
1075 | do_stuff(foo); | 1166 | do_stuff(foo); |
1076 | }"#, | 1167 | }"#, |
1077 | expect![[r#" | 1168 | expect![[r#" |
@@ -1094,9 +1185,9 @@ fn replace_nonpath_within_selection() { | |||
1094 | "$a + $b ==>> $b * $a", | 1185 | "$a + $b ==>> $b * $a", |
1095 | r#" | 1186 | r#" |
1096 | fn main() { | 1187 | fn main() { |
1097 | let v = 1 + 2;<|> | 1188 | let v = 1 + 2;$0 |
1098 | let v2 = 3 + 3; | 1189 | let v2 = 3 + 3; |
1099 | let v3 = 4 + 5;<|> | 1190 | let v3 = 4 + 5;$0 |
1100 | let v4 = 6 + 7; | 1191 | let v4 = 6 + 7; |
1101 | }"#, | 1192 | }"#, |
1102 | expect![[r#" | 1193 | expect![[r#" |
@@ -1121,7 +1212,7 @@ fn replace_self() { | |||
1121 | fn bar(_: &S1) {} | 1212 | fn bar(_: &S1) {} |
1122 | impl S1 { | 1213 | impl S1 { |
1123 | fn f1(&self) { | 1214 | fn f1(&self) { |
1124 | foo(self)<|> | 1215 | foo(self)$0 |
1125 | } | 1216 | } |
1126 | fn f2(&self) { | 1217 | fn f2(&self) { |
1127 | foo(self) | 1218 | foo(self) |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 374ed5910..13aab1451 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! Missing batteries for standard libraries. | 1 | //! Missing batteries for standard libraries. |
2 | use std::time::Instant; | 2 | use std::{cmp::Ordering, ops, process, time::Instant}; |
3 | 3 | ||
4 | mod macros; | 4 | mod macros; |
5 | pub mod panic_context; | 5 | pub mod panic_context; |
@@ -117,7 +117,12 @@ impl<'a> Iterator for LinesWithEnds<'a> { | |||
117 | } | 117 | } |
118 | } | 118 | } |
119 | 119 | ||
120 | // https://github.com/rust-lang/rust/issues/73831 | 120 | /// Returns `idx` such that: |
121 | /// | ||
122 | /// ∀ x in slice[..idx]: pred(x) | ||
123 | /// && ∀ x in slice[idx..]: !pred(x) | ||
124 | /// | ||
125 | /// https://github.com/rust-lang/rust/issues/73831 | ||
121 | pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize | 126 | pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize |
122 | where | 127 | where |
123 | P: FnMut(&T) -> bool, | 128 | P: FnMut(&T) -> bool, |
@@ -147,6 +152,36 @@ where | |||
147 | left | 152 | left |
148 | } | 153 | } |
149 | 154 | ||
155 | pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize> | ||
156 | where | ||
157 | F: FnMut(&T) -> Ordering, | ||
158 | { | ||
159 | let start = partition_point(slice, |it| key(it) == Ordering::Less); | ||
160 | let len = partition_point(&slice[start..], |it| key(it) == Ordering::Equal); | ||
161 | start..start + len | ||
162 | } | ||
163 | |||
164 | pub struct JodChild(pub process::Child); | ||
165 | |||
166 | impl ops::Deref for JodChild { | ||
167 | type Target = process::Child; | ||
168 | fn deref(&self) -> &process::Child { | ||
169 | &self.0 | ||
170 | } | ||
171 | } | ||
172 | |||
173 | impl ops::DerefMut for JodChild { | ||
174 | fn deref_mut(&mut self) -> &mut process::Child { | ||
175 | &mut self.0 | ||
176 | } | ||
177 | } | ||
178 | |||
179 | impl Drop for JodChild { | ||
180 | fn drop(&mut self) { | ||
181 | let _ = self.0.kill(); | ||
182 | } | ||
183 | } | ||
184 | |||
150 | #[cfg(test)] | 185 | #[cfg(test)] |
151 | mod tests { | 186 | mod tests { |
152 | use super::*; | 187 | use super::*; |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 21015591c..cfeaed9e6 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -11,9 +11,9 @@ edition = "2018" | |||
11 | doctest = false | 11 | doctest = false |
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
@@ -33,4 +33,4 @@ profile = { path = "../profile", version = "0.0.0" } | |||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | walkdir = "2.3.1" | 34 | walkdir = "2.3.1" |
35 | rayon = "1" | 35 | rayon = "1" |
36 | expect-test = "1.0" | 36 | expect-test = "1.1" |
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 5696c014f..384d031e7 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | 19 | ||
20 | /// Returns ancestors of the node at the offset, sorted by length. This should | 20 | /// Returns ancestors of the node at the offset, sorted by length. This should |
21 | /// do the right thing at an edge, e.g. when searching for expressions at `{ | 21 | /// do the right thing at an edge, e.g. when searching for expressions at `{ |
22 | /// <|>foo }` we will get the name reference instead of the whole block, which | 22 | /// $0foo }` we will get the name reference instead of the whole block, which |
23 | /// we would get if we just did `find_token_at_offset(...).flat_map(|t| | 23 | /// we would get if we just did `find_token_at_offset(...).flat_map(|t| |
24 | /// t.parent().ancestors())`. | 24 | /// t.parent().ancestors())`. |
25 | pub fn ancestors_at_offset( | 25 | pub fn ancestors_at_offset( |
@@ -88,8 +88,8 @@ pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNod | |||
88 | let keep = u_depth.min(v_depth); | 88 | let keep = u_depth.min(v_depth); |
89 | 89 | ||
90 | let u_candidates = u.ancestors().skip(u_depth - keep); | 90 | let u_candidates = u.ancestors().skip(u_depth - keep); |
91 | let v_canidates = v.ancestors().skip(v_depth - keep); | 91 | let v_candidates = v.ancestors().skip(v_depth - keep); |
92 | let (res, _) = u_candidates.zip(v_canidates).find(|(x, y)| x == y)?; | 92 | let (res, _) = u_candidates.zip(v_candidates).find(|(x, y)| x == y)?; |
93 | Some(res) | 93 | Some(res) |
94 | } | 94 | } |
95 | 95 | ||
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 77233ab31..824ebf41c 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -220,7 +220,7 @@ impl ast::RecordExprFieldList { | |||
220 | InsertPosition::After($anchor.syntax().clone().into()) | 220 | InsertPosition::After($anchor.syntax().clone().into()) |
221 | } | 221 | } |
222 | }; | 222 | }; |
223 | }; | 223 | } |
224 | 224 | ||
225 | let position = match position { | 225 | let position = match position { |
226 | InsertPosition::First => after_l_curly!(), | 226 | InsertPosition::First => after_l_curly!(), |
@@ -533,7 +533,7 @@ impl ast::GenericParamList { | |||
533 | InsertPosition::After($anchor.syntax().clone().into()) | 533 | InsertPosition::After($anchor.syntax().clone().into()) |
534 | } | 534 | } |
535 | }; | 535 | }; |
536 | }; | 536 | } |
537 | 537 | ||
538 | let position = match self.generic_params().last() { | 538 | let position = match self.generic_params().last() { |
539 | Some(it) => after_field!(it), | 539 | Some(it) => after_field!(it), |
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index c5b80bffe..92ed2ee9d 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs | |||
@@ -484,7 +484,7 @@ impl ast::AttrsOwner for BlockExpr {} | |||
484 | impl BlockExpr { | 484 | impl BlockExpr { |
485 | pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } | 485 | pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } |
486 | pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) } | 486 | pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) } |
487 | pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } | 487 | pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) } |
488 | pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } | 488 | pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } |
489 | } | 489 | } |
490 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 490 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index cafa4c198..1ed8a96e5 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -241,7 +241,7 @@ pub fn wildcard_pat() -> ast::WildcardPat { | |||
241 | } | 241 | } |
242 | } | 242 | } |
243 | 243 | ||
244 | /// Creates a tuple of patterns from an interator of patterns. | 244 | /// Creates a tuple of patterns from an iterator of patterns. |
245 | /// | 245 | /// |
246 | /// Invariant: `pats` must be length > 1 | 246 | /// Invariant: `pats` must be length > 1 |
247 | /// | 247 | /// |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 2aa472fb4..27381ba80 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -133,7 +133,7 @@ impl ast::Attr { | |||
133 | first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind); | 133 | first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind); |
134 | 134 | ||
135 | match (first_token_kind, second_token_kind) { | 135 | match (first_token_kind, second_token_kind) { |
136 | (Some(SyntaxKind::POUND), Some(T![!])) => AttrKind::Inner, | 136 | (Some(T![#]), Some(T![!])) => AttrKind::Inner, |
137 | _ => AttrKind::Outer, | 137 | _ => AttrKind::Outer, |
138 | } | 138 | } |
139 | } | 139 | } |
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 4d272f367..ea7482bb1 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs | |||
@@ -212,6 +212,13 @@ impl ast::Attr { | |||
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | impl ast::Stmt { | ||
216 | /// Returns `text`, parsed as statement, but only if it has no errors. | ||
217 | pub fn parse(text: &str) -> Result<Self, ()> { | ||
218 | parsing::parse_text_fragment(text, parser::FragmentKind::StatementOptionalSemi) | ||
219 | } | ||
220 | } | ||
221 | |||
215 | /// Matches a `SyntaxNode` against an `ast` type. | 222 | /// Matches a `SyntaxNode` against an `ast` type. |
216 | /// | 223 | /// |
217 | /// # Example: | 224 | /// # Example: |
@@ -283,7 +290,7 @@ fn api_walkthrough() { | |||
283 | 290 | ||
284 | // Let's get the `1 + 1` expression! | 291 | // Let's get the `1 + 1` expression! |
285 | let body: ast::BlockExpr = func.body().unwrap(); | 292 | let body: ast::BlockExpr = func.body().unwrap(); |
286 | let expr: ast::Expr = body.expr().unwrap(); | 293 | let expr: ast::Expr = body.tail_expr().unwrap(); |
287 | 294 | ||
288 | // Enums are used to group related ast nodes together, and can be used for | 295 | // Enums are used to group related ast nodes together, and can be used for |
289 | // matching. However, because there are no public fields, it's possible to | 296 | // matching. However, because there are no public fields, it's possible to |
diff --git a/crates/syntax/src/parsing/lexer.rs b/crates/syntax/src/parsing/lexer.rs index 0cbba73c5..7c8d0a4c4 100644 --- a/crates/syntax/src/parsing/lexer.rs +++ b/crates/syntax/src/parsing/lexer.rs | |||
@@ -24,7 +24,7 @@ pub struct Token { | |||
24 | /// Beware that it checks for shebang first and its length contributes to resulting | 24 | /// Beware that it checks for shebang first and its length contributes to resulting |
25 | /// tokens offsets. | 25 | /// tokens offsets. |
26 | pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) { | 26 | pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) { |
27 | // non-empty string is a precondtion of `rustc_lexer::strip_shebang()`. | 27 | // non-empty string is a precondition of `rustc_lexer::strip_shebang()`. |
28 | if text.is_empty() { | 28 | if text.is_empty() { |
29 | return Default::default(); | 29 | return Default::default(); |
30 | } | 30 | } |
@@ -76,7 +76,7 @@ pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxEr | |||
76 | } | 76 | } |
77 | 77 | ||
78 | /// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and | 78 | /// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and |
79 | /// returns `None` if any tokenization error occured. | 79 | /// returns `None` if any tokenization error occurred. |
80 | /// | 80 | /// |
81 | /// Beware that unescape errors are not checked at tokenization time. | 81 | /// Beware that unescape errors are not checked at tokenization time. |
82 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { | 82 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { |
@@ -96,7 +96,7 @@ pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { | |||
96 | /// | 96 | /// |
97 | /// Beware that unescape errors are not checked at tokenization time. | 97 | /// Beware that unescape errors are not checked at tokenization time. |
98 | fn lex_first_token(text: &str) -> Option<(Token, Option<SyntaxError>)> { | 98 | fn lex_first_token(text: &str) -> Option<(Token, Option<SyntaxError>)> { |
99 | // non-empty string is a precondtion of `rustc_lexer::first_token()`. | 99 | // non-empty string is a precondition of `rustc_lexer::first_token()`. |
100 | if text.is_empty() { | 100 | if text.is_empty() { |
101 | return None; | 101 | return None; |
102 | } | 102 | } |
@@ -117,7 +117,7 @@ fn rustc_token_kind_to_syntax_kind( | |||
117 | token_text: &str, | 117 | token_text: &str, |
118 | ) -> (SyntaxKind, Option<&'static str>) { | 118 | ) -> (SyntaxKind, Option<&'static str>) { |
119 | // A note on an intended tradeoff: | 119 | // A note on an intended tradeoff: |
120 | // We drop some useful infromation here (see patterns with double dots `..`) | 120 | // We drop some useful information here (see patterns with double dots `..`) |
121 | // Storing that info in `SyntaxKind` is not possible due to its layout requirements of | 121 | // Storing that info in `SyntaxKind` is not possible due to its layout requirements of |
122 | // being `u16` that come from `rowan::SyntaxKind`. | 122 | // being `u16` that come from `rowan::SyntaxKind`. |
123 | 123 | ||
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs index 190f5f67a..78eaf3410 100644 --- a/crates/syntax/src/parsing/reparsing.rs +++ b/crates/syntax/src/parsing/reparsing.rs | |||
@@ -223,7 +223,7 @@ mod tests { | |||
223 | do_check( | 223 | do_check( |
224 | r" | 224 | r" |
225 | fn foo() { | 225 | fn foo() { |
226 | let x = foo + <|>bar<|> | 226 | let x = foo + $0bar$0 |
227 | } | 227 | } |
228 | ", | 228 | ", |
229 | "baz", | 229 | "baz", |
@@ -232,7 +232,7 @@ fn foo() { | |||
232 | do_check( | 232 | do_check( |
233 | r" | 233 | r" |
234 | fn foo() { | 234 | fn foo() { |
235 | let x = foo<|> + bar<|> | 235 | let x = foo$0 + bar$0 |
236 | } | 236 | } |
237 | ", | 237 | ", |
238 | "baz", | 238 | "baz", |
@@ -241,7 +241,7 @@ fn foo() { | |||
241 | do_check( | 241 | do_check( |
242 | r" | 242 | r" |
243 | struct Foo { | 243 | struct Foo { |
244 | f: foo<|><|> | 244 | f: foo$0$0 |
245 | } | 245 | } |
246 | ", | 246 | ", |
247 | ",\n g: (),", | 247 | ",\n g: (),", |
@@ -252,7 +252,7 @@ struct Foo { | |||
252 | fn foo { | 252 | fn foo { |
253 | let; | 253 | let; |
254 | 1 + 1; | 254 | 1 + 1; |
255 | <|>92<|>; | 255 | $092$0; |
256 | } | 256 | } |
257 | ", | 257 | ", |
258 | "62", | 258 | "62", |
@@ -261,7 +261,7 @@ fn foo { | |||
261 | do_check( | 261 | do_check( |
262 | r" | 262 | r" |
263 | mod foo { | 263 | mod foo { |
264 | fn <|><|> | 264 | fn $0$0 |
265 | } | 265 | } |
266 | ", | 266 | ", |
267 | "bar", | 267 | "bar", |
@@ -271,7 +271,7 @@ mod foo { | |||
271 | do_check( | 271 | do_check( |
272 | r" | 272 | r" |
273 | trait Foo { | 273 | trait Foo { |
274 | type <|>Foo<|>; | 274 | type $0Foo$0; |
275 | } | 275 | } |
276 | ", | 276 | ", |
277 | "Output", | 277 | "Output", |
@@ -280,17 +280,17 @@ trait Foo { | |||
280 | do_check( | 280 | do_check( |
281 | r" | 281 | r" |
282 | impl IntoIterator<Item=i32> for Foo { | 282 | impl IntoIterator<Item=i32> for Foo { |
283 | f<|><|> | 283 | f$0$0 |
284 | } | 284 | } |
285 | ", | 285 | ", |
286 | "n next(", | 286 | "n next(", |
287 | 9, | 287 | 9, |
288 | ); | 288 | ); |
289 | do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10); | 289 | do_check(r"use a::b::{foo,$0,bar$0};", "baz", 10); |
290 | do_check( | 290 | do_check( |
291 | r" | 291 | r" |
292 | pub enum A { | 292 | pub enum A { |
293 | Foo<|><|> | 293 | Foo$0$0 |
294 | } | 294 | } |
295 | ", | 295 | ", |
296 | "\nBar;\n", | 296 | "\nBar;\n", |
@@ -298,7 +298,7 @@ pub enum A { | |||
298 | ); | 298 | ); |
299 | do_check( | 299 | do_check( |
300 | r" | 300 | r" |
301 | foo!{a, b<|><|> d} | 301 | foo!{a, b$0$0 d} |
302 | ", | 302 | ", |
303 | ", c[3]", | 303 | ", c[3]", |
304 | 8, | 304 | 8, |
@@ -306,7 +306,7 @@ foo!{a, b<|><|> d} | |||
306 | do_check( | 306 | do_check( |
307 | r" | 307 | r" |
308 | fn foo() { | 308 | fn foo() { |
309 | vec![<|><|>] | 309 | vec![$0$0] |
310 | } | 310 | } |
311 | ", | 311 | ", |
312 | "123", | 312 | "123", |
@@ -315,7 +315,7 @@ fn foo() { | |||
315 | do_check( | 315 | do_check( |
316 | r" | 316 | r" |
317 | extern { | 317 | extern { |
318 | fn<|>;<|> | 318 | fn$0;$0 |
319 | } | 319 | } |
320 | ", | 320 | ", |
321 | " exit(code: c_int)", | 321 | " exit(code: c_int)", |
@@ -326,7 +326,7 @@ extern { | |||
326 | #[test] | 326 | #[test] |
327 | fn reparse_token_tests() { | 327 | fn reparse_token_tests() { |
328 | do_check( | 328 | do_check( |
329 | r"<|><|> | 329 | r"$0$0 |
330 | fn foo() -> i32 { 1 } | 330 | fn foo() -> i32 { 1 } |
331 | ", | 331 | ", |
332 | "\n\n\n \n", | 332 | "\n\n\n \n", |
@@ -334,49 +334,49 @@ fn foo() -> i32 { 1 } | |||
334 | ); | 334 | ); |
335 | do_check( | 335 | do_check( |
336 | r" | 336 | r" |
337 | fn foo() -> <|><|> {} | 337 | fn foo() -> $0$0 {} |
338 | ", | 338 | ", |
339 | " \n", | 339 | " \n", |
340 | 2, | 340 | 2, |
341 | ); | 341 | ); |
342 | do_check( | 342 | do_check( |
343 | r" | 343 | r" |
344 | fn <|>foo<|>() -> i32 { 1 } | 344 | fn $0foo$0() -> i32 { 1 } |
345 | ", | 345 | ", |
346 | "bar", | 346 | "bar", |
347 | 3, | 347 | 3, |
348 | ); | 348 | ); |
349 | do_check( | 349 | do_check( |
350 | r" | 350 | r" |
351 | fn foo<|><|>foo() { } | 351 | fn foo$0$0foo() { } |
352 | ", | 352 | ", |
353 | "bar", | 353 | "bar", |
354 | 6, | 354 | 6, |
355 | ); | 355 | ); |
356 | do_check( | 356 | do_check( |
357 | r" | 357 | r" |
358 | fn foo /* <|><|> */ () {} | 358 | fn foo /* $0$0 */ () {} |
359 | ", | 359 | ", |
360 | "some comment", | 360 | "some comment", |
361 | 6, | 361 | 6, |
362 | ); | 362 | ); |
363 | do_check( | 363 | do_check( |
364 | r" | 364 | r" |
365 | fn baz <|><|> () {} | 365 | fn baz $0$0 () {} |
366 | ", | 366 | ", |
367 | " \t\t\n\n", | 367 | " \t\t\n\n", |
368 | 2, | 368 | 2, |
369 | ); | 369 | ); |
370 | do_check( | 370 | do_check( |
371 | r" | 371 | r" |
372 | fn baz <|><|> () {} | 372 | fn baz $0$0 () {} |
373 | ", | 373 | ", |
374 | " \t\t\n\n", | 374 | " \t\t\n\n", |
375 | 2, | 375 | 2, |
376 | ); | 376 | ); |
377 | do_check( | 377 | do_check( |
378 | r" | 378 | r" |
379 | /// foo <|><|>omment | 379 | /// foo $0$0omment |
380 | mod { } | 380 | mod { } |
381 | ", | 381 | ", |
382 | "c", | 382 | "c", |
@@ -384,28 +384,28 @@ mod { } | |||
384 | ); | 384 | ); |
385 | do_check( | 385 | do_check( |
386 | r#" | 386 | r#" |
387 | fn -> &str { "Hello<|><|>" } | 387 | fn -> &str { "Hello$0$0" } |
388 | "#, | 388 | "#, |
389 | ", world", | 389 | ", world", |
390 | 7, | 390 | 7, |
391 | ); | 391 | ); |
392 | do_check( | 392 | do_check( |
393 | r#" | 393 | r#" |
394 | fn -> &str { // "Hello<|><|>" | 394 | fn -> &str { // "Hello$0$0" |
395 | "#, | 395 | "#, |
396 | ", world", | 396 | ", world", |
397 | 10, | 397 | 10, |
398 | ); | 398 | ); |
399 | do_check( | 399 | do_check( |
400 | r##" | 400 | r##" |
401 | fn -> &str { r#"Hello<|><|>"# | 401 | fn -> &str { r#"Hello$0$0"# |
402 | "##, | 402 | "##, |
403 | ", world", | 403 | ", world", |
404 | 10, | 404 | 10, |
405 | ); | 405 | ); |
406 | do_check( | 406 | do_check( |
407 | r" | 407 | r" |
408 | #[derive(<|>Copy<|>)] | 408 | #[derive($0Copy$0)] |
409 | enum Foo { | 409 | enum Foo { |
410 | 410 | ||
411 | } | 411 | } |
@@ -417,12 +417,12 @@ enum Foo { | |||
417 | 417 | ||
418 | #[test] | 418 | #[test] |
419 | fn reparse_str_token_with_error_unchanged() { | 419 | fn reparse_str_token_with_error_unchanged() { |
420 | do_check(r#""<|>Unclosed<|> string literal"#, "Still unclosed", 24); | 420 | do_check(r#""$0Unclosed$0 string literal"#, "Still unclosed", 24); |
421 | } | 421 | } |
422 | 422 | ||
423 | #[test] | 423 | #[test] |
424 | fn reparse_str_token_with_error_fixed() { | 424 | fn reparse_str_token_with_error_fixed() { |
425 | do_check(r#""unterinated<|><|>"#, "\"", 12); | 425 | do_check(r#""unterinated$0$0"#, "\"", 12); |
426 | } | 426 | } |
427 | 427 | ||
428 | #[test] | 428 | #[test] |
@@ -430,7 +430,7 @@ enum Foo { | |||
430 | do_check( | 430 | do_check( |
431 | r#"fn main() { | 431 | r#"fn main() { |
432 | if {} | 432 | if {} |
433 | 32 + 4<|><|> | 433 | 32 + 4$0$0 |
434 | return | 434 | return |
435 | if {} | 435 | if {} |
436 | }"#, | 436 | }"#, |
@@ -444,7 +444,7 @@ enum Foo { | |||
444 | do_check( | 444 | do_check( |
445 | r#"fn main() { | 445 | r#"fn main() { |
446 | if {} | 446 | if {} |
447 | 32 + 4<|><|> | 447 | 32 + 4$0$0 |
448 | return | 448 | return |
449 | if {} | 449 | if {} |
450 | }"#, | 450 | }"#, |
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs index 8c217dfe0..9d3433c9d 100644 --- a/crates/syntax/src/tests.rs +++ b/crates/syntax/src/tests.rs | |||
@@ -103,6 +103,15 @@ fn type_parser_tests() { | |||
103 | } | 103 | } |
104 | 104 | ||
105 | #[test] | 105 | #[test] |
106 | fn stmt_parser_tests() { | ||
107 | fragment_parser_dir_test( | ||
108 | &["parser/fragments/stmt/ok"], | ||
109 | &["parser/fragments/stmt/err"], | ||
110 | crate::ast::Stmt::parse, | ||
111 | ); | ||
112 | } | ||
113 | |||
114 | #[test] | ||
106 | fn parser_fuzz_tests() { | 115 | fn parser_fuzz_tests() { |
107 | for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { | 116 | for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { |
108 | fuzz::check_parser(&text) | 117 | fuzz::check_parser(&text) |
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 2ddaeb176..bfa2dc4ba 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs | |||
@@ -173,7 +173,7 @@ pub(crate) fn validate_block_structure(root: &SyntaxNode) { | |||
173 | assert_eq!( | 173 | assert_eq!( |
174 | node.parent(), | 174 | node.parent(), |
175 | pair.parent(), | 175 | pair.parent(), |
176 | "\nunpaired curleys:\n{}\n{:#?}\n", | 176 | "\nunpaired curlys:\n{}\n{:#?}\n", |
177 | root.text(), | 177 | root.text(), |
178 | root, | 178 | root, |
179 | ); | 179 | ); |
@@ -344,9 +344,9 @@ fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> { | |||
344 | 344 | ||
345 | if tbl.bounds().count() > 1 { | 345 | if tbl.bounds().count() > 1 { |
346 | let dyn_token = ty.dyn_token()?; | 346 | let dyn_token = ty.dyn_token()?; |
347 | let potential_parentheses = | 347 | let potential_parenthesis = |
348 | algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; | 348 | algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; |
349 | let kind = potential_parentheses.kind(); | 349 | let kind = potential_parenthesis.kind(); |
350 | if !matches!(kind, T!['('] | T![<] | T![=]) { | 350 | if !matches!(kind, T!['('] | T![<] | T![=]) { |
351 | return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); | 351 | return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); |
352 | } | 352 | } |
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs new file mode 100644 index 000000000..988df0705 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs | |||
@@ -0,0 +1 @@ | |||
#[foo] | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs new file mode 100644 index 000000000..7e3b2fd49 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs | |||
@@ -0,0 +1 @@ | |||
a(); b(); c() | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs new file mode 100644 index 000000000..2d06f3766 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs | |||
@@ -0,0 +1 @@ | |||
( | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs new file mode 100644 index 000000000..092bc2b04 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs | |||
@@ -0,0 +1 @@ | |||
; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast new file mode 100644 index 000000000..5df7507e2 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast | |||
@@ -0,0 +1 @@ | |||
ERROR | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs new file mode 100644 index 000000000..ca49acb07 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs | |||
@@ -0,0 +1 @@ | |||
1 + | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast new file mode 100644 index 000000000..274fdf16d --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast | |||
@@ -0,0 +1,9 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] "1" | ||
5 | [email protected] " " | ||
6 | [email protected] "+" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "1" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs new file mode 100644 index 000000000..8d2f0971e --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs | |||
@@ -0,0 +1 @@ | |||
1 + 1 | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast new file mode 100644 index 000000000..6c946091f --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast | |||
@@ -0,0 +1,69 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "{" | ||
4 | [email protected] "\n " | ||
5 | [email protected] | ||
6 | [email protected] "let" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] | ||
10 | [email protected] "x" | ||
11 | [email protected] " " | ||
12 | [email protected] "=" | ||
13 | [email protected] " " | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "foo" | ||
20 | [email protected] | ||
21 | [email protected] "(" | ||
22 | [email protected] ")" | ||
23 | [email protected] ";" | ||
24 | [email protected] "\n " | ||
25 | [email protected] | ||
26 | [email protected] "let" | ||
27 | [email protected] " " | ||
28 | [email protected] | ||
29 | [email protected] | ||
30 | [email protected] "y" | ||
31 | [email protected] " " | ||
32 | [email protected] "=" | ||
33 | [email protected] " " | ||
34 | [email protected] | ||
35 | [email protected] | ||
36 | [email protected] | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] "bar" | ||
40 | [email protected] | ||
41 | [email protected] "(" | ||
42 | [email protected] ")" | ||
43 | [email protected] ";" | ||
44 | [email protected] "\n " | ||
45 | [email protected] | ||
46 | [email protected] | ||
47 | [email protected] | ||
48 | [email protected] | ||
49 | [email protected] | ||
50 | [email protected] "Ok" | ||
51 | [email protected] | ||
52 | [email protected] "(" | ||
53 | [email protected] | ||
54 | [email protected] | ||
55 | [email protected] | ||
56 | [email protected] | ||
57 | [email protected] | ||
58 | [email protected] "x" | ||
59 | [email protected] " " | ||
60 | [email protected] "+" | ||
61 | [email protected] " " | ||
62 | [email protected] | ||
63 | [email protected] | ||
64 | [email protected] | ||
65 | [email protected] | ||
66 | [email protected] "y" | ||
67 | [email protected] ")" | ||
68 | [email protected] "\n" | ||
69 | [email protected] "}" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs new file mode 100644 index 000000000..ffa5c1e66 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | { | ||
2 | let x = foo(); | ||
3 | let y = bar(); | ||
4 | Ok(x + y) | ||
5 | } | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast new file mode 100644 index 000000000..8c186da93 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast | |||
@@ -0,0 +1,11 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] "foo" | ||
8 | [email protected] | ||
9 | [email protected] "(" | ||
10 | [email protected] ")" | ||
11 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs new file mode 100644 index 000000000..a280f9a5c --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs | |||
@@ -0,0 +1 @@ | |||
foo(); | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast new file mode 100644 index 000000000..8ab38da21 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast | |||
@@ -0,0 +1,12 @@ | |||
1 | [email protected] | ||
2 | [email protected] "let" | ||
3 | [email protected] " " | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "x" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] "10" | ||
12 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs new file mode 100644 index 000000000..de8a7f1fc --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
let x = 10; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast new file mode 100644 index 000000000..81d6df29a --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast | |||
@@ -0,0 +1,21 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "m1" | ||
7 | [email protected] "!" | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] " " | ||
11 | [email protected] "let" | ||
12 | [email protected] " " | ||
13 | [email protected] "a" | ||
14 | [email protected] " " | ||
15 | [email protected] "=" | ||
16 | [email protected] " " | ||
17 | [email protected] "0" | ||
18 | [email protected] ";" | ||
19 | [email protected] " " | ||
20 | [email protected] "}" | ||
21 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs new file mode 100644 index 000000000..075f30159 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
m1!{ let a = 0; }; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast new file mode 100644 index 000000000..81d6df29a --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast | |||
@@ -0,0 +1,21 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "m1" | ||
7 | [email protected] "!" | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] " " | ||
11 | [email protected] "let" | ||
12 | [email protected] " " | ||
13 | [email protected] "a" | ||
14 | [email protected] " " | ||
15 | [email protected] "=" | ||
16 | [email protected] " " | ||
17 | [email protected] "0" | ||
18 | [email protected] ";" | ||
19 | [email protected] " " | ||
20 | [email protected] "}" | ||
21 | [email protected] ";" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs new file mode 100644 index 000000000..075f30159 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
m1!{ let a = 0; }; | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast new file mode 100644 index 000000000..64c5d2969 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast | |||
@@ -0,0 +1,22 @@ | |||
1 | [email protected] | ||
2 | [email protected] "struct" | ||
3 | [email protected] " " | ||
4 | [email protected] | ||
5 | [email protected] "Foo" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "{" | ||
9 | [email protected] "\n " | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] "bar" | ||
13 | [email protected] ":" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "u32" | ||
20 | [email protected] "," | ||
21 | [email protected] "\n" | ||
22 | [email protected] "}" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs new file mode 100644 index 000000000..e5473e3ac --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | struct Foo { | ||
2 | bar: u32, | ||
3 | } | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast new file mode 100644 index 000000000..9089906bc --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast | |||
@@ -0,0 +1,10 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] "foo" | ||
8 | [email protected] | ||
9 | [email protected] "(" | ||
10 | [email protected] ")" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs new file mode 100644 index 000000000..eb28ef440 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs | |||
@@ -0,0 +1 @@ | |||
foo() | |||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast new file mode 100644 index 000000000..37663671f --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast | |||
@@ -0,0 +1,11 @@ | |||
1 | [email protected] | ||
2 | [email protected] "let" | ||
3 | [email protected] " " | ||
4 | [email protected] | ||
5 | [email protected] | ||
6 | [email protected] "x" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] "10" | ||
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs new file mode 100644 index 000000000..78364b2a9 --- /dev/null +++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs | |||
@@ -0,0 +1 @@ | |||
let x = 10 | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast index b1fb75ed1..f40500e38 100644 --- a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast +++ b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast | |||
@@ -1,4 +1,4 @@ | |||
1 | [email protected]9 | 1 | [email protected]8 |
2 | [email protected] | 2 | [email protected] |
3 | [email protected] "use" | 3 | [email protected] "use" |
4 | [email protected] " " | 4 | [email protected] " " |
@@ -75,62 +75,62 @@ [email protected] | |||
75 | [email protected] "}" | 75 | [email protected] "}" |
76 | [email protected] ";" | 76 | [email protected] ";" |
77 | [email protected] " " | 77 | [email protected] " " |
78 | [email protected]6 | 78 | [email protected]5 |
79 | [email protected] "// Rust 2015" | 79 | [email protected] "// Rust 2015" |
80 | [email protected] "\n" | 80 | [email protected] "\n" |
81 | [email protected] "use" | 81 | [email protected] "use" |
82 | [email protected] " " | 82 | [email protected] " " |
83 | [email protected]5 | 83 | [email protected]4 |
84 | [email protected] "::" | 84 | [email protected] "::" |
85 | [email protected]5 | 85 | [email protected]4 |
86 | [email protected] "{" | 86 | [email protected] "{" |
87 | [email protected]4 | 87 | [email protected]3 |
88 | [email protected]4 | 88 | [email protected]3 |
89 | [email protected]8 | 89 | [email protected]7 |
90 | [email protected] | 90 | [email protected] |
91 | [email protected] | 91 | [email protected] |
92 | [email protected] | 92 | [email protected] |
93 | [email protected] "some" | 93 | [email protected] "some" |
94 | [email protected] "::" | 94 | [email protected] "::" |
95 | [email protected]8 | 95 | [email protected]7 |
96 | [email protected]8 | 96 | [email protected]7 |
97 | [email protected]8 "arbritrary" | 97 | [email protected]7 "arbitrary" |
98 | COLON2@158..160 "::" | 98 | COLON2@157..159 "::" |
99 | PATH_SEGMENT@160..164 | 99 | PATH_SEGMENT@159..163 |
100 | NAME_REF@160..164 | 100 | NAME_REF@159..163 |
101 | IDENT@160..164 "path" | 101 | IDENT@159..163 "path" |
102 | R_CURLY@164..165 "}" | 102 | R_CURLY@163..164 "}" |
103 | SEMICOLON@165..166 ";" | 103 | SEMICOLON@164..165 ";" |
104 | WHITESPACE@166..167 " " | 104 | WHITESPACE@165..166 " " |
105 | USE@167..205 | 105 | USE@166..204 |
106 | COMMENT@167..179 "// Rust 2015" | 106 | COMMENT@166..178 "// Rust 2015" |
107 | WHITESPACE@179..180 "\n" | 107 | WHITESPACE@178..179 "\n" |
108 | USE_KW@180..183 "use" | 108 | USE_KW@179..182 "use" |
109 | WHITESPACE@183..184 " " | 109 | WHITESPACE@182..183 " " |
110 | USE_TREE@184..204 | 110 | USE_TREE@183..203 |
111 | COLON2@184..186 "::" | 111 | COLON2@183..185 "::" |
112 | USE_TREE_LIST@186..204 | 112 | USE_TREE_LIST@185..203 |
113 | L_CURLY@186..187 "{" | 113 | L_CURLY@185..186 "{" |
114 | USE_TREE@187..203 | 114 | USE_TREE@186..202 |
115 | USE_TREE_LIST@187..203 | 115 | USE_TREE_LIST@186..202 |
116 | L_CURLY@187..188 "{" | 116 | L_CURLY@186..187 "{" |
117 | USE_TREE@188..202 | 117 | USE_TREE@187..201 |
118 | USE_TREE_LIST@188..202 | 118 | USE_TREE_LIST@187..201 |
119 | L_CURLY@188..189 "{" | 119 | L_CURLY@187..188 "{" |
120 | USE_TREE@189..201 | 120 | USE_TREE@188..200 |
121 | PATH@189..201 | 121 | PATH@188..200 |
122 | PATH@189..193 | 122 | PATH@188..192 |
123 | PATH_SEGMENT@189..193 | 123 | PATH_SEGMENT@188..192 |
124 | NAME_REF@189..193 | 124 | NAME_REF@188..192 |
125 | IDENT@189..193 "root" | 125 | IDENT@188..192 "root" |
126 | COLON2@193..195 "::" | 126 | COLON2@192..194 "::" |
127 | PATH_SEGMENT@195..201 | 127 | PATH_SEGMENT@194..200 |
128 | NAME_REF@195..201 | 128 | NAME_REF@194..200 |
129 | IDENT@195..201 "export" | 129 | IDENT@194..200 "export" |
130 | R_CURLY@201..202 "}" | 130 | R_CURLY@200..201 "}" |
131 | R_CURLY@202..203 "}" | 131 | R_CURLY@201..202 "}" |
132 | R_CURLY@203..204 "}" | 132 | R_CURLY@202..203 "}" |
133 | SEMICOLON@204..205 ";" | 133 | SEMICOLON@203..204 ";" |
134 | WHITESPACE@205..206 " " | 134 | WHITESPACE@204..205 " " |
135 | COMMENT@206..248 "// Nonsensical but pe ..." | 135 | COMMENT@205..247 "// Nonsensical but pe ..." |
136 | WHITESPACE@248..249 "\n" | 136 | WHITESPACE@247..248 "\n" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rs b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rs index 381cba1e2..02af4b446 100644 --- a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rs +++ b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) | 1 | use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) |
2 | use {path::from::root}; // Rust 2015 | 2 | use {path::from::root}; // Rust 2015 |
3 | use ::{some::arbritrary::path}; // Rust 2015 | 3 | use ::{some::arbitrary::path}; // Rust 2015 |
4 | use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting | 4 | use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting |
diff --git a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast index 51e881a8e..68c0f1c66 100644 --- a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast +++ b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast | |||
@@ -1,5 +1,5 @@ | |||
1 | SOURCE_FILE@0..46 | 1 | SOURCE_FILE@0..59 |
2 | TYPE_ALIAS@0..45 | 2 | [email protected]8 |
3 | [email protected] "type" | 3 | [email protected] "type" |
4 | [email protected] " " | 4 | [email protected] " " |
5 | [email protected] | 5 | [email protected] |
@@ -7,12 +7,12 @@ [email protected] | |||
7 | [email protected] " " | 7 | [email protected] " " |
8 | [email protected] "=" | 8 | [email protected] "=" |
9 | [email protected] " " | 9 | [email protected] " " |
10 | PATH_TYPE@9..44 | 10 | PATH_TYPE@9..57 |
11 | PATH@9..44 | 11 | PATH@9..57 |
12 | PATH_SEGMENT@9..44 | 12 | PATH_SEGMENT@9..57 |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] "B" | 14 | [email protected] "B" |
15 | GENERIC_ARG_LIST@10..44 | 15 | GENERIC_ARG_LIST@10..57 |
16 | [email protected] "<" | 16 | [email protected] "<" |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] |
@@ -51,6 +51,16 @@ [email protected] | |||
51 | [email protected] | 51 | [email protected] |
52 | [email protected] | 52 | [email protected] |
53 | [email protected] "u64" | 53 | [email protected] "u64" |
54 | [email protected] ">" | 54 | [email protected] "," |
55 | [email protected] ";" | 55 | [email protected] " " |
56 | [email protected] "\n" | 56 | [email protected] |
57 | [email protected] | ||
58 | [email protected] "true" | ||
59 | [email protected] "," | ||
60 | [email protected] " " | ||
61 | [email protected] | ||
62 | [email protected] | ||
63 | [email protected] "false" | ||
64 | [email protected] ">" | ||
65 | [email protected] ";" | ||
66 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs index 0d07d7651..6a8721a73 100644 --- a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs +++ b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rs | |||
@@ -1 +1 @@ | |||
type A = B<'static, i32, 1, { 2 }, Item=u64>; | type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>; | ||
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml index 93eecc678..06341f003 100644 --- a/crates/test_utils/Cargo.toml +++ b/crates/test_utils/Cargo.toml | |||
@@ -11,7 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | # Avoid adding deps here, this crate is widely used in tests it should compile fast! | 13 | # Avoid adding deps here, this crate is widely used in tests it should compile fast! |
14 | difference = "2.0.0" | 14 | dissimilar = "1.0.2" |
15 | text-size = "1.0.0" | 15 | text-size = "1.0.0" |
16 | serde_json = "1.0.48" | 16 | serde_json = "1.0.48" |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 05940a546..e19d2ad61 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | //! Most notable things are: | 3 | //! Most notable things are: |
4 | //! | 4 | //! |
5 | //! * Rich text comparison, which outputs a diff. | 5 | //! * Rich text comparison, which outputs a diff. |
6 | //! * Extracting markup (mainly, `<|>` markers) out of fixture strings. | 6 | //! * Extracting markup (mainly, `$0` markers) out of fixture strings. |
7 | //! * marks (see the eponymous module). | 7 | //! * marks (see the eponymous module). |
8 | 8 | ||
9 | #[macro_use] | 9 | #[macro_use] |
@@ -20,12 +20,13 @@ use serde_json::Value; | |||
20 | use stdx::lines_with_ends; | 20 | use stdx::lines_with_ends; |
21 | use text_size::{TextRange, TextSize}; | 21 | use text_size::{TextRange, TextSize}; |
22 | 22 | ||
23 | pub use difference::Changeset as __Changeset; | 23 | pub use dissimilar::diff as __diff; |
24 | pub use rustc_hash::FxHashMap; | 24 | pub use rustc_hash::FxHashMap; |
25 | 25 | ||
26 | pub use crate::fixture::Fixture; | 26 | pub use crate::fixture::Fixture; |
27 | 27 | ||
28 | pub const CURSOR_MARKER: &str = "<|>"; | 28 | pub const CURSOR_MARKER: &str = "$0"; |
29 | pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; | ||
29 | 30 | ||
30 | /// Asserts that two strings are equal, otherwise displays a rich diff between them. | 31 | /// Asserts that two strings are equal, otherwise displays a rich diff between them. |
31 | /// | 32 | /// |
@@ -45,8 +46,8 @@ macro_rules! assert_eq_text { | |||
45 | if left.trim() == right.trim() { | 46 | if left.trim() == right.trim() { |
46 | std::eprintln!("Left:\n{:?}\n\nRight:\n{:?}\n\nWhitespace difference\n", left, right); | 47 | std::eprintln!("Left:\n{:?}\n\nRight:\n{:?}\n\nWhitespace difference\n", left, right); |
47 | } else { | 48 | } else { |
48 | let changeset = $crate::__Changeset::new(left, right, "\n"); | 49 | let diff = $crate::__diff(left, right); |
49 | std::eprintln!("Left:\n{}\n\nRight:\n{}\n\nDiff:\n{}\n", left, right, changeset); | 50 | std::eprintln!("Left:\n{}\n\nRight:\n{}\n\nDiff:\n{}\n", left, right, $crate::format_diff(diff)); |
50 | } | 51 | } |
51 | std::eprintln!($($tt)*); | 52 | std::eprintln!($($tt)*); |
52 | panic!("text differs"); | 53 | panic!("text differs"); |
@@ -62,7 +63,7 @@ pub fn extract_offset(text: &str) -> (TextSize, String) { | |||
62 | } | 63 | } |
63 | } | 64 | } |
64 | 65 | ||
65 | /// Returns the offset of the first occurence of `<|>` marker and the copy of `text` | 66 | /// Returns the offset of the first occurrence of `$0` marker and the copy of `text` |
66 | /// without the marker. | 67 | /// without the marker. |
67 | fn try_extract_offset(text: &str) -> Option<(TextSize, String)> { | 68 | fn try_extract_offset(text: &str) -> Option<(TextSize, String)> { |
68 | let cursor_pos = text.find(CURSOR_MARKER)?; | 69 | let cursor_pos = text.find(CURSOR_MARKER)?; |
@@ -81,7 +82,7 @@ pub fn extract_range(text: &str) -> (TextRange, String) { | |||
81 | } | 82 | } |
82 | } | 83 | } |
83 | 84 | ||
84 | /// Returns `TextRange` between the first two markers `<|>...<|>` and the copy | 85 | /// Returns `TextRange` between the first two markers `$0...$0` and the copy |
85 | /// of `text` without both of these markers. | 86 | /// of `text` without both of these markers. |
86 | fn try_extract_range(text: &str) -> Option<(TextRange, String)> { | 87 | fn try_extract_range(text: &str) -> Option<(TextRange, String)> { |
87 | let (start, text) = try_extract_offset(text)?; | 88 | let (start, text) = try_extract_offset(text)?; |
@@ -104,11 +105,11 @@ impl From<RangeOrOffset> for TextRange { | |||
104 | } | 105 | } |
105 | } | 106 | } |
106 | 107 | ||
107 | /// Extracts `TextRange` or `TextSize` depending on the amount of `<|>` markers | 108 | /// Extracts `TextRange` or `TextSize` depending on the amount of `$0` markers |
108 | /// found in `text`. | 109 | /// found in `text`. |
109 | /// | 110 | /// |
110 | /// # Panics | 111 | /// # Panics |
111 | /// Panics if no `<|>` marker is present in the `text`. | 112 | /// Panics if no `$0` marker is present in the `text`. |
112 | pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) { | 113 | pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) { |
113 | if let Some((range, text)) = try_extract_range(text) { | 114 | if let Some((range, text)) = try_extract_range(text) { |
114 | return (RangeOrOffset::Range(range), text); | 115 | return (RangeOrOffset::Range(range), text); |
@@ -164,12 +165,12 @@ fn test_extract_tags() { | |||
164 | assert_eq!(actual, vec![("fn main() {}", Some("fn".into())), ("main", None),]); | 165 | assert_eq!(actual, vec![("fn main() {}", Some("fn".into())), ("main", None),]); |
165 | } | 166 | } |
166 | 167 | ||
167 | /// Inserts `<|>` marker into the `text` at `offset`. | 168 | /// Inserts `$0` marker into the `text` at `offset`. |
168 | pub fn add_cursor(text: &str, offset: TextSize) -> String { | 169 | pub fn add_cursor(text: &str, offset: TextSize) -> String { |
169 | let offset: usize = offset.into(); | 170 | let offset: usize = offset.into(); |
170 | let mut res = String::new(); | 171 | let mut res = String::new(); |
171 | res.push_str(&text[..offset]); | 172 | res.push_str(&text[..offset]); |
172 | res.push_str("<|>"); | 173 | res.push_str("$0"); |
173 | res.push_str(&text[offset..]); | 174 | res.push_str(&text[offset..]); |
174 | res | 175 | res |
175 | } | 176 | } |
@@ -392,3 +393,16 @@ pub fn project_dir() -> PathBuf { | |||
392 | let dir = env!("CARGO_MANIFEST_DIR"); | 393 | let dir = env!("CARGO_MANIFEST_DIR"); |
393 | PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned() | 394 | PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned() |
394 | } | 395 | } |
396 | |||
397 | pub fn format_diff(chunks: Vec<dissimilar::Chunk>) -> String { | ||
398 | let mut buf = String::new(); | ||
399 | for chunk in chunks { | ||
400 | let formatted = match chunk { | ||
401 | dissimilar::Chunk::Equal(text) => text.into(), | ||
402 | dissimilar::Chunk::Delete(text) => format!("\x1b[41m{}\x1b[0m", text), | ||
403 | dissimilar::Chunk::Insert(text) => format!("\x1b[42m{}\x1b[0m", text), | ||
404 | }; | ||
405 | buf.push_str(&formatted); | ||
406 | } | ||
407 | buf | ||
408 | } | ||
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs index 02c771f70..3606c887d 100644 --- a/crates/tt/src/buffer.rs +++ b/crates/tt/src/buffer.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use crate::{Subtree, TokenTree}; | 3 | use crate::{Leaf, Subtree, TokenTree}; |
4 | 4 | ||
5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | 5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
6 | struct EntryId(usize); | 6 | struct EntryId(usize); |
@@ -13,7 +13,7 @@ struct EntryPtr(EntryId, usize); | |||
13 | #[derive(Debug)] | 13 | #[derive(Debug)] |
14 | enum Entry<'t> { | 14 | enum Entry<'t> { |
15 | // Mimicking types from proc-macro. | 15 | // Mimicking types from proc-macro. |
16 | Subtree(&'t TokenTree, EntryId), | 16 | Subtree(Option<&'t TokenTree>, &'t Subtree, EntryId), |
17 | Leaf(&'t TokenTree), | 17 | Leaf(&'t TokenTree), |
18 | // End entries contain a pointer to the entry from the containing | 18 | // End entries contain a pointer to the entry from the containing |
19 | // token tree, or None if this is the outermost level. | 19 | // token tree, or None if this is the outermost level. |
@@ -27,37 +27,64 @@ pub struct TokenBuffer<'t> { | |||
27 | buffers: Vec<Box<[Entry<'t>]>>, | 27 | buffers: Vec<Box<[Entry<'t>]>>, |
28 | } | 28 | } |
29 | 29 | ||
30 | impl<'t> TokenBuffer<'t> { | 30 | trait TokenList<'a> { |
31 | pub fn new(tokens: &'t [TokenTree]) -> TokenBuffer<'t> { | 31 | fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>); |
32 | let mut buffers = vec![]; | 32 | } |
33 | |||
34 | let idx = TokenBuffer::new_inner(tokens, &mut buffers, None); | ||
35 | assert_eq!(idx, 0); | ||
36 | |||
37 | TokenBuffer { buffers } | ||
38 | } | ||
39 | 33 | ||
40 | fn new_inner( | 34 | impl<'a> TokenList<'a> for &'a [TokenTree] { |
41 | tokens: &'t [TokenTree], | 35 | fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) { |
42 | buffers: &mut Vec<Box<[Entry<'t>]>>, | ||
43 | next: Option<EntryPtr>, | ||
44 | ) -> usize { | ||
45 | // Must contain everything in tokens and then the Entry::End | 36 | // Must contain everything in tokens and then the Entry::End |
46 | let start_capacity = tokens.len() + 1; | 37 | let start_capacity = self.len() + 1; |
47 | let mut entries = Vec::with_capacity(start_capacity); | 38 | let mut entries = Vec::with_capacity(start_capacity); |
48 | let mut children = vec![]; | 39 | let mut children = vec![]; |
49 | 40 | for (idx, tt) in self.iter().enumerate() { | |
50 | for (idx, tt) in tokens.iter().enumerate() { | ||
51 | match tt { | 41 | match tt { |
52 | TokenTree::Leaf(_) => { | 42 | TokenTree::Leaf(_) => { |
53 | entries.push(Entry::Leaf(tt)); | 43 | entries.push(Entry::Leaf(tt)); |
54 | } | 44 | } |
55 | TokenTree::Subtree(subtree) => { | 45 | TokenTree::Subtree(subtree) => { |
56 | entries.push(Entry::End(None)); | 46 | entries.push(Entry::End(None)); |
57 | children.push((idx, (subtree, tt))); | 47 | children.push((idx, (subtree, Some(tt)))); |
58 | } | 48 | } |
59 | } | 49 | } |
60 | } | 50 | } |
51 | (children, entries) | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl<'a> TokenList<'a> for &'a Subtree { | ||
56 | fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) { | ||
57 | // Must contain everything in tokens and then the Entry::End | ||
58 | let mut entries = vec![]; | ||
59 | let mut children = vec![]; | ||
60 | entries.push(Entry::End(None)); | ||
61 | children.push((0usize, (*self, None))); | ||
62 | (children, entries) | ||
63 | } | ||
64 | } | ||
65 | |||
66 | impl<'t> TokenBuffer<'t> { | ||
67 | pub fn from_tokens(tokens: &'t [TokenTree]) -> TokenBuffer<'t> { | ||
68 | Self::new(tokens) | ||
69 | } | ||
70 | |||
71 | pub fn from_subtree(subtree: &'t Subtree) -> TokenBuffer<'t> { | ||
72 | Self::new(subtree) | ||
73 | } | ||
74 | |||
75 | fn new<T: TokenList<'t>>(tokens: T) -> TokenBuffer<'t> { | ||
76 | let mut buffers = vec![]; | ||
77 | let idx = TokenBuffer::new_inner(tokens, &mut buffers, None); | ||
78 | assert_eq!(idx, 0); | ||
79 | TokenBuffer { buffers } | ||
80 | } | ||
81 | |||
82 | fn new_inner<T: TokenList<'t>>( | ||
83 | tokens: T, | ||
84 | buffers: &mut Vec<Box<[Entry<'t>]>>, | ||
85 | next: Option<EntryPtr>, | ||
86 | ) -> usize { | ||
87 | let (children, mut entries) = tokens.entries(); | ||
61 | 88 | ||
62 | entries.push(Entry::End(next)); | 89 | entries.push(Entry::End(next)); |
63 | let res = buffers.len(); | 90 | let res = buffers.len(); |
@@ -65,11 +92,11 @@ impl<'t> TokenBuffer<'t> { | |||
65 | 92 | ||
66 | for (child_idx, (subtree, tt)) in children { | 93 | for (child_idx, (subtree, tt)) in children { |
67 | let idx = TokenBuffer::new_inner( | 94 | let idx = TokenBuffer::new_inner( |
68 | &subtree.token_trees, | 95 | subtree.token_trees.as_slice(), |
69 | buffers, | 96 | buffers, |
70 | Some(EntryPtr(EntryId(res), child_idx + 1)), | 97 | Some(EntryPtr(EntryId(res), child_idx + 1)), |
71 | ); | 98 | ); |
72 | buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, EntryId(idx)); | 99 | buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, subtree, EntryId(idx)); |
73 | } | 100 | } |
74 | 101 | ||
75 | res | 102 | res |
@@ -87,6 +114,24 @@ impl<'t> TokenBuffer<'t> { | |||
87 | } | 114 | } |
88 | } | 115 | } |
89 | 116 | ||
117 | #[derive(Debug)] | ||
118 | pub enum TokenTreeRef<'a> { | ||
119 | Subtree(&'a Subtree, Option<&'a TokenTree>), | ||
120 | Leaf(&'a Leaf, &'a TokenTree), | ||
121 | } | ||
122 | |||
123 | impl<'a> TokenTreeRef<'a> { | ||
124 | pub fn cloned(&self) -> TokenTree { | ||
125 | match &self { | ||
126 | TokenTreeRef::Subtree(subtree, tt) => match tt { | ||
127 | Some(it) => (*it).clone(), | ||
128 | None => (*subtree).clone().into(), | ||
129 | }, | ||
130 | TokenTreeRef::Leaf(_, tt) => (*tt).clone(), | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
90 | /// A safe version of `Cursor` from `syn` crate https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125 | 135 | /// A safe version of `Cursor` from `syn` crate https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125 |
91 | #[derive(Copy, Clone, Debug)] | 136 | #[derive(Copy, Clone, Debug)] |
92 | pub struct Cursor<'a> { | 137 | pub struct Cursor<'a> { |
@@ -114,12 +159,11 @@ impl<'a> Cursor<'a> { | |||
114 | match self.entry() { | 159 | match self.entry() { |
115 | Some(Entry::End(Some(ptr))) => { | 160 | Some(Entry::End(Some(ptr))) => { |
116 | let idx = ptr.1; | 161 | let idx = ptr.1; |
117 | if let Some(Entry::Subtree(TokenTree::Subtree(subtree), _)) = | 162 | if let Some(Entry::Subtree(_, subtree, _)) = |
118 | self.buffer.entry(&EntryPtr(ptr.0, idx - 1)) | 163 | self.buffer.entry(&EntryPtr(ptr.0, idx - 1)) |
119 | { | 164 | { |
120 | return Some(subtree); | 165 | return Some(subtree); |
121 | } | 166 | } |
122 | |||
123 | None | 167 | None |
124 | } | 168 | } |
125 | _ => None, | 169 | _ => None, |
@@ -134,7 +178,7 @@ impl<'a> Cursor<'a> { | |||
134 | /// a cursor into that subtree | 178 | /// a cursor into that subtree |
135 | pub fn subtree(self) -> Option<Cursor<'a>> { | 179 | pub fn subtree(self) -> Option<Cursor<'a>> { |
136 | match self.entry() { | 180 | match self.entry() { |
137 | Some(Entry::Subtree(_, entry_id)) => { | 181 | Some(Entry::Subtree(_, _, entry_id)) => { |
138 | Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0))) | 182 | Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0))) |
139 | } | 183 | } |
140 | _ => None, | 184 | _ => None, |
@@ -142,10 +186,13 @@ impl<'a> Cursor<'a> { | |||
142 | } | 186 | } |
143 | 187 | ||
144 | /// If the cursor is pointing at a `TokenTree`, returns it | 188 | /// If the cursor is pointing at a `TokenTree`, returns it |
145 | pub fn token_tree(self) -> Option<&'a TokenTree> { | 189 | pub fn token_tree(self) -> Option<TokenTreeRef<'a>> { |
146 | match self.entry() { | 190 | match self.entry() { |
147 | Some(Entry::Leaf(tt)) => Some(tt), | 191 | Some(Entry::Leaf(tt)) => match tt { |
148 | Some(Entry::Subtree(tt, _)) => Some(tt), | 192 | TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, *tt)), |
193 | TokenTree::Subtree(subtree) => Some(TokenTreeRef::Subtree(subtree, Some(tt))), | ||
194 | }, | ||
195 | Some(Entry::Subtree(tt, subtree, _)) => Some(TokenTreeRef::Subtree(subtree, *tt)), | ||
149 | Some(Entry::End(_)) => None, | 196 | Some(Entry::End(_)) => None, |
150 | None => None, | 197 | None => None, |
151 | } | 198 | } |
@@ -172,7 +219,7 @@ impl<'a> Cursor<'a> { | |||
172 | /// a cursor into that subtree | 219 | /// a cursor into that subtree |
173 | pub fn bump_subtree(self) -> Cursor<'a> { | 220 | pub fn bump_subtree(self) -> Cursor<'a> { |
174 | match self.entry() { | 221 | match self.entry() { |
175 | Some(Entry::Subtree(_, _)) => self.subtree().unwrap(), | 222 | Some(Entry::Subtree(_, _, _)) => self.subtree().unwrap(), |
176 | _ => self.bump(), | 223 | _ => self.bump(), |
177 | } | 224 | } |
178 | } | 225 | } |
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 9cf2afd33..2b7b14524 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs | |||
@@ -2,43 +2,46 @@ | |||
2 | //! | 2 | //! |
3 | //! VFS stores all files read by rust-analyzer. Reading file contents from VFS | 3 | //! VFS stores all files read by rust-analyzer. Reading file contents from VFS |
4 | //! always returns the same contents, unless VFS was explicitly modified with | 4 | //! always returns the same contents, unless VFS was explicitly modified with |
5 | //! `set_file_contents`. All changes to VFS are logged, and can be retrieved via | 5 | //! [`set_file_contents`]. All changes to VFS are logged, and can be retrieved via |
6 | //! `take_changes` method. The pack of changes is then pushed to `salsa` and | 6 | //! [`take_changes`] method. The pack of changes is then pushed to `salsa` and |
7 | //! triggers incremental recomputation. | 7 | //! triggers incremental recomputation. |
8 | //! | 8 | //! |
9 | //! Files in VFS are identified with `FileId`s -- interned paths. The notion of | 9 | //! Files in VFS are identified with [`FileId`]s -- interned paths. The notion of |
10 | //! the path, `VfsPath` is somewhat abstract: at the moment, it is represented | 10 | //! the path, [`VfsPath`] is somewhat abstract: at the moment, it is represented |
11 | //! as an `std::path::PathBuf` internally, but this is an implementation detail. | 11 | //! as an [`std::path::PathBuf`] internally, but this is an implementation detail. |
12 | //! | 12 | //! |
13 | //! VFS doesn't do IO or file watching itself. For that, see the `loader` | 13 | //! VFS doesn't do IO or file watching itself. For that, see the [`loader`] |
14 | //! module. `loader::Handle` is an object-safe trait which abstracts both file | 14 | //! module. [`loader::Handle`] is an object-safe trait which abstracts both file |
15 | //! loading and file watching. `Handle` is dynamically configured with a set of | 15 | //! loading and file watching. [`Handle`] is dynamically configured with a set of |
16 | //! directory entries which should be scanned and watched. `Handle` then | 16 | //! directory entries which should be scanned and watched. [`Handle`] then |
17 | //! asynchronously pushes file changes. Directory entries are configured in | 17 | //! asynchronously pushes file changes. Directory entries are configured in |
18 | //! free-form via list of globs, it's up to the `Handle` to interpret the globs | 18 | //! free-form via list of globs, it's up to the [`Handle`] to interpret the globs |
19 | //! in any specific way. | 19 | //! in any specific way. |
20 | //! | 20 | //! |
21 | //! A simple `WalkdirLoaderHandle` is provided, which doesn't implement watching | 21 | //! VFS stores a flat list of files. [`file_set::FileSet`] can partition this list |
22 | //! and just scans the directory using walkdir. | 22 | //! of files into disjoint sets of files. Traversal-like operations (including |
23 | //! | 23 | //! getting the neighbor file by the relative path) are handled by the [`FileSet`]. |
24 | //! VFS stores a flat list of files. `FileSet` can partition this list of files | 24 | //! [`FileSet`]s are also pushed to salsa and cause it to re-check `mod foo;` |
25 | //! into disjoint sets of files. Traversal-like operations (including getting | ||
26 | //! the neighbor file by the relative path) are handled by the `FileSet`. | ||
27 | //! `FileSet`s are also pushed to salsa and cause it to re-check `mod foo;` | ||
28 | //! declarations when files are created or deleted. | 25 | //! declarations when files are created or deleted. |
29 | //! | 26 | //! |
30 | //! `file_set::FileSet` and `loader::Entry` play similar, but different roles. | 27 | //! [`FileSet`] and [`loader::Entry`] play similar, but different roles. |
31 | //! Both specify the "set of paths/files", one is geared towards file watching, | 28 | //! Both specify the "set of paths/files", one is geared towards file watching, |
32 | //! the other towards salsa changes. In particular, single `file_set::FileSet` | 29 | //! the other towards salsa changes. In particular, single [`FileSet`] |
33 | //! may correspond to several `loader::Entry`. For example, a crate from | 30 | //! may correspond to several [`loader::Entry`]. For example, a crate from |
34 | //! crates.io which uses code generation would have two `Entries` -- for sources | 31 | //! crates.io which uses code generation would have two [`Entries`] -- for sources |
35 | //! in `~/.cargo`, and for generated code in `./target/debug/build`. It will | 32 | //! in `~/.cargo`, and for generated code in `./target/debug/build`. It will |
36 | //! have a single `FileSet` which unions the two sources. | 33 | //! have a single [`FileSet`] which unions the two sources. |
37 | mod vfs_path; | 34 | //! |
38 | mod path_interner; | 35 | //! [`set_file_contents`]: Vfs::set_file_contents |
36 | //! [`take_changes`]: Vfs::take_changes | ||
37 | //! [`FileSet`]: file_set::FileSet | ||
38 | //! [`Handle`]: loader::Handle | ||
39 | //! [`Entries`]: loader::Entry | ||
39 | mod anchored_path; | 40 | mod anchored_path; |
40 | pub mod file_set; | 41 | pub mod file_set; |
41 | pub mod loader; | 42 | pub mod loader; |
43 | mod path_interner; | ||
44 | mod vfs_path; | ||
42 | 45 | ||
43 | use std::{fmt, mem}; | 46 | use std::{fmt, mem}; |
44 | 47 | ||