diff options
Diffstat (limited to 'crates')
104 files changed, 2903 insertions, 2893 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 005c17776..5b1a4680b 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -5,7 +5,7 @@ use hir::Semantics; | |||
5 | use ra_db::{FileId, FileRange}; | 5 | use ra_db::{FileId, FileRange}; |
6 | use ra_fmt::{leading_indent, reindent}; | 6 | use ra_fmt::{leading_indent, reindent}; |
7 | use ra_ide_db::{ | 7 | use ra_ide_db::{ |
8 | source_change::{SingleFileChange, SourceChange}, | 8 | source_change::{SourceChange, SourceFileEdit}, |
9 | RootDatabase, | 9 | RootDatabase, |
10 | }; | 10 | }; |
11 | use ra_syntax::{ | 11 | use ra_syntax::{ |
@@ -150,11 +150,10 @@ impl Assists { | |||
150 | self.add_impl(label, f) | 150 | self.add_impl(label, f) |
151 | } | 151 | } |
152 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | 152 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { |
153 | let change_label = label.label.clone(); | ||
154 | let source_change = if self.resolve { | 153 | let source_change = if self.resolve { |
155 | let mut builder = AssistBuilder::new(self.file); | 154 | let mut builder = AssistBuilder::new(self.file); |
156 | f(&mut builder); | 155 | f(&mut builder); |
157 | Some(builder.finish(change_label)) | 156 | Some(builder.finish()) |
158 | } else { | 157 | } else { |
159 | None | 158 | None |
160 | }; | 159 | }; |
@@ -171,19 +170,13 @@ impl Assists { | |||
171 | 170 | ||
172 | pub(crate) struct AssistBuilder { | 171 | pub(crate) struct AssistBuilder { |
173 | edit: TextEditBuilder, | 172 | edit: TextEditBuilder, |
174 | cursor_position: Option<TextSize>, | ||
175 | file: FileId, | 173 | file: FileId, |
176 | is_snippet: bool, | 174 | is_snippet: bool, |
177 | } | 175 | } |
178 | 176 | ||
179 | impl AssistBuilder { | 177 | impl AssistBuilder { |
180 | pub(crate) fn new(file: FileId) -> AssistBuilder { | 178 | pub(crate) fn new(file: FileId) -> AssistBuilder { |
181 | AssistBuilder { | 179 | AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false } |
182 | edit: TextEditBuilder::default(), | ||
183 | cursor_position: None, | ||
184 | file, | ||
185 | is_snippet: false, | ||
186 | } | ||
187 | } | 180 | } |
188 | 181 | ||
189 | /// Remove specified `range` of text. | 182 | /// Remove specified `range` of text. |
@@ -241,10 +234,6 @@ impl AssistBuilder { | |||
241 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | 234 | algo::diff(&node, &new).into_text_edit(&mut self.edit) |
242 | } | 235 | } |
243 | 236 | ||
244 | /// Specify desired position of the cursor after the assist is applied. | ||
245 | pub(crate) fn set_cursor(&mut self, offset: TextSize) { | ||
246 | self.cursor_position = Some(offset) | ||
247 | } | ||
248 | // FIXME: better API | 237 | // FIXME: better API |
249 | pub(crate) fn set_file(&mut self, assist_file: FileId) { | 238 | pub(crate) fn set_file(&mut self, assist_file: FileId) { |
250 | self.file = assist_file; | 239 | self.file = assist_file; |
@@ -256,14 +245,10 @@ impl AssistBuilder { | |||
256 | &mut self.edit | 245 | &mut self.edit |
257 | } | 246 | } |
258 | 247 | ||
259 | fn finish(self, change_label: String) -> SourceChange { | 248 | fn finish(self) -> SourceChange { |
260 | let edit = self.edit.finish(); | 249 | let edit = self.edit.finish(); |
261 | if edit.is_empty() && self.cursor_position.is_none() { | 250 | let source_file_edit = SourceFileEdit { file_id: self.file, edit }; |
262 | panic!("Only call `add_assist` if the assist can be applied") | 251 | let mut res: SourceChange = source_file_edit.into(); |
263 | } | ||
264 | let mut res = | ||
265 | SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position } | ||
266 | .into_source_change(self.file); | ||
267 | if self.is_snippet { | 252 | if self.is_snippet { |
268 | res.is_snippet = true; | 253 | res.is_snippet = true; |
269 | } | 254 | } |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 770049212..ab20c6649 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -86,11 +86,7 @@ mod tests { | |||
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( | 89 | check_assist(add_explicit_type, "fn f() { let a<|> = 1; }", "fn f() { let a: i32 = 1; }"); |
90 | add_explicit_type, | ||
91 | "fn f() { let a<|> = 1; }", | ||
92 | "fn f() { let a<|>: i32 = 1; }", | ||
93 | ); | ||
94 | } | 90 | } |
95 | 91 | ||
96 | #[test] | 92 | #[test] |
@@ -98,7 +94,7 @@ mod tests { | |||
98 | check_assist( | 94 | check_assist( |
99 | add_explicit_type, | 95 | add_explicit_type, |
100 | "fn f() { let a<|>: _ = 1; }", | 96 | "fn f() { let a<|>: _ = 1; }", |
101 | "fn f() { let a<|>: i32 = 1; }", | 97 | "fn f() { let a: i32 = 1; }", |
102 | ); | 98 | ); |
103 | } | 99 | } |
104 | 100 | ||
@@ -122,7 +118,7 @@ mod tests { | |||
122 | } | 118 | } |
123 | 119 | ||
124 | fn f() { | 120 | fn f() { |
125 | let a<|>: Option<i32> = Option::Some(1); | 121 | let a: Option<i32> = Option::Some(1); |
126 | }"#, | 122 | }"#, |
127 | ); | 123 | ); |
128 | } | 124 | } |
@@ -132,7 +128,7 @@ mod tests { | |||
132 | check_assist( | 128 | check_assist( |
133 | add_explicit_type, | 129 | add_explicit_type, |
134 | r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", | 130 | r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", |
135 | r"macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }", | 131 | r"macro_rules! v { () => {0u64} } fn f() { let a: u64 = v!(); }", |
136 | ); | 132 | ); |
137 | } | 133 | } |
138 | 134 | ||
@@ -140,8 +136,8 @@ mod tests { | |||
140 | fn add_explicit_type_works_for_macro_call_recursive() { | 136 | fn add_explicit_type_works_for_macro_call_recursive() { |
141 | check_assist( | 137 | check_assist( |
142 | add_explicit_type, | 138 | add_explicit_type, |
143 | "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }", | 139 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }"#, |
144 | "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|>: u64 = v!(); }", | 140 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a: u64 = v!(); }"#, |
145 | ); | 141 | ); |
146 | } | 142 | } |
147 | 143 | ||
@@ -208,7 +204,7 @@ struct Test<K, T = u8> { | |||
208 | } | 204 | } |
209 | 205 | ||
210 | fn main() { | 206 | fn main() { |
211 | let test<|>: Test<i32> = Test { t: 23, k: 33 }; | 207 | let test: Test<i32> = Test { t: 23, k: 33 }; |
212 | }"#, | 208 | }"#, |
213 | ); | 209 | ); |
214 | } | 210 | } |
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs index eb57b7231..6a675e812 100644 --- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_ide_db::RootDatabase; | 1 | use ra_ide_db::RootDatabase; |
2 | use ra_syntax::ast::{self, AstNode, NameOwner}; | 2 | use ra_syntax::ast::{self, AstNode, NameOwner}; |
3 | use test_utils::tested_by; | 3 | use test_utils::mark; |
4 | 4 | ||
5 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | 5 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; |
6 | 6 | ||
@@ -39,7 +39,7 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> | |||
39 | }; | 39 | }; |
40 | 40 | ||
41 | if existing_from_impl(&ctx.sema, &variant).is_some() { | 41 | if existing_from_impl(&ctx.sema, &variant).is_some() { |
42 | tested_by!(test_add_from_impl_already_exists); | 42 | mark::hit!(test_add_from_impl_already_exists); |
43 | return None; | 43 | return None; |
44 | } | 44 | } |
45 | 45 | ||
@@ -90,7 +90,7 @@ fn existing_from_impl( | |||
90 | 90 | ||
91 | #[cfg(test)] | 91 | #[cfg(test)] |
92 | mod tests { | 92 | mod tests { |
93 | use test_utils::covers; | 93 | use test_utils::mark; |
94 | 94 | ||
95 | use crate::tests::{check_assist, check_assist_not_applicable}; | 95 | use crate::tests::{check_assist, check_assist_not_applicable}; |
96 | 96 | ||
@@ -101,7 +101,7 @@ mod tests { | |||
101 | check_assist( | 101 | check_assist( |
102 | add_from_impl_for_enum, | 102 | add_from_impl_for_enum, |
103 | "enum A { <|>One(u32) }", | 103 | "enum A { <|>One(u32) }", |
104 | r#"enum A { <|>One(u32) } | 104 | r#"enum A { One(u32) } |
105 | 105 | ||
106 | impl From<u32> for A { | 106 | impl From<u32> for A { |
107 | fn from(v: u32) -> Self { | 107 | fn from(v: u32) -> Self { |
@@ -116,7 +116,7 @@ impl From<u32> for A { | |||
116 | check_assist( | 116 | check_assist( |
117 | add_from_impl_for_enum, | 117 | add_from_impl_for_enum, |
118 | r#"enum A { <|>One(foo::bar::baz::Boo) }"#, | 118 | r#"enum A { <|>One(foo::bar::baz::Boo) }"#, |
119 | r#"enum A { <|>One(foo::bar::baz::Boo) } | 119 | r#"enum A { One(foo::bar::baz::Boo) } |
120 | 120 | ||
121 | impl From<foo::bar::baz::Boo> for A { | 121 | impl From<foo::bar::baz::Boo> for A { |
122 | fn from(v: foo::bar::baz::Boo) -> Self { | 122 | fn from(v: foo::bar::baz::Boo) -> Self { |
@@ -149,7 +149,7 @@ impl From<foo::bar::baz::Boo> for A { | |||
149 | 149 | ||
150 | #[test] | 150 | #[test] |
151 | fn test_add_from_impl_already_exists() { | 151 | fn test_add_from_impl_already_exists() { |
152 | covers!(test_add_from_impl_already_exists); | 152 | mark::check!(test_add_from_impl_already_exists); |
153 | check_not_applicable( | 153 | check_not_applicable( |
154 | r#" | 154 | r#" |
155 | enum A { <|>One(u32), } | 155 | enum A { <|>One(u32), } |
@@ -178,7 +178,7 @@ impl From<String> for A { | |||
178 | pub trait From<T> { | 178 | pub trait From<T> { |
179 | fn from(T) -> Self; | 179 | fn from(T) -> Self; |
180 | }"#, | 180 | }"#, |
181 | r#"enum A { <|>One(u32), Two(String), } | 181 | r#"enum A { One(u32), Two(String), } |
182 | 182 | ||
183 | impl From<u32> for A { | 183 | impl From<u32> for A { |
184 | fn from(v: u32) -> Self { | 184 | fn from(v: u32) -> Self { |
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs index a0363bc78..26acf81f2 100644 --- a/crates/ra_assists/src/handlers/add_turbo_fish.rs +++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass}; | 1 | use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass}; |
2 | use ra_syntax::{ast, AstNode, SyntaxKind, T}; | 2 | use ra_syntax::{ast, AstNode, SyntaxKind, T}; |
3 | use test_utils::mark; | ||
3 | 4 | ||
4 | use crate::{ | 5 | use crate::{ |
5 | assist_context::{AssistContext, Assists}, | 6 | assist_context::{AssistContext, Assists}, |
6 | AssistId, | 7 | AssistId, |
7 | }; | 8 | }; |
8 | use test_utils::tested_by; | ||
9 | 9 | ||
10 | // Assist: add_turbo_fish | 10 | // Assist: add_turbo_fish |
11 | // | 11 | // |
@@ -28,7 +28,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
28 | let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?; | 28 | let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?; |
29 | let next_token = ident.next_token()?; | 29 | let next_token = ident.next_token()?; |
30 | if next_token.kind() == T![::] { | 30 | if next_token.kind() == T![::] { |
31 | tested_by!(add_turbo_fish_one_fish_is_enough); | 31 | mark::hit!(add_turbo_fish_one_fish_is_enough); |
32 | return None; | 32 | return None; |
33 | } | 33 | } |
34 | let name_ref = ast::NameRef::cast(ident.parent())?; | 34 | let name_ref = ast::NameRef::cast(ident.parent())?; |
@@ -42,7 +42,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
42 | }; | 42 | }; |
43 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); | 43 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); |
44 | if generics.is_empty() { | 44 | if generics.is_empty() { |
45 | tested_by!(add_turbo_fish_non_generic); | 45 | mark::hit!(add_turbo_fish_non_generic); |
46 | return None; | 46 | return None; |
47 | } | 47 | } |
48 | acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| { | 48 | acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| { |
@@ -58,7 +58,7 @@ mod tests { | |||
58 | use crate::tests::{check_assist, check_assist_not_applicable}; | 58 | use crate::tests::{check_assist, check_assist_not_applicable}; |
59 | 59 | ||
60 | use super::*; | 60 | use super::*; |
61 | use test_utils::covers; | 61 | use test_utils::mark; |
62 | 62 | ||
63 | #[test] | 63 | #[test] |
64 | fn add_turbo_fish_function() { | 64 | fn add_turbo_fish_function() { |
@@ -106,7 +106,7 @@ fn main() { | |||
106 | 106 | ||
107 | #[test] | 107 | #[test] |
108 | fn add_turbo_fish_one_fish_is_enough() { | 108 | fn add_turbo_fish_one_fish_is_enough() { |
109 | covers!(add_turbo_fish_one_fish_is_enough); | 109 | mark::check!(add_turbo_fish_one_fish_is_enough); |
110 | check_assist_not_applicable( | 110 | check_assist_not_applicable( |
111 | add_turbo_fish, | 111 | add_turbo_fish, |
112 | r#" | 112 | r#" |
@@ -120,7 +120,7 @@ fn main() { | |||
120 | 120 | ||
121 | #[test] | 121 | #[test] |
122 | fn add_turbo_fish_non_generic() { | 122 | fn add_turbo_fish_non_generic() { |
123 | covers!(add_turbo_fish_non_generic); | 123 | mark::check!(add_turbo_fish_non_generic); |
124 | check_assist_not_applicable( | 124 | check_assist_not_applicable( |
125 | add_turbo_fish, | 125 | add_turbo_fish, |
126 | r#" | 126 | r#" |
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index 0feba5e11..233e8fb8e 100644 --- a/crates/ra_assists/src/handlers/apply_demorgan.rs +++ b/crates/ra_assists/src/handlers/apply_demorgan.rs | |||
@@ -63,22 +63,22 @@ mod tests { | |||
63 | 63 | ||
64 | #[test] | 64 | #[test] |
65 | fn demorgan_turns_and_into_or() { | 65 | fn demorgan_turns_and_into_or() { |
66 | check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x ||<|> x) }") | 66 | check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x || x) }") |
67 | } | 67 | } |
68 | 68 | ||
69 | #[test] | 69 | #[test] |
70 | fn demorgan_turns_or_into_and() { | 70 | fn demorgan_turns_or_into_and() { |
71 | check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x &&<|> x) }") | 71 | check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x && x) }") |
72 | } | 72 | } |
73 | 73 | ||
74 | #[test] | 74 | #[test] |
75 | fn demorgan_removes_inequality() { | 75 | fn demorgan_removes_inequality() { |
76 | check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x &&<|> x) }") | 76 | check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x && x) }") |
77 | } | 77 | } |
78 | 78 | ||
79 | #[test] | 79 | #[test] |
80 | fn demorgan_general_case() { | 80 | fn demorgan_general_case() { |
81 | check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x &&<|> !x) }") | 81 | check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x && !x) }") |
82 | } | 82 | } |
83 | 83 | ||
84 | #[test] | 84 | #[test] |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index f6d25579e..edf96d50e 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -298,7 +298,7 @@ mod tests { | |||
298 | } | 298 | } |
299 | ", | 299 | ", |
300 | r" | 300 | r" |
301 | <|>use PubMod::PubStruct; | 301 | use PubMod::PubStruct; |
302 | 302 | ||
303 | PubStruct | 303 | PubStruct |
304 | 304 | ||
@@ -329,7 +329,7 @@ mod tests { | |||
329 | macro_rules! foo { | 329 | macro_rules! foo { |
330 | ($i:ident) => { fn foo(a: $i) {} } | 330 | ($i:ident) => { fn foo(a: $i) {} } |
331 | } | 331 | } |
332 | foo!(Pub<|>Struct); | 332 | foo!(PubStruct); |
333 | 333 | ||
334 | pub mod PubMod { | 334 | pub mod PubMod { |
335 | pub struct PubStruct; | 335 | pub struct PubStruct; |
@@ -360,7 +360,7 @@ mod tests { | |||
360 | use PubMod::{PubStruct2, PubStruct1}; | 360 | use PubMod::{PubStruct2, PubStruct1}; |
361 | 361 | ||
362 | struct Test { | 362 | struct Test { |
363 | test: Pub<|>Struct2<u8>, | 363 | test: PubStruct2<u8>, |
364 | } | 364 | } |
365 | 365 | ||
366 | pub mod PubMod { | 366 | pub mod PubMod { |
@@ -393,7 +393,7 @@ mod tests { | |||
393 | r" | 393 | r" |
394 | use PubMod3::PubStruct; | 394 | use PubMod3::PubStruct; |
395 | 395 | ||
396 | PubSt<|>ruct | 396 | PubStruct |
397 | 397 | ||
398 | pub mod PubMod1 { | 398 | pub mod PubMod1 { |
399 | pub struct PubStruct; | 399 | pub struct PubStruct; |
@@ -474,7 +474,7 @@ mod tests { | |||
474 | r" | 474 | r" |
475 | use PubMod::test_function; | 475 | use PubMod::test_function; |
476 | 476 | ||
477 | test_function<|> | 477 | test_function |
478 | 478 | ||
479 | pub mod PubMod { | 479 | pub mod PubMod { |
480 | pub fn test_function() {}; | 480 | pub fn test_function() {}; |
@@ -501,7 +501,7 @@ mod tests { | |||
501 | r"use crate_with_macro::foo; | 501 | r"use crate_with_macro::foo; |
502 | 502 | ||
503 | fn main() { | 503 | fn main() { |
504 | foo<|> | 504 | foo |
505 | } | 505 | } |
506 | ", | 506 | ", |
507 | ); | 507 | ); |
@@ -587,7 +587,7 @@ fn main() { | |||
587 | } | 587 | } |
588 | 588 | ||
589 | fn main() { | 589 | fn main() { |
590 | TestStruct::test_function<|> | 590 | TestStruct::test_function |
591 | } | 591 | } |
592 | ", | 592 | ", |
593 | ); | 593 | ); |
@@ -620,7 +620,7 @@ fn main() { | |||
620 | } | 620 | } |
621 | 621 | ||
622 | fn main() { | 622 | fn main() { |
623 | TestStruct::TEST_CONST<|> | 623 | TestStruct::TEST_CONST |
624 | } | 624 | } |
625 | ", | 625 | ", |
626 | ); | 626 | ); |
@@ -659,7 +659,7 @@ fn main() { | |||
659 | } | 659 | } |
660 | 660 | ||
661 | fn main() { | 661 | fn main() { |
662 | test_mod::TestStruct::test_function<|> | 662 | test_mod::TestStruct::test_function |
663 | } | 663 | } |
664 | ", | 664 | ", |
665 | ); | 665 | ); |
@@ -730,7 +730,7 @@ fn main() { | |||
730 | } | 730 | } |
731 | 731 | ||
732 | fn main() { | 732 | fn main() { |
733 | test_mod::TestStruct::TEST_CONST<|> | 733 | test_mod::TestStruct::TEST_CONST |
734 | } | 734 | } |
735 | ", | 735 | ", |
736 | ); | 736 | ); |
@@ -803,7 +803,7 @@ fn main() { | |||
803 | 803 | ||
804 | fn main() { | 804 | fn main() { |
805 | let test_struct = test_mod::TestStruct {}; | 805 | let test_struct = test_mod::TestStruct {}; |
806 | test_struct.test_meth<|>od() | 806 | test_struct.test_method() |
807 | } | 807 | } |
808 | ", | 808 | ", |
809 | ); | 809 | ); |
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 40cf4b422..c21d75be0 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -5,14 +5,11 @@ use ra_syntax::{ | |||
5 | ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, | 5 | ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, |
6 | WHITESPACE, | 6 | WHITESPACE, |
7 | }, | 7 | }, |
8 | SyntaxNode, TextRange, TextSize, T, | 8 | SyntaxNode, TextSize, T, |
9 | }; | 9 | }; |
10 | 10 | use test_utils::mark; | |
11 | use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; | ||
12 | use test_utils::tested_by; | ||
13 | 11 | ||
14 | use crate::{AssistContext, AssistId, Assists}; | 12 | use crate::{AssistContext, AssistId, Assists}; |
15 | use ra_db::FileId; | ||
16 | 13 | ||
17 | // Assist: change_visibility | 14 | // Assist: change_visibility |
18 | // | 15 | // |
@@ -30,8 +27,6 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
30 | return change_vis(acc, vis); | 27 | return change_vis(acc, vis); |
31 | } | 28 | } |
32 | add_vis(acc, ctx) | 29 | add_vis(acc, ctx) |
33 | .or_else(|| add_vis_to_referenced_module_def(acc, ctx)) | ||
34 | .or_else(|| add_vis_to_referenced_record_field(acc, ctx)) | ||
35 | } | 30 | } |
36 | 31 | ||
37 | fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 32 | fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -55,7 +50,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
55 | } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { | 50 | } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { |
56 | let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; | 51 | let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; |
57 | if field.name()? != field_name { | 52 | if field.name()? != field_name { |
58 | tested_by!(change_visibility_field_false_positive); | 53 | mark::hit!(change_visibility_field_false_positive); |
59 | return None; | 54 | return None; |
60 | } | 55 | } |
61 | if field.visibility().is_some() { | 56 | if field.visibility().is_some() { |
@@ -73,147 +68,9 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
73 | 68 | ||
74 | acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| { | 69 | acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| { |
75 | edit.insert(offset, "pub(crate) "); | 70 | edit.insert(offset, "pub(crate) "); |
76 | edit.set_cursor(offset); | ||
77 | }) | ||
78 | } | ||
79 | |||
80 | fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
81 | let path: ast::Path = ctx.find_node_at_offset()?; | ||
82 | let path_res = ctx.sema.resolve_path(&path)?; | ||
83 | let def = match path_res { | ||
84 | PathResolution::Def(def) => def, | ||
85 | _ => return None, | ||
86 | }; | ||
87 | |||
88 | let current_module = ctx.sema.scope(&path.syntax()).module()?; | ||
89 | let target_module = def.module(ctx.db)?; | ||
90 | |||
91 | let vis = target_module.visibility_of(ctx.db, &def)?; | ||
92 | if vis.is_visible_from(ctx.db, current_module.into()) { | ||
93 | return None; | ||
94 | }; | ||
95 | |||
96 | let (offset, target, target_file, target_name) = target_data_for_def(ctx.db, def)?; | ||
97 | |||
98 | let missing_visibility = | ||
99 | if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; | ||
100 | |||
101 | let assist_label = match target_name { | ||
102 | None => format!("Change visibility to {}", missing_visibility), | ||
103 | Some(name) => format!("Change visibility of {} to {}", name, missing_visibility), | ||
104 | }; | ||
105 | |||
106 | acc.add(AssistId("change_visibility"), assist_label, target, |edit| { | ||
107 | edit.set_file(target_file); | ||
108 | edit.insert(offset, format!("{} ", missing_visibility)); | ||
109 | edit.set_cursor(offset); | ||
110 | }) | ||
111 | } | ||
112 | |||
113 | fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
114 | let record_field: ast::RecordField = ctx.find_node_at_offset()?; | ||
115 | let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; | ||
116 | |||
117 | let current_module = ctx.sema.scope(record_field.syntax()).module()?; | ||
118 | let visibility = record_field_def.visibility(ctx.db); | ||
119 | if visibility.is_visible_from(ctx.db, current_module.into()) { | ||
120 | return None; | ||
121 | } | ||
122 | |||
123 | let parent = record_field_def.parent_def(ctx.db); | ||
124 | let parent_name = parent.name(ctx.db); | ||
125 | let target_module = parent.module(ctx.db); | ||
126 | |||
127 | let in_file_source = record_field_def.source(ctx.db); | ||
128 | let (offset, target) = match in_file_source.value { | ||
129 | hir::FieldSource::Named(it) => { | ||
130 | let s = it.syntax(); | ||
131 | (vis_offset(s), s.text_range()) | ||
132 | } | ||
133 | hir::FieldSource::Pos(it) => { | ||
134 | let s = it.syntax(); | ||
135 | (vis_offset(s), s.text_range()) | ||
136 | } | ||
137 | }; | ||
138 | |||
139 | let missing_visibility = | ||
140 | if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; | ||
141 | let target_file = in_file_source.file_id.original_file(ctx.db); | ||
142 | |||
143 | let target_name = record_field_def.name(ctx.db); | ||
144 | let assist_label = | ||
145 | format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); | ||
146 | |||
147 | acc.add(AssistId("change_visibility"), assist_label, target, |edit| { | ||
148 | edit.set_file(target_file); | ||
149 | edit.insert(offset, format!("{} ", missing_visibility)); | ||
150 | edit.set_cursor(offset) | ||
151 | }) | 71 | }) |
152 | } | 72 | } |
153 | 73 | ||
154 | fn target_data_for_def( | ||
155 | db: &dyn HirDatabase, | ||
156 | def: hir::ModuleDef, | ||
157 | ) -> Option<(TextSize, TextRange, FileId, Option<hir::Name>)> { | ||
158 | fn offset_target_and_file_id<S, Ast>( | ||
159 | db: &dyn HirDatabase, | ||
160 | x: S, | ||
161 | ) -> (TextSize, TextRange, FileId) | ||
162 | where | ||
163 | S: HasSource<Ast = Ast>, | ||
164 | Ast: AstNode, | ||
165 | { | ||
166 | let source = x.source(db); | ||
167 | let in_file_syntax = source.syntax(); | ||
168 | let file_id = in_file_syntax.file_id; | ||
169 | let syntax = in_file_syntax.value; | ||
170 | (vis_offset(syntax), syntax.text_range(), file_id.original_file(db.upcast())) | ||
171 | } | ||
172 | |||
173 | let target_name; | ||
174 | let (offset, target, target_file) = match def { | ||
175 | hir::ModuleDef::Function(f) => { | ||
176 | target_name = Some(f.name(db)); | ||
177 | offset_target_and_file_id(db, f) | ||
178 | } | ||
179 | hir::ModuleDef::Adt(adt) => { | ||
180 | target_name = Some(adt.name(db)); | ||
181 | match adt { | ||
182 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s), | ||
183 | hir::Adt::Union(u) => offset_target_and_file_id(db, u), | ||
184 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e), | ||
185 | } | ||
186 | } | ||
187 | hir::ModuleDef::Const(c) => { | ||
188 | target_name = c.name(db); | ||
189 | offset_target_and_file_id(db, c) | ||
190 | } | ||
191 | hir::ModuleDef::Static(s) => { | ||
192 | target_name = s.name(db); | ||
193 | offset_target_and_file_id(db, s) | ||
194 | } | ||
195 | hir::ModuleDef::Trait(t) => { | ||
196 | target_name = Some(t.name(db)); | ||
197 | offset_target_and_file_id(db, t) | ||
198 | } | ||
199 | hir::ModuleDef::TypeAlias(t) => { | ||
200 | target_name = Some(t.name(db)); | ||
201 | offset_target_and_file_id(db, t) | ||
202 | } | ||
203 | hir::ModuleDef::Module(m) => { | ||
204 | target_name = m.name(db); | ||
205 | let in_file_source = m.declaration_source(db)?; | ||
206 | let file_id = in_file_source.file_id.original_file(db.upcast()); | ||
207 | let syntax = in_file_source.value.syntax(); | ||
208 | (vis_offset(syntax), syntax.text_range(), file_id) | ||
209 | } | ||
210 | // Enum variants can't be private, we can't modify builtin types | ||
211 | hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None, | ||
212 | }; | ||
213 | |||
214 | Some((offset, target, target_file, target_name)) | ||
215 | } | ||
216 | |||
217 | fn vis_offset(node: &SyntaxNode) -> TextSize { | 74 | fn vis_offset(node: &SyntaxNode) -> TextSize { |
218 | node.children_with_tokens() | 75 | node.children_with_tokens() |
219 | .skip_while(|it| match it.kind() { | 76 | .skip_while(|it| match it.kind() { |
@@ -234,7 +91,6 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | |||
234 | target, | 91 | target, |
235 | |edit| { | 92 | |edit| { |
236 | edit.replace(vis.syntax().text_range(), "pub(crate)"); | 93 | edit.replace(vis.syntax().text_range(), "pub(crate)"); |
237 | edit.set_cursor(vis.syntax().text_range().start()) | ||
238 | }, | 94 | }, |
239 | ); | 95 | ); |
240 | } | 96 | } |
@@ -246,7 +102,6 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | |||
246 | target, | 102 | target, |
247 | |edit| { | 103 | |edit| { |
248 | edit.replace(vis.syntax().text_range(), "pub"); | 104 | edit.replace(vis.syntax().text_range(), "pub"); |
249 | edit.set_cursor(vis.syntax().text_range().start()); | ||
250 | }, | 105 | }, |
251 | ); | 106 | ); |
252 | } | 107 | } |
@@ -255,7 +110,7 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | |||
255 | 110 | ||
256 | #[cfg(test)] | 111 | #[cfg(test)] |
257 | mod tests { | 112 | mod tests { |
258 | use test_utils::covers; | 113 | use test_utils::mark; |
259 | 114 | ||
260 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 115 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
261 | 116 | ||
@@ -263,17 +118,13 @@ mod tests { | |||
263 | 118 | ||
264 | #[test] | 119 | #[test] |
265 | fn change_visibility_adds_pub_crate_to_items() { | 120 | fn change_visibility_adds_pub_crate_to_items() { |
266 | check_assist(change_visibility, "<|>fn foo() {}", "<|>pub(crate) fn foo() {}"); | 121 | check_assist(change_visibility, "<|>fn foo() {}", "pub(crate) fn foo() {}"); |
267 | check_assist(change_visibility, "f<|>n foo() {}", "<|>pub(crate) fn foo() {}"); | 122 | check_assist(change_visibility, "f<|>n foo() {}", "pub(crate) fn foo() {}"); |
268 | check_assist(change_visibility, "<|>struct Foo {}", "<|>pub(crate) struct Foo {}"); | 123 | check_assist(change_visibility, "<|>struct Foo {}", "pub(crate) struct Foo {}"); |
269 | check_assist(change_visibility, "<|>mod foo {}", "<|>pub(crate) mod foo {}"); | 124 | check_assist(change_visibility, "<|>mod foo {}", "pub(crate) mod foo {}"); |
270 | check_assist(change_visibility, "<|>trait Foo {}", "<|>pub(crate) trait Foo {}"); | 125 | check_assist(change_visibility, "<|>trait Foo {}", "pub(crate) trait Foo {}"); |
271 | check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}"); | 126 | check_assist(change_visibility, "m<|>od {}", "pub(crate) mod {}"); |
272 | check_assist( | 127 | check_assist(change_visibility, "unsafe f<|>n foo() {}", "pub(crate) unsafe fn foo() {}"); |
273 | change_visibility, | ||
274 | "unsafe f<|>n foo() {}", | ||
275 | "<|>pub(crate) unsafe fn foo() {}", | ||
276 | ); | ||
277 | } | 128 | } |
278 | 129 | ||
279 | #[test] | 130 | #[test] |
@@ -281,14 +132,14 @@ mod tests { | |||
281 | check_assist( | 132 | check_assist( |
282 | change_visibility, | 133 | change_visibility, |
283 | r"struct S { <|>field: u32 }", | 134 | r"struct S { <|>field: u32 }", |
284 | r"struct S { <|>pub(crate) field: u32 }", | 135 | r"struct S { pub(crate) field: u32 }", |
285 | ); | 136 | ); |
286 | check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( <|>pub(crate) u32 )"); | 137 | check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( pub(crate) u32 )"); |
287 | } | 138 | } |
288 | 139 | ||
289 | #[test] | 140 | #[test] |
290 | fn change_visibility_field_false_positive() { | 141 | fn change_visibility_field_false_positive() { |
291 | covers!(change_visibility_field_false_positive); | 142 | mark::check!(change_visibility_field_false_positive); |
292 | check_assist_not_applicable( | 143 | check_assist_not_applicable( |
293 | change_visibility, | 144 | change_visibility, |
294 | r"struct S { field: [(); { let <|>x = ();}] }", | 145 | r"struct S { field: [(); { let <|>x = ();}] }", |
@@ -297,17 +148,17 @@ mod tests { | |||
297 | 148 | ||
298 | #[test] | 149 | #[test] |
299 | fn change_visibility_pub_to_pub_crate() { | 150 | fn change_visibility_pub_to_pub_crate() { |
300 | check_assist(change_visibility, "<|>pub fn foo() {}", "<|>pub(crate) fn foo() {}") | 151 | check_assist(change_visibility, "<|>pub fn foo() {}", "pub(crate) fn foo() {}") |
301 | } | 152 | } |
302 | 153 | ||
303 | #[test] | 154 | #[test] |
304 | fn change_visibility_pub_crate_to_pub() { | 155 | fn change_visibility_pub_crate_to_pub() { |
305 | check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "<|>pub fn foo() {}") | 156 | check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "pub fn foo() {}") |
306 | } | 157 | } |
307 | 158 | ||
308 | #[test] | 159 | #[test] |
309 | fn change_visibility_const() { | 160 | fn change_visibility_const() { |
310 | check_assist(change_visibility, "<|>const FOO = 3u8;", "<|>pub(crate) const FOO = 3u8;"); | 161 | check_assist(change_visibility, "<|>const FOO = 3u8;", "pub(crate) const FOO = 3u8;"); |
311 | } | 162 | } |
312 | 163 | ||
313 | #[test] | 164 | #[test] |
@@ -328,199 +179,12 @@ mod tests { | |||
328 | // comments | 179 | // comments |
329 | 180 | ||
330 | #[derive(Debug)] | 181 | #[derive(Debug)] |
331 | <|>pub(crate) struct Foo; | 182 | pub(crate) struct Foo; |
332 | ", | 183 | ", |
333 | ) | 184 | ) |
334 | } | 185 | } |
335 | 186 | ||
336 | #[test] | 187 | #[test] |
337 | fn change_visibility_of_fn_via_path() { | ||
338 | check_assist( | ||
339 | change_visibility, | ||
340 | r"mod foo { fn foo() {} } | ||
341 | fn main() { foo::foo<|>() } ", | ||
342 | r"mod foo { <|>pub(crate) fn foo() {} } | ||
343 | fn main() { foo::foo() } ", | ||
344 | ); | ||
345 | check_assist_not_applicable( | ||
346 | change_visibility, | ||
347 | r"mod foo { pub fn foo() {} } | ||
348 | fn main() { foo::foo<|>() } ", | ||
349 | ) | ||
350 | } | ||
351 | |||
352 | #[test] | ||
353 | fn change_visibility_of_adt_in_submodule_via_path() { | ||
354 | check_assist( | ||
355 | change_visibility, | ||
356 | r"mod foo { struct Foo; } | ||
357 | fn main() { foo::Foo<|> } ", | ||
358 | r"mod foo { <|>pub(crate) struct Foo; } | ||
359 | fn main() { foo::Foo } ", | ||
360 | ); | ||
361 | check_assist_not_applicable( | ||
362 | change_visibility, | ||
363 | r"mod foo { pub struct Foo; } | ||
364 | fn main() { foo::Foo<|> } ", | ||
365 | ); | ||
366 | check_assist( | ||
367 | change_visibility, | ||
368 | r"mod foo { enum Foo; } | ||
369 | fn main() { foo::Foo<|> } ", | ||
370 | r"mod foo { <|>pub(crate) enum Foo; } | ||
371 | fn main() { foo::Foo } ", | ||
372 | ); | ||
373 | check_assist_not_applicable( | ||
374 | change_visibility, | ||
375 | r"mod foo { pub enum Foo; } | ||
376 | fn main() { foo::Foo<|> } ", | ||
377 | ); | ||
378 | check_assist( | ||
379 | change_visibility, | ||
380 | r"mod foo { union Foo; } | ||
381 | fn main() { foo::Foo<|> } ", | ||
382 | r"mod foo { <|>pub(crate) union Foo; } | ||
383 | fn main() { foo::Foo } ", | ||
384 | ); | ||
385 | check_assist_not_applicable( | ||
386 | change_visibility, | ||
387 | r"mod foo { pub union Foo; } | ||
388 | fn main() { foo::Foo<|> } ", | ||
389 | ); | ||
390 | } | ||
391 | |||
392 | #[test] | ||
393 | fn change_visibility_of_adt_in_other_file_via_path() { | ||
394 | check_assist( | ||
395 | change_visibility, | ||
396 | r" | ||
397 | //- /main.rs | ||
398 | mod foo; | ||
399 | fn main() { foo::Foo<|> } | ||
400 | |||
401 | //- /foo.rs | ||
402 | struct Foo; | ||
403 | ", | ||
404 | r"<|>pub(crate) struct Foo; | ||
405 | |||
406 | ", | ||
407 | ); | ||
408 | } | ||
409 | |||
410 | #[test] | ||
411 | fn change_visibility_of_struct_field_via_path() { | ||
412 | check_assist( | ||
413 | change_visibility, | ||
414 | r"mod foo { pub struct Foo { bar: (), } } | ||
415 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
416 | r"mod foo { pub struct Foo { <|>pub(crate) bar: (), } } | ||
417 | fn main() { foo::Foo { bar: () }; } ", | ||
418 | ); | ||
419 | check_assist( | ||
420 | change_visibility, | ||
421 | r"//- /lib.rs | ||
422 | mod foo; | ||
423 | fn main() { foo::Foo { <|>bar: () }; } | ||
424 | //- /foo.rs | ||
425 | pub struct Foo { bar: () } | ||
426 | ", | ||
427 | r"pub struct Foo { <|>pub(crate) bar: () } | ||
428 | |||
429 | ", | ||
430 | ); | ||
431 | check_assist_not_applicable( | ||
432 | change_visibility, | ||
433 | r"mod foo { pub struct Foo { pub bar: (), } } | ||
434 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
435 | ); | ||
436 | check_assist_not_applicable( | ||
437 | change_visibility, | ||
438 | r"//- /lib.rs | ||
439 | mod foo; | ||
440 | fn main() { foo::Foo { <|>bar: () }; } | ||
441 | //- /foo.rs | ||
442 | pub struct Foo { pub bar: () } | ||
443 | ", | ||
444 | ); | ||
445 | } | ||
446 | |||
447 | #[test] | ||
448 | fn change_visibility_of_enum_variant_field_via_path() { | ||
449 | check_assist( | ||
450 | change_visibility, | ||
451 | r"mod foo { pub enum Foo { Bar { bar: () } } } | ||
452 | fn main() { foo::Foo::Bar { <|>bar: () }; } ", | ||
453 | r"mod foo { pub enum Foo { Bar { <|>pub(crate) bar: () } } } | ||
454 | fn main() { foo::Foo::Bar { bar: () }; } ", | ||
455 | ); | ||
456 | check_assist( | ||
457 | change_visibility, | ||
458 | r"//- /lib.rs | ||
459 | mod foo; | ||
460 | fn main() { foo::Foo::Bar { <|>bar: () }; } | ||
461 | //- /foo.rs | ||
462 | pub enum Foo { Bar { bar: () } } | ||
463 | ", | ||
464 | r"pub enum Foo { Bar { <|>pub(crate) bar: () } } | ||
465 | |||
466 | ", | ||
467 | ); | ||
468 | check_assist_not_applicable( | ||
469 | change_visibility, | ||
470 | r"mod foo { pub struct Foo { pub bar: (), } } | ||
471 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
472 | ); | ||
473 | check_assist_not_applicable( | ||
474 | change_visibility, | ||
475 | r"//- /lib.rs | ||
476 | mod foo; | ||
477 | fn main() { foo::Foo { <|>bar: () }; } | ||
478 | //- /foo.rs | ||
479 | pub struct Foo { pub bar: () } | ||
480 | ", | ||
481 | ); | ||
482 | } | ||
483 | |||
484 | #[test] | ||
485 | #[ignore] | ||
486 | // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields | ||
487 | fn change_visibility_of_union_field_via_path() { | ||
488 | check_assist( | ||
489 | change_visibility, | ||
490 | r"mod foo { pub union Foo { bar: (), } } | ||
491 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
492 | r"mod foo { pub union Foo { <|>pub(crate) bar: (), } } | ||
493 | fn main() { foo::Foo { bar: () }; } ", | ||
494 | ); | ||
495 | check_assist( | ||
496 | change_visibility, | ||
497 | r"//- /lib.rs | ||
498 | mod foo; | ||
499 | fn main() { foo::Foo { <|>bar: () }; } | ||
500 | //- /foo.rs | ||
501 | pub union Foo { bar: () } | ||
502 | ", | ||
503 | r"pub union Foo { <|>pub(crate) bar: () } | ||
504 | |||
505 | ", | ||
506 | ); | ||
507 | check_assist_not_applicable( | ||
508 | change_visibility, | ||
509 | r"mod foo { pub union Foo { pub bar: (), } } | ||
510 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
511 | ); | ||
512 | check_assist_not_applicable( | ||
513 | change_visibility, | ||
514 | r"//- /lib.rs | ||
515 | mod foo; | ||
516 | fn main() { foo::Foo { <|>bar: () }; } | ||
517 | //- /foo.rs | ||
518 | pub union Foo { pub bar: () } | ||
519 | ", | ||
520 | ); | ||
521 | } | ||
522 | |||
523 | #[test] | ||
524 | fn not_applicable_for_enum_variants() { | 188 | fn not_applicable_for_enum_variants() { |
525 | check_assist_not_applicable( | 189 | check_assist_not_applicable( |
526 | change_visibility, | 190 | change_visibility, |
@@ -530,182 +194,6 @@ mod tests { | |||
530 | } | 194 | } |
531 | 195 | ||
532 | #[test] | 196 | #[test] |
533 | fn change_visibility_of_const_via_path() { | ||
534 | check_assist( | ||
535 | change_visibility, | ||
536 | r"mod foo { const FOO: () = (); } | ||
537 | fn main() { foo::FOO<|> } ", | ||
538 | r"mod foo { <|>pub(crate) const FOO: () = (); } | ||
539 | fn main() { foo::FOO } ", | ||
540 | ); | ||
541 | check_assist_not_applicable( | ||
542 | change_visibility, | ||
543 | r"mod foo { pub const FOO: () = (); } | ||
544 | fn main() { foo::FOO<|> } ", | ||
545 | ); | ||
546 | } | ||
547 | |||
548 | #[test] | ||
549 | fn change_visibility_of_static_via_path() { | ||
550 | check_assist( | ||
551 | change_visibility, | ||
552 | r"mod foo { static FOO: () = (); } | ||
553 | fn main() { foo::FOO<|> } ", | ||
554 | r"mod foo { <|>pub(crate) static FOO: () = (); } | ||
555 | fn main() { foo::FOO } ", | ||
556 | ); | ||
557 | check_assist_not_applicable( | ||
558 | change_visibility, | ||
559 | r"mod foo { pub static FOO: () = (); } | ||
560 | fn main() { foo::FOO<|> } ", | ||
561 | ); | ||
562 | } | ||
563 | |||
564 | #[test] | ||
565 | fn change_visibility_of_trait_via_path() { | ||
566 | check_assist( | ||
567 | change_visibility, | ||
568 | r"mod foo { trait Foo { fn foo(&self) {} } } | ||
569 | fn main() { let x: &dyn foo::<|>Foo; } ", | ||
570 | r"mod foo { <|>pub(crate) trait Foo { fn foo(&self) {} } } | ||
571 | fn main() { let x: &dyn foo::Foo; } ", | ||
572 | ); | ||
573 | check_assist_not_applicable( | ||
574 | change_visibility, | ||
575 | r"mod foo { pub trait Foo { fn foo(&self) {} } } | ||
576 | fn main() { let x: &dyn foo::Foo<|>; } ", | ||
577 | ); | ||
578 | } | ||
579 | |||
580 | #[test] | ||
581 | fn change_visibility_of_type_alias_via_path() { | ||
582 | check_assist( | ||
583 | change_visibility, | ||
584 | r"mod foo { type Foo = (); } | ||
585 | fn main() { let x: foo::Foo<|>; } ", | ||
586 | r"mod foo { <|>pub(crate) type Foo = (); } | ||
587 | fn main() { let x: foo::Foo; } ", | ||
588 | ); | ||
589 | check_assist_not_applicable( | ||
590 | change_visibility, | ||
591 | r"mod foo { pub type Foo = (); } | ||
592 | fn main() { let x: foo::Foo<|>; } ", | ||
593 | ); | ||
594 | } | ||
595 | |||
596 | #[test] | ||
597 | fn change_visibility_of_module_via_path() { | ||
598 | check_assist( | ||
599 | change_visibility, | ||
600 | r"mod foo { mod bar { fn bar() {} } } | ||
601 | fn main() { foo::bar<|>::bar(); } ", | ||
602 | r"mod foo { <|>pub(crate) mod bar { fn bar() {} } } | ||
603 | fn main() { foo::bar::bar(); } ", | ||
604 | ); | ||
605 | |||
606 | check_assist( | ||
607 | change_visibility, | ||
608 | r" | ||
609 | //- /main.rs | ||
610 | mod foo; | ||
611 | fn main() { foo::bar<|>::baz(); } | ||
612 | |||
613 | //- /foo.rs | ||
614 | mod bar { | ||
615 | pub fn baz() {} | ||
616 | } | ||
617 | ", | ||
618 | r"<|>pub(crate) mod bar { | ||
619 | pub fn baz() {} | ||
620 | } | ||
621 | |||
622 | ", | ||
623 | ); | ||
624 | |||
625 | check_assist_not_applicable( | ||
626 | change_visibility, | ||
627 | r"mod foo { pub mod bar { pub fn bar() {} } } | ||
628 | fn main() { foo::bar<|>::bar(); } ", | ||
629 | ); | ||
630 | } | ||
631 | |||
632 | #[test] | ||
633 | fn change_visibility_of_inline_module_in_other_file_via_path() { | ||
634 | check_assist( | ||
635 | change_visibility, | ||
636 | r" | ||
637 | //- /main.rs | ||
638 | mod foo; | ||
639 | fn main() { foo::bar<|>::baz(); } | ||
640 | |||
641 | //- /foo.rs | ||
642 | mod bar; | ||
643 | |||
644 | //- /foo/bar.rs | ||
645 | pub fn baz() {} | ||
646 | } | ||
647 | ", | ||
648 | r"<|>pub(crate) mod bar; | ||
649 | ", | ||
650 | ); | ||
651 | } | ||
652 | |||
653 | #[test] | ||
654 | fn change_visibility_of_module_declaration_in_other_file_via_path() { | ||
655 | check_assist( | ||
656 | change_visibility, | ||
657 | r"//- /main.rs | ||
658 | mod foo; | ||
659 | fn main() { foo::bar<|>>::baz(); } | ||
660 | |||
661 | //- /foo.rs | ||
662 | mod bar { | ||
663 | pub fn baz() {} | ||
664 | }", | ||
665 | r"<|>pub(crate) mod bar { | ||
666 | pub fn baz() {} | ||
667 | } | ||
668 | ", | ||
669 | ); | ||
670 | } | ||
671 | |||
672 | #[test] | ||
673 | #[ignore] | ||
674 | // FIXME handle reexports properly | ||
675 | fn change_visibility_of_reexport() { | ||
676 | check_assist( | ||
677 | change_visibility, | ||
678 | r" | ||
679 | mod foo { | ||
680 | use bar::Baz; | ||
681 | mod bar { pub(super) struct Baz; } | ||
682 | } | ||
683 | foo::Baz<|> | ||
684 | ", | ||
685 | r" | ||
686 | mod foo { | ||
687 | <|>pub(crate) use bar::Baz; | ||
688 | mod bar { pub(super) struct Baz; } | ||
689 | } | ||
690 | foo::Baz | ||
691 | ", | ||
692 | ) | ||
693 | } | ||
694 | |||
695 | #[test] | ||
696 | fn adds_pub_when_target_is_in_another_crate() { | ||
697 | check_assist( | ||
698 | change_visibility, | ||
699 | r"//- /main.rs crate:a deps:foo | ||
700 | foo::Bar<|> | ||
701 | //- /lib.rs crate:foo | ||
702 | struct Bar;", | ||
703 | r"<|>pub struct Bar; | ||
704 | ", | ||
705 | ) | ||
706 | } | ||
707 | |||
708 | #[test] | ||
709 | fn change_visibility_target() { | 197 | fn change_visibility_target() { |
710 | check_assist_target(change_visibility, "<|>fn foo() {}", "fn"); | 198 | check_assist_target(change_visibility, "<|>fn foo() {}", "fn"); |
711 | check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)"); | 199 | check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)"); |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 66b296081..4cc75a7ce 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -97,7 +97,6 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
97 | } | 97 | } |
98 | 98 | ||
99 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 99 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
100 | let cursor_position = ctx.offset(); | ||
101 | 100 | ||
102 | let target = if_expr.syntax().text_range(); | 101 | let target = if_expr.syntax().text_range(); |
103 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { | 102 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { |
@@ -148,7 +147,6 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
148 | } | 147 | } |
149 | }; | 148 | }; |
150 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | 149 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); |
151 | edit.set_cursor(cursor_position); | ||
152 | 150 | ||
153 | fn replace( | 151 | fn replace( |
154 | new_expr: &SyntaxNode, | 152 | new_expr: &SyntaxNode, |
@@ -207,7 +205,7 @@ mod tests { | |||
207 | r#" | 205 | r#" |
208 | fn main() { | 206 | fn main() { |
209 | bar(); | 207 | bar(); |
210 | if<|> !true { | 208 | if !true { |
211 | return; | 209 | return; |
212 | } | 210 | } |
213 | foo(); | 211 | foo(); |
@@ -237,7 +235,7 @@ mod tests { | |||
237 | r#" | 235 | r#" |
238 | fn main(n: Option<String>) { | 236 | fn main(n: Option<String>) { |
239 | bar(); | 237 | bar(); |
240 | le<|>t n = match n { | 238 | let n = match n { |
241 | Some(it) => it, | 239 | Some(it) => it, |
242 | _ => return, | 240 | _ => return, |
243 | }; | 241 | }; |
@@ -263,7 +261,7 @@ mod tests { | |||
263 | "#, | 261 | "#, |
264 | r#" | 262 | r#" |
265 | fn main() { | 263 | fn main() { |
266 | le<|>t x = match Err(92) { | 264 | let x = match Err(92) { |
267 | Ok(it) => it, | 265 | Ok(it) => it, |
268 | _ => return, | 266 | _ => return, |
269 | }; | 267 | }; |
@@ -291,7 +289,7 @@ mod tests { | |||
291 | r#" | 289 | r#" |
292 | fn main(n: Option<String>) { | 290 | fn main(n: Option<String>) { |
293 | bar(); | 291 | bar(); |
294 | le<|>t n = match n { | 292 | let n = match n { |
295 | Ok(it) => it, | 293 | Ok(it) => it, |
296 | _ => return, | 294 | _ => return, |
297 | }; | 295 | }; |
@@ -321,7 +319,7 @@ mod tests { | |||
321 | r#" | 319 | r#" |
322 | fn main() { | 320 | fn main() { |
323 | while true { | 321 | while true { |
324 | if<|> !true { | 322 | if !true { |
325 | continue; | 323 | continue; |
326 | } | 324 | } |
327 | foo(); | 325 | foo(); |
@@ -349,7 +347,7 @@ mod tests { | |||
349 | r#" | 347 | r#" |
350 | fn main() { | 348 | fn main() { |
351 | while true { | 349 | while true { |
352 | le<|>t n = match n { | 350 | let n = match n { |
353 | Some(it) => it, | 351 | Some(it) => it, |
354 | _ => continue, | 352 | _ => continue, |
355 | }; | 353 | }; |
@@ -378,7 +376,7 @@ mod tests { | |||
378 | r#" | 376 | r#" |
379 | fn main() { | 377 | fn main() { |
380 | loop { | 378 | loop { |
381 | if<|> !true { | 379 | if !true { |
382 | continue; | 380 | continue; |
383 | } | 381 | } |
384 | foo(); | 382 | foo(); |
@@ -406,7 +404,7 @@ mod tests { | |||
406 | r#" | 404 | r#" |
407 | fn main() { | 405 | fn main() { |
408 | loop { | 406 | loop { |
409 | le<|>t n = match n { | 407 | let n = match n { |
410 | Some(it) => it, | 408 | Some(it) => it, |
411 | _ => continue, | 409 | _ => continue, |
412 | }; | 410 | }; |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index b57ff75ae..cc303285b 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -4,9 +4,12 @@ use hir::{Adt, HasSource, ModuleDef, Semantics}; | |||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; | 6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; |
7 | use test_utils::tested_by; | 7 | use test_utils::mark; |
8 | 8 | ||
9 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | 9 | use crate::{ |
10 | utils::{render_snippet, Cursor, FamousDefs}, | ||
11 | AssistContext, AssistId, Assists, | ||
12 | }; | ||
10 | 13 | ||
11 | // Assist: fill_match_arms | 14 | // Assist: fill_match_arms |
12 | // | 15 | // |
@@ -27,7 +30,7 @@ use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | |||
27 | // | 30 | // |
28 | // fn handle(action: Action) { | 31 | // fn handle(action: Action) { |
29 | // match action { | 32 | // match action { |
30 | // Action::Move { distance } => {} | 33 | // $0Action::Move { distance } => {} |
31 | // Action::Stop => {} | 34 | // Action::Stop => {} |
32 | // } | 35 | // } |
33 | // } | 36 | // } |
@@ -58,7 +61,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
58 | .collect::<Vec<_>>(); | 61 | .collect::<Vec<_>>(); |
59 | if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { | 62 | if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { |
60 | // Match `Some` variant first. | 63 | // Match `Some` variant first. |
61 | tested_by!(option_order); | 64 | mark::hit!(option_order); |
62 | variants.reverse() | 65 | variants.reverse() |
63 | } | 66 | } |
64 | variants | 67 | variants |
@@ -100,10 +103,23 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
100 | } | 103 | } |
101 | 104 | ||
102 | let target = match_expr.syntax().text_range(); | 105 | let target = match_expr.syntax().text_range(); |
103 | acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { | 106 | acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |builder| { |
104 | let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); | 107 | let new_arm_list = match_arm_list.remove_placeholder(); |
105 | edit.set_cursor(expr.syntax().text_range().start()); | 108 | let n_old_arms = new_arm_list.arms().count(); |
106 | edit.replace_ast(match_arm_list, new_arm_list); | 109 | let new_arm_list = new_arm_list.append_arms(missing_arms); |
110 | let first_new_arm = new_arm_list.arms().nth(n_old_arms); | ||
111 | let old_range = match_arm_list.syntax().text_range(); | ||
112 | match (first_new_arm, ctx.config.snippet_cap) { | ||
113 | (Some(first_new_arm), Some(cap)) => { | ||
114 | let snippet = render_snippet( | ||
115 | cap, | ||
116 | new_arm_list.syntax(), | ||
117 | Cursor::Before(first_new_arm.syntax()), | ||
118 | ); | ||
119 | builder.replace_snippet(cap, old_range, snippet); | ||
120 | } | ||
121 | _ => builder.replace(old_range, new_arm_list.to_string()), | ||
122 | } | ||
107 | }) | 123 | }) |
108 | } | 124 | } |
109 | 125 | ||
@@ -174,13 +190,14 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O | |||
174 | 190 | ||
175 | #[cfg(test)] | 191 | #[cfg(test)] |
176 | mod tests { | 192 | mod tests { |
193 | use test_utils::mark; | ||
194 | |||
177 | use crate::{ | 195 | use crate::{ |
178 | tests::{check_assist, check_assist_not_applicable, check_assist_target}, | 196 | tests::{check_assist, check_assist_not_applicable, check_assist_target}, |
179 | utils::FamousDefs, | 197 | utils::FamousDefs, |
180 | }; | 198 | }; |
181 | 199 | ||
182 | use super::fill_match_arms; | 200 | use super::fill_match_arms; |
183 | use test_utils::covers; | ||
184 | 201 | ||
185 | #[test] | 202 | #[test] |
186 | fn all_match_arms_provided() { | 203 | fn all_match_arms_provided() { |
@@ -225,12 +242,12 @@ mod tests { | |||
225 | r#" | 242 | r#" |
226 | enum A { | 243 | enum A { |
227 | As, | 244 | As, |
228 | Bs{x:i32, y:Option<i32>}, | 245 | Bs { x: i32, y: Option<i32> }, |
229 | Cs(i32, Option<i32>), | 246 | Cs(i32, Option<i32>), |
230 | } | 247 | } |
231 | fn main() { | 248 | fn main() { |
232 | match A::As<|> { | 249 | match A::As<|> { |
233 | A::Bs{x,y:Some(_)} => {} | 250 | A::Bs { x, y: Some(_) } => {} |
234 | A::Cs(_, Some(_)) => {} | 251 | A::Cs(_, Some(_)) => {} |
235 | } | 252 | } |
236 | } | 253 | } |
@@ -238,14 +255,14 @@ mod tests { | |||
238 | r#" | 255 | r#" |
239 | enum A { | 256 | enum A { |
240 | As, | 257 | As, |
241 | Bs{x:i32, y:Option<i32>}, | 258 | Bs { x: i32, y: Option<i32> }, |
242 | Cs(i32, Option<i32>), | 259 | Cs(i32, Option<i32>), |
243 | } | 260 | } |
244 | fn main() { | 261 | fn main() { |
245 | match <|>A::As { | 262 | match A::As { |
246 | A::Bs{x,y:Some(_)} => {} | 263 | A::Bs { x, y: Some(_) } => {} |
247 | A::Cs(_, Some(_)) => {} | 264 | A::Cs(_, Some(_)) => {} |
248 | A::As => {} | 265 | $0A::As => {} |
249 | } | 266 | } |
250 | } | 267 | } |
251 | "#, | 268 | "#, |
@@ -275,9 +292,9 @@ mod tests { | |||
275 | Cs(Option<i32>), | 292 | Cs(Option<i32>), |
276 | } | 293 | } |
277 | fn main() { | 294 | fn main() { |
278 | match <|>A::As { | 295 | match A::As { |
279 | A::Cs(_) | A::Bs => {} | 296 | A::Cs(_) | A::Bs => {} |
280 | A::As => {} | 297 | $0A::As => {} |
281 | } | 298 | } |
282 | } | 299 | } |
283 | "#, | 300 | "#, |
@@ -321,11 +338,11 @@ mod tests { | |||
321 | Ys, | 338 | Ys, |
322 | } | 339 | } |
323 | fn main() { | 340 | fn main() { |
324 | match <|>A::As { | 341 | match A::As { |
325 | A::Bs if 0 < 1 => {} | 342 | A::Bs if 0 < 1 => {} |
326 | A::Ds(_value) => { let x = 1; } | 343 | A::Ds(_value) => { let x = 1; } |
327 | A::Es(B::Xs) => (), | 344 | A::Es(B::Xs) => (), |
328 | A::As => {} | 345 | $0A::As => {} |
329 | A::Cs => {} | 346 | A::Cs => {} |
330 | } | 347 | } |
331 | } | 348 | } |
@@ -343,7 +360,7 @@ mod tests { | |||
343 | Bs, | 360 | Bs, |
344 | Cs(String), | 361 | Cs(String), |
345 | Ds(String, String), | 362 | Ds(String, String), |
346 | Es{ x: usize, y: usize } | 363 | Es { x: usize, y: usize } |
347 | } | 364 | } |
348 | 365 | ||
349 | fn main() { | 366 | fn main() { |
@@ -357,13 +374,13 @@ mod tests { | |||
357 | Bs, | 374 | Bs, |
358 | Cs(String), | 375 | Cs(String), |
359 | Ds(String, String), | 376 | Ds(String, String), |
360 | Es{ x: usize, y: usize } | 377 | Es { x: usize, y: usize } |
361 | } | 378 | } |
362 | 379 | ||
363 | fn main() { | 380 | fn main() { |
364 | let a = A::As; | 381 | let a = A::As; |
365 | match <|>a { | 382 | match a { |
366 | A::As => {} | 383 | $0A::As => {} |
367 | A::Bs => {} | 384 | A::Bs => {} |
368 | A::Cs(_) => {} | 385 | A::Cs(_) => {} |
369 | A::Ds(_, _) => {} | 386 | A::Ds(_, _) => {} |
@@ -379,14 +396,8 @@ mod tests { | |||
379 | check_assist( | 396 | check_assist( |
380 | fill_match_arms, | 397 | fill_match_arms, |
381 | r#" | 398 | r#" |
382 | enum A { | 399 | enum A { One, Two } |
383 | One, | 400 | enum B { One, Two } |
384 | Two, | ||
385 | } | ||
386 | enum B { | ||
387 | One, | ||
388 | Two, | ||
389 | } | ||
390 | 401 | ||
391 | fn main() { | 402 | fn main() { |
392 | let a = A::One; | 403 | let a = A::One; |
@@ -395,20 +406,14 @@ mod tests { | |||
395 | } | 406 | } |
396 | "#, | 407 | "#, |
397 | r#" | 408 | r#" |
398 | enum A { | 409 | enum A { One, Two } |
399 | One, | 410 | enum B { One, Two } |
400 | Two, | ||
401 | } | ||
402 | enum B { | ||
403 | One, | ||
404 | Two, | ||
405 | } | ||
406 | 411 | ||
407 | fn main() { | 412 | fn main() { |
408 | let a = A::One; | 413 | let a = A::One; |
409 | let b = B::One; | 414 | let b = B::One; |
410 | match <|>(a, b) { | 415 | match (a, b) { |
411 | (A::One, B::One) => {} | 416 | $0(A::One, B::One) => {} |
412 | (A::One, B::Two) => {} | 417 | (A::One, B::Two) => {} |
413 | (A::Two, B::One) => {} | 418 | (A::Two, B::One) => {} |
414 | (A::Two, B::Two) => {} | 419 | (A::Two, B::Two) => {} |
@@ -423,14 +428,8 @@ mod tests { | |||
423 | check_assist( | 428 | check_assist( |
424 | fill_match_arms, | 429 | fill_match_arms, |
425 | r#" | 430 | r#" |
426 | enum A { | 431 | enum A { One, Two } |
427 | One, | 432 | enum B { One, Two } |
428 | Two, | ||
429 | } | ||
430 | enum B { | ||
431 | One, | ||
432 | Two, | ||
433 | } | ||
434 | 433 | ||
435 | fn main() { | 434 | fn main() { |
436 | let a = A::One; | 435 | let a = A::One; |
@@ -439,20 +438,14 @@ mod tests { | |||
439 | } | 438 | } |
440 | "#, | 439 | "#, |
441 | r#" | 440 | r#" |
442 | enum A { | 441 | enum A { One, Two } |
443 | One, | 442 | enum B { One, Two } |
444 | Two, | ||
445 | } | ||
446 | enum B { | ||
447 | One, | ||
448 | Two, | ||
449 | } | ||
450 | 443 | ||
451 | fn main() { | 444 | fn main() { |
452 | let a = A::One; | 445 | let a = A::One; |
453 | let b = B::One; | 446 | let b = B::One; |
454 | match <|>(&a, &b) { | 447 | match (&a, &b) { |
455 | (A::One, B::One) => {} | 448 | $0(A::One, B::One) => {} |
456 | (A::One, B::Two) => {} | 449 | (A::One, B::Two) => {} |
457 | (A::Two, B::One) => {} | 450 | (A::Two, B::One) => {} |
458 | (A::Two, B::Two) => {} | 451 | (A::Two, B::Two) => {} |
@@ -467,14 +460,8 @@ mod tests { | |||
467 | check_assist_not_applicable( | 460 | check_assist_not_applicable( |
468 | fill_match_arms, | 461 | fill_match_arms, |
469 | r#" | 462 | r#" |
470 | enum A { | 463 | enum A { One, Two } |
471 | One, | 464 | enum B { One, Two } |
472 | Two, | ||
473 | } | ||
474 | enum B { | ||
475 | One, | ||
476 | Two, | ||
477 | } | ||
478 | 465 | ||
479 | fn main() { | 466 | fn main() { |
480 | let a = A::One; | 467 | let a = A::One; |
@@ -492,14 +479,8 @@ mod tests { | |||
492 | check_assist_not_applicable( | 479 | check_assist_not_applicable( |
493 | fill_match_arms, | 480 | fill_match_arms, |
494 | r#" | 481 | r#" |
495 | enum A { | 482 | enum A { One, Two } |
496 | One, | 483 | enum B { One, Two } |
497 | Two, | ||
498 | } | ||
499 | enum B { | ||
500 | One, | ||
501 | Two, | ||
502 | } | ||
503 | 484 | ||
504 | fn main() { | 485 | fn main() { |
505 | let a = A::One; | 486 | let a = A::One; |
@@ -523,10 +504,7 @@ mod tests { | |||
523 | check_assist_not_applicable( | 504 | check_assist_not_applicable( |
524 | fill_match_arms, | 505 | fill_match_arms, |
525 | r#" | 506 | r#" |
526 | enum A { | 507 | enum A { One, Two } |
527 | One, | ||
528 | Two, | ||
529 | } | ||
530 | 508 | ||
531 | fn main() { | 509 | fn main() { |
532 | let a = A::One; | 510 | let a = A::One; |
@@ -542,9 +520,7 @@ mod tests { | |||
542 | check_assist( | 520 | check_assist( |
543 | fill_match_arms, | 521 | fill_match_arms, |
544 | r#" | 522 | r#" |
545 | enum A { | 523 | enum A { As } |
546 | As, | ||
547 | } | ||
548 | 524 | ||
549 | fn foo(a: &A) { | 525 | fn foo(a: &A) { |
550 | match a<|> { | 526 | match a<|> { |
@@ -552,13 +528,11 @@ mod tests { | |||
552 | } | 528 | } |
553 | "#, | 529 | "#, |
554 | r#" | 530 | r#" |
555 | enum A { | 531 | enum A { As } |
556 | As, | ||
557 | } | ||
558 | 532 | ||
559 | fn foo(a: &A) { | 533 | fn foo(a: &A) { |
560 | match <|>a { | 534 | match a { |
561 | A::As => {} | 535 | $0A::As => {} |
562 | } | 536 | } |
563 | } | 537 | } |
564 | "#, | 538 | "#, |
@@ -568,7 +542,7 @@ mod tests { | |||
568 | fill_match_arms, | 542 | fill_match_arms, |
569 | r#" | 543 | r#" |
570 | enum A { | 544 | enum A { |
571 | Es{ x: usize, y: usize } | 545 | Es { x: usize, y: usize } |
572 | } | 546 | } |
573 | 547 | ||
574 | fn foo(a: &mut A) { | 548 | fn foo(a: &mut A) { |
@@ -578,12 +552,12 @@ mod tests { | |||
578 | "#, | 552 | "#, |
579 | r#" | 553 | r#" |
580 | enum A { | 554 | enum A { |
581 | Es{ x: usize, y: usize } | 555 | Es { x: usize, y: usize } |
582 | } | 556 | } |
583 | 557 | ||
584 | fn foo(a: &mut A) { | 558 | fn foo(a: &mut A) { |
585 | match <|>a { | 559 | match a { |
586 | A::Es { x, y } => {} | 560 | $0A::Es { x, y } => {} |
587 | } | 561 | } |
588 | } | 562 | } |
589 | "#, | 563 | "#, |
@@ -622,8 +596,8 @@ mod tests { | |||
622 | enum E { X, Y } | 596 | enum E { X, Y } |
623 | 597 | ||
624 | fn main() { | 598 | fn main() { |
625 | match <|>E::X { | 599 | match E::X { |
626 | E::X => {} | 600 | $0E::X => {} |
627 | E::Y => {} | 601 | E::Y => {} |
628 | } | 602 | } |
629 | } | 603 | } |
@@ -650,8 +624,8 @@ mod tests { | |||
650 | use foo::E::X; | 624 | use foo::E::X; |
651 | 625 | ||
652 | fn main() { | 626 | fn main() { |
653 | match <|>X { | 627 | match X { |
654 | X => {} | 628 | $0X => {} |
655 | foo::E::Y => {} | 629 | foo::E::Y => {} |
656 | } | 630 | } |
657 | } | 631 | } |
@@ -664,10 +638,7 @@ mod tests { | |||
664 | check_assist( | 638 | check_assist( |
665 | fill_match_arms, | 639 | fill_match_arms, |
666 | r#" | 640 | r#" |
667 | enum A { | 641 | enum A { One, Two } |
668 | One, | ||
669 | Two, | ||
670 | } | ||
671 | fn foo(a: A) { | 642 | fn foo(a: A) { |
672 | match a { | 643 | match a { |
673 | // foo bar baz<|> | 644 | // foo bar baz<|> |
@@ -677,16 +648,13 @@ mod tests { | |||
677 | } | 648 | } |
678 | "#, | 649 | "#, |
679 | r#" | 650 | r#" |
680 | enum A { | 651 | enum A { One, Two } |
681 | One, | ||
682 | Two, | ||
683 | } | ||
684 | fn foo(a: A) { | 652 | fn foo(a: A) { |
685 | match <|>a { | 653 | match a { |
686 | // foo bar baz | 654 | // foo bar baz |
687 | A::One => {} | 655 | A::One => {} |
688 | // This is where the rest should be | 656 | // This is where the rest should be |
689 | A::Two => {} | 657 | $0A::Two => {} |
690 | } | 658 | } |
691 | } | 659 | } |
692 | "#, | 660 | "#, |
@@ -698,10 +666,7 @@ mod tests { | |||
698 | check_assist( | 666 | check_assist( |
699 | fill_match_arms, | 667 | fill_match_arms, |
700 | r#" | 668 | r#" |
701 | enum A { | 669 | enum A { One, Two } |
702 | One, | ||
703 | Two, | ||
704 | } | ||
705 | fn foo(a: A) { | 670 | fn foo(a: A) { |
706 | match a { | 671 | match a { |
707 | // foo bar baz<|> | 672 | // foo bar baz<|> |
@@ -709,14 +674,11 @@ mod tests { | |||
709 | } | 674 | } |
710 | "#, | 675 | "#, |
711 | r#" | 676 | r#" |
712 | enum A { | 677 | enum A { One, Two } |
713 | One, | ||
714 | Two, | ||
715 | } | ||
716 | fn foo(a: A) { | 678 | fn foo(a: A) { |
717 | match <|>a { | 679 | match a { |
718 | // foo bar baz | 680 | // foo bar baz |
719 | A::One => {} | 681 | $0A::One => {} |
720 | A::Two => {} | 682 | A::Two => {} |
721 | } | 683 | } |
722 | } | 684 | } |
@@ -739,8 +701,8 @@ mod tests { | |||
739 | r#" | 701 | r#" |
740 | enum A { One, Two, } | 702 | enum A { One, Two, } |
741 | fn foo(a: A) { | 703 | fn foo(a: A) { |
742 | match <|>a { | 704 | match a { |
743 | A::One => {} | 705 | $0A::One => {} |
744 | A::Two => {} | 706 | A::Two => {} |
745 | } | 707 | } |
746 | } | 708 | } |
@@ -750,7 +712,7 @@ mod tests { | |||
750 | 712 | ||
751 | #[test] | 713 | #[test] |
752 | fn option_order() { | 714 | fn option_order() { |
753 | covers!(option_order); | 715 | mark::check!(option_order); |
754 | let before = r#" | 716 | let before = r#" |
755 | fn foo(opt: Option<i32>) { | 717 | fn foo(opt: Option<i32>) { |
756 | match opt<|> { | 718 | match opt<|> { |
@@ -764,8 +726,8 @@ fn foo(opt: Option<i32>) { | |||
764 | before, | 726 | before, |
765 | r#" | 727 | r#" |
766 | fn foo(opt: Option<i32>) { | 728 | fn foo(opt: Option<i32>) { |
767 | match <|>opt { | 729 | match opt { |
768 | Some(_) => {} | 730 | $0Some(_) => {} |
769 | None => {} | 731 | None => {} |
770 | } | 732 | } |
771 | } | 733 | } |
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs new file mode 100644 index 000000000..9ec42f568 --- /dev/null +++ b/crates/ra_assists/src/handlers/fix_visibility.rs | |||
@@ -0,0 +1,559 @@ | |||
1 | use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; | ||
2 | use ra_db::FileId; | ||
3 | use ra_syntax::{ | ||
4 | ast, AstNode, | ||
5 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | ||
6 | SyntaxNode, TextRange, TextSize, | ||
7 | }; | ||
8 | |||
9 | use crate::{AssistContext, AssistId, Assists}; | ||
10 | |||
11 | // FIXME: this really should be a fix for diagnostic, rather than an assist. | ||
12 | |||
13 | // Assist: fix_visibility | ||
14 | // | ||
15 | // Makes inaccessible item public. | ||
16 | // | ||
17 | // ``` | ||
18 | // mod m { | ||
19 | // fn frobnicate() {} | ||
20 | // } | ||
21 | // fn main() { | ||
22 | // m::frobnicate<|>() {} | ||
23 | // } | ||
24 | // ``` | ||
25 | // -> | ||
26 | // ``` | ||
27 | // mod m { | ||
28 | // $0pub(crate) fn frobnicate() {} | ||
29 | // } | ||
30 | // fn main() { | ||
31 | // m::frobnicate() {} | ||
32 | // } | ||
33 | // ``` | ||
34 | pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
35 | add_vis_to_referenced_module_def(acc, ctx) | ||
36 | .or_else(|| add_vis_to_referenced_record_field(acc, ctx)) | ||
37 | } | ||
38 | |||
39 | fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
40 | let path: ast::Path = ctx.find_node_at_offset()?; | ||
41 | let path_res = ctx.sema.resolve_path(&path)?; | ||
42 | let def = match path_res { | ||
43 | PathResolution::Def(def) => def, | ||
44 | _ => return None, | ||
45 | }; | ||
46 | |||
47 | let current_module = ctx.sema.scope(&path.syntax()).module()?; | ||
48 | let target_module = def.module(ctx.db)?; | ||
49 | |||
50 | let vis = target_module.visibility_of(ctx.db, &def)?; | ||
51 | if vis.is_visible_from(ctx.db, current_module.into()) { | ||
52 | return None; | ||
53 | }; | ||
54 | |||
55 | let (offset, target, target_file, target_name) = target_data_for_def(ctx.db, def)?; | ||
56 | |||
57 | let missing_visibility = | ||
58 | if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; | ||
59 | |||
60 | let assist_label = match target_name { | ||
61 | None => format!("Change visibility to {}", missing_visibility), | ||
62 | Some(name) => format!("Change visibility of {} to {}", name, missing_visibility), | ||
63 | }; | ||
64 | |||
65 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { | ||
66 | builder.set_file(target_file); | ||
67 | match ctx.config.snippet_cap { | ||
68 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | ||
69 | None => builder.insert(offset, format!("{} ", missing_visibility)), | ||
70 | } | ||
71 | }) | ||
72 | } | ||
73 | |||
74 | fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
75 | let record_field: ast::RecordField = ctx.find_node_at_offset()?; | ||
76 | let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; | ||
77 | |||
78 | let current_module = ctx.sema.scope(record_field.syntax()).module()?; | ||
79 | let visibility = record_field_def.visibility(ctx.db); | ||
80 | if visibility.is_visible_from(ctx.db, current_module.into()) { | ||
81 | return None; | ||
82 | } | ||
83 | |||
84 | let parent = record_field_def.parent_def(ctx.db); | ||
85 | let parent_name = parent.name(ctx.db); | ||
86 | let target_module = parent.module(ctx.db); | ||
87 | |||
88 | let in_file_source = record_field_def.source(ctx.db); | ||
89 | let (offset, target) = match in_file_source.value { | ||
90 | hir::FieldSource::Named(it) => { | ||
91 | let s = it.syntax(); | ||
92 | (vis_offset(s), s.text_range()) | ||
93 | } | ||
94 | hir::FieldSource::Pos(it) => { | ||
95 | let s = it.syntax(); | ||
96 | (vis_offset(s), s.text_range()) | ||
97 | } | ||
98 | }; | ||
99 | |||
100 | let missing_visibility = | ||
101 | if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; | ||
102 | let target_file = in_file_source.file_id.original_file(ctx.db); | ||
103 | |||
104 | let target_name = record_field_def.name(ctx.db); | ||
105 | let assist_label = | ||
106 | format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); | ||
107 | |||
108 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { | ||
109 | builder.set_file(target_file); | ||
110 | match ctx.config.snippet_cap { | ||
111 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | ||
112 | None => builder.insert(offset, format!("{} ", missing_visibility)), | ||
113 | } | ||
114 | }) | ||
115 | } | ||
116 | |||
117 | fn target_data_for_def( | ||
118 | db: &dyn HirDatabase, | ||
119 | def: hir::ModuleDef, | ||
120 | ) -> Option<(TextSize, TextRange, FileId, Option<hir::Name>)> { | ||
121 | fn offset_target_and_file_id<S, Ast>( | ||
122 | db: &dyn HirDatabase, | ||
123 | x: S, | ||
124 | ) -> (TextSize, TextRange, FileId) | ||
125 | where | ||
126 | S: HasSource<Ast = Ast>, | ||
127 | Ast: AstNode, | ||
128 | { | ||
129 | let source = x.source(db); | ||
130 | let in_file_syntax = source.syntax(); | ||
131 | let file_id = in_file_syntax.file_id; | ||
132 | let syntax = in_file_syntax.value; | ||
133 | (vis_offset(syntax), syntax.text_range(), file_id.original_file(db.upcast())) | ||
134 | } | ||
135 | |||
136 | let target_name; | ||
137 | let (offset, target, target_file) = match def { | ||
138 | hir::ModuleDef::Function(f) => { | ||
139 | target_name = Some(f.name(db)); | ||
140 | offset_target_and_file_id(db, f) | ||
141 | } | ||
142 | hir::ModuleDef::Adt(adt) => { | ||
143 | target_name = Some(adt.name(db)); | ||
144 | match adt { | ||
145 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s), | ||
146 | hir::Adt::Union(u) => offset_target_and_file_id(db, u), | ||
147 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e), | ||
148 | } | ||
149 | } | ||
150 | hir::ModuleDef::Const(c) => { | ||
151 | target_name = c.name(db); | ||
152 | offset_target_and_file_id(db, c) | ||
153 | } | ||
154 | hir::ModuleDef::Static(s) => { | ||
155 | target_name = s.name(db); | ||
156 | offset_target_and_file_id(db, s) | ||
157 | } | ||
158 | hir::ModuleDef::Trait(t) => { | ||
159 | target_name = Some(t.name(db)); | ||
160 | offset_target_and_file_id(db, t) | ||
161 | } | ||
162 | hir::ModuleDef::TypeAlias(t) => { | ||
163 | target_name = Some(t.name(db)); | ||
164 | offset_target_and_file_id(db, t) | ||
165 | } | ||
166 | hir::ModuleDef::Module(m) => { | ||
167 | target_name = m.name(db); | ||
168 | let in_file_source = m.declaration_source(db)?; | ||
169 | let file_id = in_file_source.file_id.original_file(db.upcast()); | ||
170 | let syntax = in_file_source.value.syntax(); | ||
171 | (vis_offset(syntax), syntax.text_range(), file_id) | ||
172 | } | ||
173 | // Enum variants can't be private, we can't modify builtin types | ||
174 | hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None, | ||
175 | }; | ||
176 | |||
177 | Some((offset, target, target_file, target_name)) | ||
178 | } | ||
179 | |||
180 | fn vis_offset(node: &SyntaxNode) -> TextSize { | ||
181 | node.children_with_tokens() | ||
182 | .skip_while(|it| match it.kind() { | ||
183 | WHITESPACE | COMMENT | ATTR => true, | ||
184 | _ => false, | ||
185 | }) | ||
186 | .next() | ||
187 | .map(|it| it.text_range().start()) | ||
188 | .unwrap_or_else(|| node.text_range().start()) | ||
189 | } | ||
190 | |||
191 | #[cfg(test)] | ||
192 | mod tests { | ||
193 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
194 | |||
195 | use super::*; | ||
196 | |||
197 | #[test] | ||
198 | fn fix_visibility_of_fn() { | ||
199 | check_assist( | ||
200 | fix_visibility, | ||
201 | r"mod foo { fn foo() {} } | ||
202 | fn main() { foo::foo<|>() } ", | ||
203 | r"mod foo { $0pub(crate) fn foo() {} } | ||
204 | fn main() { foo::foo() } ", | ||
205 | ); | ||
206 | check_assist_not_applicable( | ||
207 | fix_visibility, | ||
208 | r"mod foo { pub fn foo() {} } | ||
209 | fn main() { foo::foo<|>() } ", | ||
210 | ) | ||
211 | } | ||
212 | |||
213 | #[test] | ||
214 | fn fix_visibility_of_adt_in_submodule() { | ||
215 | check_assist( | ||
216 | fix_visibility, | ||
217 | r"mod foo { struct Foo; } | ||
218 | fn main() { foo::Foo<|> } ", | ||
219 | r"mod foo { $0pub(crate) struct Foo; } | ||
220 | fn main() { foo::Foo } ", | ||
221 | ); | ||
222 | check_assist_not_applicable( | ||
223 | fix_visibility, | ||
224 | r"mod foo { pub struct Foo; } | ||
225 | fn main() { foo::Foo<|> } ", | ||
226 | ); | ||
227 | check_assist( | ||
228 | fix_visibility, | ||
229 | r"mod foo { enum Foo; } | ||
230 | fn main() { foo::Foo<|> } ", | ||
231 | r"mod foo { $0pub(crate) enum Foo; } | ||
232 | fn main() { foo::Foo } ", | ||
233 | ); | ||
234 | check_assist_not_applicable( | ||
235 | fix_visibility, | ||
236 | r"mod foo { pub enum Foo; } | ||
237 | fn main() { foo::Foo<|> } ", | ||
238 | ); | ||
239 | check_assist( | ||
240 | fix_visibility, | ||
241 | r"mod foo { union Foo; } | ||
242 | fn main() { foo::Foo<|> } ", | ||
243 | r"mod foo { $0pub(crate) union Foo; } | ||
244 | fn main() { foo::Foo } ", | ||
245 | ); | ||
246 | check_assist_not_applicable( | ||
247 | fix_visibility, | ||
248 | r"mod foo { pub union Foo; } | ||
249 | fn main() { foo::Foo<|> } ", | ||
250 | ); | ||
251 | } | ||
252 | |||
253 | #[test] | ||
254 | fn fix_visibility_of_adt_in_other_file() { | ||
255 | check_assist( | ||
256 | fix_visibility, | ||
257 | r" | ||
258 | //- /main.rs | ||
259 | mod foo; | ||
260 | fn main() { foo::Foo<|> } | ||
261 | |||
262 | //- /foo.rs | ||
263 | struct Foo; | ||
264 | ", | ||
265 | r"$0pub(crate) struct Foo; | ||
266 | |||
267 | ", | ||
268 | ); | ||
269 | } | ||
270 | |||
271 | #[test] | ||
272 | fn fix_visibility_of_struct_field() { | ||
273 | check_assist( | ||
274 | fix_visibility, | ||
275 | r"mod foo { pub struct Foo { bar: (), } } | ||
276 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
277 | r"mod foo { pub struct Foo { $0pub(crate) bar: (), } } | ||
278 | fn main() { foo::Foo { bar: () }; } ", | ||
279 | ); | ||
280 | check_assist( | ||
281 | fix_visibility, | ||
282 | r"//- /lib.rs | ||
283 | mod foo; | ||
284 | fn main() { foo::Foo { <|>bar: () }; } | ||
285 | //- /foo.rs | ||
286 | pub struct Foo { bar: () } | ||
287 | ", | ||
288 | r"pub struct Foo { $0pub(crate) bar: () } | ||
289 | |||
290 | ", | ||
291 | ); | ||
292 | check_assist_not_applicable( | ||
293 | fix_visibility, | ||
294 | r"mod foo { pub struct Foo { pub bar: (), } } | ||
295 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
296 | ); | ||
297 | check_assist_not_applicable( | ||
298 | fix_visibility, | ||
299 | r"//- /lib.rs | ||
300 | mod foo; | ||
301 | fn main() { foo::Foo { <|>bar: () }; } | ||
302 | //- /foo.rs | ||
303 | pub struct Foo { pub bar: () } | ||
304 | ", | ||
305 | ); | ||
306 | } | ||
307 | |||
308 | #[test] | ||
309 | fn fix_visibility_of_enum_variant_field() { | ||
310 | check_assist( | ||
311 | fix_visibility, | ||
312 | r"mod foo { pub enum Foo { Bar { bar: () } } } | ||
313 | fn main() { foo::Foo::Bar { <|>bar: () }; } ", | ||
314 | r"mod foo { pub enum Foo { Bar { $0pub(crate) bar: () } } } | ||
315 | fn main() { foo::Foo::Bar { bar: () }; } ", | ||
316 | ); | ||
317 | check_assist( | ||
318 | fix_visibility, | ||
319 | r"//- /lib.rs | ||
320 | mod foo; | ||
321 | fn main() { foo::Foo::Bar { <|>bar: () }; } | ||
322 | //- /foo.rs | ||
323 | pub enum Foo { Bar { bar: () } } | ||
324 | ", | ||
325 | r"pub enum Foo { Bar { $0pub(crate) bar: () } } | ||
326 | |||
327 | ", | ||
328 | ); | ||
329 | check_assist_not_applicable( | ||
330 | fix_visibility, | ||
331 | r"mod foo { pub struct Foo { pub bar: (), } } | ||
332 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
333 | ); | ||
334 | check_assist_not_applicable( | ||
335 | fix_visibility, | ||
336 | r"//- /lib.rs | ||
337 | mod foo; | ||
338 | fn main() { foo::Foo { <|>bar: () }; } | ||
339 | //- /foo.rs | ||
340 | pub struct Foo { pub bar: () } | ||
341 | ", | ||
342 | ); | ||
343 | } | ||
344 | |||
345 | #[test] | ||
346 | #[ignore] | ||
347 | // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields | ||
348 | fn fix_visibility_of_union_field() { | ||
349 | check_assist( | ||
350 | fix_visibility, | ||
351 | r"mod foo { pub union Foo { bar: (), } } | ||
352 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
353 | r"mod foo { pub union Foo { $0pub(crate) bar: (), } } | ||
354 | fn main() { foo::Foo { bar: () }; } ", | ||
355 | ); | ||
356 | check_assist( | ||
357 | fix_visibility, | ||
358 | r"//- /lib.rs | ||
359 | mod foo; | ||
360 | fn main() { foo::Foo { <|>bar: () }; } | ||
361 | //- /foo.rs | ||
362 | pub union Foo { bar: () } | ||
363 | ", | ||
364 | r"pub union Foo { $0pub(crate) bar: () } | ||
365 | |||
366 | ", | ||
367 | ); | ||
368 | check_assist_not_applicable( | ||
369 | fix_visibility, | ||
370 | r"mod foo { pub union Foo { pub bar: (), } } | ||
371 | fn main() { foo::Foo { <|>bar: () }; } ", | ||
372 | ); | ||
373 | check_assist_not_applicable( | ||
374 | fix_visibility, | ||
375 | r"//- /lib.rs | ||
376 | mod foo; | ||
377 | fn main() { foo::Foo { <|>bar: () }; } | ||
378 | //- /foo.rs | ||
379 | pub union Foo { pub bar: () } | ||
380 | ", | ||
381 | ); | ||
382 | } | ||
383 | |||
384 | #[test] | ||
385 | fn fix_visibility_of_const() { | ||
386 | check_assist( | ||
387 | fix_visibility, | ||
388 | r"mod foo { const FOO: () = (); } | ||
389 | fn main() { foo::FOO<|> } ", | ||
390 | r"mod foo { $0pub(crate) const FOO: () = (); } | ||
391 | fn main() { foo::FOO } ", | ||
392 | ); | ||
393 | check_assist_not_applicable( | ||
394 | fix_visibility, | ||
395 | r"mod foo { pub const FOO: () = (); } | ||
396 | fn main() { foo::FOO<|> } ", | ||
397 | ); | ||
398 | } | ||
399 | |||
400 | #[test] | ||
401 | fn fix_visibility_of_static() { | ||
402 | check_assist( | ||
403 | fix_visibility, | ||
404 | r"mod foo { static FOO: () = (); } | ||
405 | fn main() { foo::FOO<|> } ", | ||
406 | r"mod foo { $0pub(crate) static FOO: () = (); } | ||
407 | fn main() { foo::FOO } ", | ||
408 | ); | ||
409 | check_assist_not_applicable( | ||
410 | fix_visibility, | ||
411 | r"mod foo { pub static FOO: () = (); } | ||
412 | fn main() { foo::FOO<|> } ", | ||
413 | ); | ||
414 | } | ||
415 | |||
416 | #[test] | ||
417 | fn fix_visibility_of_trait() { | ||
418 | check_assist( | ||
419 | fix_visibility, | ||
420 | r"mod foo { trait Foo { fn foo(&self) {} } } | ||
421 | fn main() { let x: &dyn foo::<|>Foo; } ", | ||
422 | r"mod foo { $0pub(crate) trait Foo { fn foo(&self) {} } } | ||
423 | fn main() { let x: &dyn foo::Foo; } ", | ||
424 | ); | ||
425 | check_assist_not_applicable( | ||
426 | fix_visibility, | ||
427 | r"mod foo { pub trait Foo { fn foo(&self) {} } } | ||
428 | fn main() { let x: &dyn foo::Foo<|>; } ", | ||
429 | ); | ||
430 | } | ||
431 | |||
432 | #[test] | ||
433 | fn fix_visibility_of_type_alias() { | ||
434 | check_assist( | ||
435 | fix_visibility, | ||
436 | r"mod foo { type Foo = (); } | ||
437 | fn main() { let x: foo::Foo<|>; } ", | ||
438 | r"mod foo { $0pub(crate) type Foo = (); } | ||
439 | fn main() { let x: foo::Foo; } ", | ||
440 | ); | ||
441 | check_assist_not_applicable( | ||
442 | fix_visibility, | ||
443 | r"mod foo { pub type Foo = (); } | ||
444 | fn main() { let x: foo::Foo<|>; } ", | ||
445 | ); | ||
446 | } | ||
447 | |||
448 | #[test] | ||
449 | fn fix_visibility_of_module() { | ||
450 | check_assist( | ||
451 | fix_visibility, | ||
452 | r"mod foo { mod bar { fn bar() {} } } | ||
453 | fn main() { foo::bar<|>::bar(); } ", | ||
454 | r"mod foo { $0pub(crate) mod bar { fn bar() {} } } | ||
455 | fn main() { foo::bar::bar(); } ", | ||
456 | ); | ||
457 | |||
458 | check_assist( | ||
459 | fix_visibility, | ||
460 | r" | ||
461 | //- /main.rs | ||
462 | mod foo; | ||
463 | fn main() { foo::bar<|>::baz(); } | ||
464 | |||
465 | //- /foo.rs | ||
466 | mod bar { | ||
467 | pub fn baz() {} | ||
468 | } | ||
469 | ", | ||
470 | r"$0pub(crate) mod bar { | ||
471 | pub fn baz() {} | ||
472 | } | ||
473 | |||
474 | ", | ||
475 | ); | ||
476 | |||
477 | check_assist_not_applicable( | ||
478 | fix_visibility, | ||
479 | r"mod foo { pub mod bar { pub fn bar() {} } } | ||
480 | fn main() { foo::bar<|>::bar(); } ", | ||
481 | ); | ||
482 | } | ||
483 | |||
484 | #[test] | ||
485 | fn fix_visibility_of_inline_module_in_other_file() { | ||
486 | check_assist( | ||
487 | fix_visibility, | ||
488 | r" | ||
489 | //- /main.rs | ||
490 | mod foo; | ||
491 | fn main() { foo::bar<|>::baz(); } | ||
492 | |||
493 | //- /foo.rs | ||
494 | mod bar; | ||
495 | |||
496 | //- /foo/bar.rs | ||
497 | pub fn baz() {} | ||
498 | } | ||
499 | ", | ||
500 | r"$0pub(crate) mod bar; | ||
501 | ", | ||
502 | ); | ||
503 | } | ||
504 | |||
505 | #[test] | ||
506 | fn fix_visibility_of_module_declaration_in_other_file() { | ||
507 | check_assist( | ||
508 | fix_visibility, | ||
509 | r"//- /main.rs | ||
510 | mod foo; | ||
511 | fn main() { foo::bar<|>>::baz(); } | ||
512 | |||
513 | //- /foo.rs | ||
514 | mod bar { | ||
515 | pub fn baz() {} | ||
516 | }", | ||
517 | r"$0pub(crate) mod bar { | ||
518 | pub fn baz() {} | ||
519 | } | ||
520 | ", | ||
521 | ); | ||
522 | } | ||
523 | |||
524 | #[test] | ||
525 | fn adds_pub_when_target_is_in_another_crate() { | ||
526 | check_assist( | ||
527 | fix_visibility, | ||
528 | r"//- /main.rs crate:a deps:foo | ||
529 | foo::Bar<|> | ||
530 | //- /lib.rs crate:foo | ||
531 | struct Bar;", | ||
532 | r"$0pub struct Bar; | ||
533 | ", | ||
534 | ) | ||
535 | } | ||
536 | |||
537 | #[test] | ||
538 | #[ignore] | ||
539 | // FIXME handle reexports properly | ||
540 | fn fix_visibility_of_reexport() { | ||
541 | check_assist( | ||
542 | fix_visibility, | ||
543 | r" | ||
544 | mod foo { | ||
545 | use bar::Baz; | ||
546 | mod bar { pub(super) struct Baz; } | ||
547 | } | ||
548 | foo::Baz<|> | ||
549 | ", | ||
550 | r" | ||
551 | mod foo { | ||
552 | $0pub(crate) use bar::Baz; | ||
553 | mod bar { pub(super) struct Baz; } | ||
554 | } | ||
555 | foo::Baz | ||
556 | ", | ||
557 | ) | ||
558 | } | ||
559 | } | ||
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs index 692ba4895..573196576 100644 --- a/crates/ra_assists/src/handlers/flip_binexpr.rs +++ b/crates/ra_assists/src/handlers/flip_binexpr.rs | |||
@@ -85,17 +85,13 @@ mod tests { | |||
85 | check_assist( | 85 | check_assist( |
86 | flip_binexpr, | 86 | flip_binexpr, |
87 | "fn f() { let res = 1 ==<|> 2; }", | 87 | "fn f() { let res = 1 ==<|> 2; }", |
88 | "fn f() { let res = 2 ==<|> 1; }", | 88 | "fn f() { let res = 2 == 1; }", |
89 | ) | 89 | ) |
90 | } | 90 | } |
91 | 91 | ||
92 | #[test] | 92 | #[test] |
93 | fn flip_binexpr_works_for_gt() { | 93 | fn flip_binexpr_works_for_gt() { |
94 | check_assist( | 94 | check_assist(flip_binexpr, "fn f() { let res = 1 ><|> 2; }", "fn f() { let res = 2 < 1; }") |
95 | flip_binexpr, | ||
96 | "fn f() { let res = 1 ><|> 2; }", | ||
97 | "fn f() { let res = 2 <<|> 1; }", | ||
98 | ) | ||
99 | } | 95 | } |
100 | 96 | ||
101 | #[test] | 97 | #[test] |
@@ -103,7 +99,7 @@ mod tests { | |||
103 | check_assist( | 99 | check_assist( |
104 | flip_binexpr, | 100 | flip_binexpr, |
105 | "fn f() { let res = 1 <=<|> 2; }", | 101 | "fn f() { let res = 1 <=<|> 2; }", |
106 | "fn f() { let res = 2 >=<|> 1; }", | 102 | "fn f() { let res = 2 >= 1; }", |
107 | ) | 103 | ) |
108 | } | 104 | } |
109 | 105 | ||
@@ -112,7 +108,7 @@ mod tests { | |||
112 | check_assist( | 108 | check_assist( |
113 | flip_binexpr, | 109 | flip_binexpr, |
114 | "fn f() { let res = (1 + 1) ==<|> (2 + 2); }", | 110 | "fn f() { let res = (1 + 1) ==<|> (2 + 2); }", |
115 | "fn f() { let res = (2 + 2) ==<|> (1 + 1); }", | 111 | "fn f() { let res = (2 + 2) == (1 + 1); }", |
116 | ) | 112 | ) |
117 | } | 113 | } |
118 | 114 | ||
@@ -132,7 +128,7 @@ mod tests { | |||
132 | fn dyn_eq(&self, other: &dyn Diagnostic) -> bool { | 128 | fn dyn_eq(&self, other: &dyn Diagnostic) -> bool { |
133 | match other.downcast_ref::<Self>() { | 129 | match other.downcast_ref::<Self>() { |
134 | None => false, | 130 | None => false, |
135 | Some(it) => self ==<|> it, | 131 | Some(it) => self == it, |
136 | } | 132 | } |
137 | } | 133 | } |
138 | "#, | 134 | "#, |
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs index dfe2a7fed..a57a1c463 100644 --- a/crates/ra_assists/src/handlers/flip_comma.rs +++ b/crates/ra_assists/src/handlers/flip_comma.rs | |||
@@ -45,7 +45,7 @@ mod tests { | |||
45 | check_assist( | 45 | check_assist( |
46 | flip_comma, | 46 | flip_comma, |
47 | "fn foo(x: i32,<|> y: Result<(), ()>) {}", | 47 | "fn foo(x: i32,<|> y: Result<(), ()>) {}", |
48 | "fn foo(y: Result<(), ()>,<|> x: i32) {}", | 48 | "fn foo(y: Result<(), ()>, x: i32) {}", |
49 | ) | 49 | ) |
50 | } | 50 | } |
51 | 51 | ||
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs index 8a08702ab..0115adc8b 100644 --- a/crates/ra_assists/src/handlers/flip_trait_bound.rs +++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs | |||
@@ -60,7 +60,7 @@ mod tests { | |||
60 | check_assist( | 60 | check_assist( |
61 | flip_trait_bound, | 61 | flip_trait_bound, |
62 | "struct S<T> where T: A <|>+ B { }", | 62 | "struct S<T> where T: A <|>+ B { }", |
63 | "struct S<T> where T: B <|>+ A { }", | 63 | "struct S<T> where T: B + A { }", |
64 | ) | 64 | ) |
65 | } | 65 | } |
66 | 66 | ||
@@ -69,13 +69,13 @@ mod tests { | |||
69 | check_assist( | 69 | check_assist( |
70 | flip_trait_bound, | 70 | flip_trait_bound, |
71 | "impl X for S<T> where T: A +<|> B { }", | 71 | "impl X for S<T> where T: A +<|> B { }", |
72 | "impl X for S<T> where T: B +<|> A { }", | 72 | "impl X for S<T> where T: B + A { }", |
73 | ) | 73 | ) |
74 | } | 74 | } |
75 | 75 | ||
76 | #[test] | 76 | #[test] |
77 | fn flip_trait_bound_works_for_fn() { | 77 | fn flip_trait_bound_works_for_fn() { |
78 | check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B <|>+ A>(t: T) { }") | 78 | check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B + A>(t: T) { }") |
79 | } | 79 | } |
80 | 80 | ||
81 | #[test] | 81 | #[test] |
@@ -83,7 +83,7 @@ mod tests { | |||
83 | check_assist( | 83 | check_assist( |
84 | flip_trait_bound, | 84 | flip_trait_bound, |
85 | "fn f<T>(t: T) where T: A +<|> B { }", | 85 | "fn f<T>(t: T) where T: A +<|> B { }", |
86 | "fn f<T>(t: T) where T: B +<|> A { }", | 86 | "fn f<T>(t: T) where T: B + A { }", |
87 | ) | 87 | ) |
88 | } | 88 | } |
89 | 89 | ||
@@ -92,7 +92,7 @@ mod tests { | |||
92 | check_assist( | 92 | check_assist( |
93 | flip_trait_bound, | 93 | flip_trait_bound, |
94 | "fn f<T>(t: T) where T: A <|>+ 'static { }", | 94 | "fn f<T>(t: T) where T: A <|>+ 'static { }", |
95 | "fn f<T>(t: T) where T: 'static <|>+ A { }", | 95 | "fn f<T>(t: T) where T: 'static + A { }", |
96 | ) | 96 | ) |
97 | } | 97 | } |
98 | 98 | ||
@@ -101,7 +101,7 @@ mod tests { | |||
101 | check_assist( | 101 | check_assist( |
102 | flip_trait_bound, | 102 | flip_trait_bound, |
103 | "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }", | 103 | "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }", |
104 | "struct S<T> where T: b_mod::B<T> <|>+ A<T> + C<T> { }", | 104 | "struct S<T> where T: b_mod::B<T> + A<T> + C<T> { }", |
105 | ) | 105 | ) |
106 | } | 106 | } |
107 | 107 | ||
@@ -110,7 +110,7 @@ mod tests { | |||
110 | check_assist( | 110 | check_assist( |
111 | flip_trait_bound, | 111 | flip_trait_bound, |
112 | "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }", | 112 | "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }", |
113 | "struct S<T> where T: A + B + C + D + E + G +<|> F + H + I + J { }", | 113 | "struct S<T> where T: A + B + C + D + E + G + F + H + I + J { }", |
114 | ) | 114 | ) |
115 | } | 115 | } |
116 | } | 116 | } |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 5b26814d3..d26e68847 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -3,7 +3,7 @@ use ra_syntax::{ | |||
3 | ast::{self, AstNode, AstToken}, | 3 | ast::{self, AstNode, AstToken}, |
4 | TextRange, | 4 | TextRange, |
5 | }; | 5 | }; |
6 | use test_utils::tested_by; | 6 | use test_utils::mark; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | assist_context::{AssistContext, Assists}, | 9 | assist_context::{AssistContext, Assists}, |
@@ -33,11 +33,11 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
33 | _ => return None, | 33 | _ => return None, |
34 | }; | 34 | }; |
35 | if bind_pat.mut_token().is_some() { | 35 | if bind_pat.mut_token().is_some() { |
36 | tested_by!(test_not_inline_mut_variable); | 36 | mark::hit!(test_not_inline_mut_variable); |
37 | return None; | 37 | return None; |
38 | } | 38 | } |
39 | if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) { | 39 | if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) { |
40 | tested_by!(not_applicable_outside_of_bind_pat); | 40 | mark::hit!(not_applicable_outside_of_bind_pat); |
41 | return None; | 41 | return None; |
42 | } | 42 | } |
43 | let initializer_expr = let_stmt.initializer()?; | 43 | let initializer_expr = let_stmt.initializer()?; |
@@ -46,7 +46,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
46 | let def = Definition::Local(def); | 46 | let def = Definition::Local(def); |
47 | let refs = def.find_usages(ctx.db, None); | 47 | let refs = def.find_usages(ctx.db, None); |
48 | if refs.is_empty() { | 48 | if refs.is_empty() { |
49 | tested_by!(test_not_applicable_if_variable_unused); | 49 | mark::hit!(test_not_applicable_if_variable_unused); |
50 | return None; | 50 | return None; |
51 | }; | 51 | }; |
52 | 52 | ||
@@ -116,13 +116,12 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
116 | let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; | 116 | let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; |
117 | builder.replace(desc.file_range.range, replacement) | 117 | builder.replace(desc.file_range.range, replacement) |
118 | } | 118 | } |
119 | builder.set_cursor(delete_range.start()) | ||
120 | }) | 119 | }) |
121 | } | 120 | } |
122 | 121 | ||
123 | #[cfg(test)] | 122 | #[cfg(test)] |
124 | mod tests { | 123 | mod tests { |
125 | use test_utils::covers; | 124 | use test_utils::mark; |
126 | 125 | ||
127 | use crate::tests::{check_assist, check_assist_not_applicable}; | 126 | use crate::tests::{check_assist, check_assist_not_applicable}; |
128 | 127 | ||
@@ -149,7 +148,7 @@ fn foo() { | |||
149 | r" | 148 | r" |
150 | fn bar(a: usize) {} | 149 | fn bar(a: usize) {} |
151 | fn foo() { | 150 | fn foo() { |
152 | <|>1 + 1; | 151 | 1 + 1; |
153 | if 1 > 10 { | 152 | if 1 > 10 { |
154 | } | 153 | } |
155 | 154 | ||
@@ -183,7 +182,7 @@ fn foo() { | |||
183 | r" | 182 | r" |
184 | fn bar(a: usize) {} | 183 | fn bar(a: usize) {} |
185 | fn foo() { | 184 | fn foo() { |
186 | <|>(1 + 1) + 1; | 185 | (1 + 1) + 1; |
187 | if (1 + 1) > 10 { | 186 | if (1 + 1) > 10 { |
188 | } | 187 | } |
189 | 188 | ||
@@ -217,7 +216,7 @@ fn foo() { | |||
217 | r" | 216 | r" |
218 | fn bar(a: usize) {} | 217 | fn bar(a: usize) {} |
219 | fn foo() { | 218 | fn foo() { |
220 | <|>bar(1) + 1; | 219 | bar(1) + 1; |
221 | if bar(1) > 10 { | 220 | if bar(1) > 10 { |
222 | } | 221 | } |
223 | 222 | ||
@@ -251,7 +250,7 @@ fn foo() { | |||
251 | r" | 250 | r" |
252 | fn bar(a: usize): usize { a } | 251 | fn bar(a: usize): usize { a } |
253 | fn foo() { | 252 | fn foo() { |
254 | <|>(bar(1) as u64) + 1; | 253 | (bar(1) as u64) + 1; |
255 | if (bar(1) as u64) > 10 { | 254 | if (bar(1) as u64) > 10 { |
256 | } | 255 | } |
257 | 256 | ||
@@ -283,7 +282,7 @@ fn foo() { | |||
283 | }", | 282 | }", |
284 | r" | 283 | r" |
285 | fn foo() { | 284 | fn foo() { |
286 | <|>{ 10 + 1 } + 1; | 285 | { 10 + 1 } + 1; |
287 | if { 10 + 1 } > 10 { | 286 | if { 10 + 1 } > 10 { |
288 | } | 287 | } |
289 | 288 | ||
@@ -315,7 +314,7 @@ fn foo() { | |||
315 | }", | 314 | }", |
316 | r" | 315 | r" |
317 | fn foo() { | 316 | fn foo() { |
318 | <|>( 10 + 1 ) + 1; | 317 | ( 10 + 1 ) + 1; |
319 | if ( 10 + 1 ) > 10 { | 318 | if ( 10 + 1 ) > 10 { |
320 | } | 319 | } |
321 | 320 | ||
@@ -330,7 +329,7 @@ fn foo() { | |||
330 | 329 | ||
331 | #[test] | 330 | #[test] |
332 | fn test_not_inline_mut_variable() { | 331 | fn test_not_inline_mut_variable() { |
333 | covers!(test_not_inline_mut_variable); | 332 | mark::check!(test_not_inline_mut_variable); |
334 | check_assist_not_applicable( | 333 | check_assist_not_applicable( |
335 | inline_local_variable, | 334 | inline_local_variable, |
336 | r" | 335 | r" |
@@ -353,7 +352,7 @@ fn foo() { | |||
353 | }", | 352 | }", |
354 | r" | 353 | r" |
355 | fn foo() { | 354 | fn foo() { |
356 | <|>let b = bar(10 + 1) * 10; | 355 | let b = bar(10 + 1) * 10; |
357 | let c = bar(10 + 1) as usize; | 356 | let c = bar(10 + 1) as usize; |
358 | }", | 357 | }", |
359 | ); | 358 | ); |
@@ -373,7 +372,7 @@ fn foo() { | |||
373 | r" | 372 | r" |
374 | fn foo() { | 373 | fn foo() { |
375 | let x = vec![1, 2, 3]; | 374 | let x = vec![1, 2, 3]; |
376 | <|>let b = x[0] * 10; | 375 | let b = x[0] * 10; |
377 | let c = x[0] as usize; | 376 | let c = x[0] as usize; |
378 | }", | 377 | }", |
379 | ); | 378 | ); |
@@ -393,7 +392,7 @@ fn foo() { | |||
393 | r" | 392 | r" |
394 | fn foo() { | 393 | fn foo() { |
395 | let bar = vec![1]; | 394 | let bar = vec![1]; |
396 | <|>let b = bar.len() * 10; | 395 | let b = bar.len() * 10; |
397 | let c = bar.len() as usize; | 396 | let c = bar.len() as usize; |
398 | }", | 397 | }", |
399 | ); | 398 | ); |
@@ -421,7 +420,7 @@ struct Bar { | |||
421 | 420 | ||
422 | fn foo() { | 421 | fn foo() { |
423 | let bar = Bar { foo: 1 }; | 422 | let bar = Bar { foo: 1 }; |
424 | <|>let b = bar.foo * 10; | 423 | let b = bar.foo * 10; |
425 | let c = bar.foo as usize; | 424 | let c = bar.foo as usize; |
426 | }", | 425 | }", |
427 | ); | 426 | ); |
@@ -442,7 +441,7 @@ fn foo() -> Option<usize> { | |||
442 | r" | 441 | r" |
443 | fn foo() -> Option<usize> { | 442 | fn foo() -> Option<usize> { |
444 | let bar = Some(1); | 443 | let bar = Some(1); |
445 | <|>let b = bar? * 10; | 444 | let b = bar? * 10; |
446 | let c = bar? as usize; | 445 | let c = bar? as usize; |
447 | None | 446 | None |
448 | }", | 447 | }", |
@@ -462,7 +461,7 @@ fn foo() { | |||
462 | r" | 461 | r" |
463 | fn foo() { | 462 | fn foo() { |
464 | let bar = 10; | 463 | let bar = 10; |
465 | <|>let b = &bar * 10; | 464 | let b = &bar * 10; |
466 | }", | 465 | }", |
467 | ); | 466 | ); |
468 | } | 467 | } |
@@ -478,7 +477,7 @@ fn foo() { | |||
478 | }", | 477 | }", |
479 | r" | 478 | r" |
480 | fn foo() { | 479 | fn foo() { |
481 | <|>let b = (10, 20)[0]; | 480 | let b = (10, 20)[0]; |
482 | }", | 481 | }", |
483 | ); | 482 | ); |
484 | } | 483 | } |
@@ -494,7 +493,7 @@ fn foo() { | |||
494 | }", | 493 | }", |
495 | r" | 494 | r" |
496 | fn foo() { | 495 | fn foo() { |
497 | <|>let b = [1, 2, 3].len(); | 496 | let b = [1, 2, 3].len(); |
498 | }", | 497 | }", |
499 | ); | 498 | ); |
500 | } | 499 | } |
@@ -511,7 +510,7 @@ fn foo() { | |||
511 | }", | 510 | }", |
512 | r" | 511 | r" |
513 | fn foo() { | 512 | fn foo() { |
514 | <|>let b = (10 + 20) * 10; | 513 | let b = (10 + 20) * 10; |
515 | let c = (10 + 20) as usize; | 514 | let c = (10 + 20) as usize; |
516 | }", | 515 | }", |
517 | ); | 516 | ); |
@@ -531,7 +530,7 @@ fn foo() { | |||
531 | r" | 530 | r" |
532 | fn foo() { | 531 | fn foo() { |
533 | let d = 10; | 532 | let d = 10; |
534 | <|>let b = d * 10; | 533 | let b = d * 10; |
535 | let c = d as usize; | 534 | let c = d as usize; |
536 | }", | 535 | }", |
537 | ); | 536 | ); |
@@ -549,7 +548,7 @@ fn foo() { | |||
549 | }", | 548 | }", |
550 | r" | 549 | r" |
551 | fn foo() { | 550 | fn foo() { |
552 | <|>let b = { 10 } * 10; | 551 | let b = { 10 } * 10; |
553 | let c = { 10 } as usize; | 552 | let c = { 10 } as usize; |
554 | }", | 553 | }", |
555 | ); | 554 | ); |
@@ -569,7 +568,7 @@ fn foo() { | |||
569 | }", | 568 | }", |
570 | r" | 569 | r" |
571 | fn foo() { | 570 | fn foo() { |
572 | <|>let b = (10 + 20) * 10; | 571 | let b = (10 + 20) * 10; |
573 | let c = (10 + 20, 20); | 572 | let c = (10 + 20, 20); |
574 | let d = [10 + 20, 10]; | 573 | let d = [10 + 20, 10]; |
575 | let e = (10 + 20); | 574 | let e = (10 + 20); |
@@ -588,7 +587,7 @@ fn foo() { | |||
588 | }", | 587 | }", |
589 | r" | 588 | r" |
590 | fn foo() { | 589 | fn foo() { |
591 | <|>for i in vec![10, 20] {} | 590 | for i in vec![10, 20] {} |
592 | }", | 591 | }", |
593 | ); | 592 | ); |
594 | } | 593 | } |
@@ -604,7 +603,7 @@ fn foo() { | |||
604 | }", | 603 | }", |
605 | r" | 604 | r" |
606 | fn foo() { | 605 | fn foo() { |
607 | <|>while 1 > 0 {} | 606 | while 1 > 0 {} |
608 | }", | 607 | }", |
609 | ); | 608 | ); |
610 | } | 609 | } |
@@ -622,7 +621,7 @@ fn foo() { | |||
622 | }", | 621 | }", |
623 | r" | 622 | r" |
624 | fn foo() { | 623 | fn foo() { |
625 | <|>loop { | 624 | loop { |
626 | break 1 + 1; | 625 | break 1 + 1; |
627 | } | 626 | } |
628 | }", | 627 | }", |
@@ -640,7 +639,7 @@ fn foo() { | |||
640 | }", | 639 | }", |
641 | r" | 640 | r" |
642 | fn foo() { | 641 | fn foo() { |
643 | <|>return 1 > 0; | 642 | return 1 > 0; |
644 | }", | 643 | }", |
645 | ); | 644 | ); |
646 | } | 645 | } |
@@ -656,14 +655,14 @@ fn foo() { | |||
656 | }", | 655 | }", |
657 | r" | 656 | r" |
658 | fn foo() { | 657 | fn foo() { |
659 | <|>match 1 > 0 {} | 658 | match 1 > 0 {} |
660 | }", | 659 | }", |
661 | ); | 660 | ); |
662 | } | 661 | } |
663 | 662 | ||
664 | #[test] | 663 | #[test] |
665 | fn test_not_applicable_if_variable_unused() { | 664 | fn test_not_applicable_if_variable_unused() { |
666 | covers!(test_not_applicable_if_variable_unused); | 665 | mark::check!(test_not_applicable_if_variable_unused); |
667 | check_assist_not_applicable( | 666 | check_assist_not_applicable( |
668 | inline_local_variable, | 667 | inline_local_variable, |
669 | r" | 668 | r" |
@@ -676,7 +675,7 @@ fn foo() { | |||
676 | 675 | ||
677 | #[test] | 676 | #[test] |
678 | fn not_applicable_outside_of_bind_pat() { | 677 | fn not_applicable_outside_of_bind_pat() { |
679 | covers!(not_applicable_outside_of_bind_pat); | 678 | mark::check!(not_applicable_outside_of_bind_pat); |
680 | check_assist_not_applicable( | 679 | check_assist_not_applicable( |
681 | inline_local_variable, | 680 | inline_local_variable, |
682 | r" | 681 | r" |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index fdf3ada0d..31d6539f7 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -4,10 +4,10 @@ use ra_syntax::{ | |||
4 | BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, | 4 | BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, |
5 | WHITESPACE, | 5 | WHITESPACE, |
6 | }, | 6 | }, |
7 | SyntaxNode, TextSize, | 7 | SyntaxNode, |
8 | }; | 8 | }; |
9 | use stdx::format_to; | 9 | use stdx::format_to; |
10 | use test_utils::tested_by; | 10 | use test_utils::mark; |
11 | 11 | ||
12 | use crate::{AssistContext, AssistId, Assists}; | 12 | use crate::{AssistContext, AssistId, Assists}; |
13 | 13 | ||
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
23 | // -> | 23 | // -> |
24 | // ``` | 24 | // ``` |
25 | // fn main() { | 25 | // fn main() { |
26 | // let var_name = (1 + 2); | 26 | // let $0var_name = (1 + 2); |
27 | // var_name * 4; | 27 | // var_name * 4; |
28 | // } | 28 | // } |
29 | // ``` | 29 | // ``` |
@@ -33,7 +33,7 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
33 | } | 33 | } |
34 | let node = ctx.covering_element(); | 34 | let node = ctx.covering_element(); |
35 | if node.kind() == COMMENT { | 35 | if node.kind() == COMMENT { |
36 | tested_by!(introduce_var_in_comment_is_not_applicable); | 36 | mark::hit!(introduce_var_in_comment_is_not_applicable); |
37 | return None; | 37 | return None; |
38 | } | 38 | } |
39 | let expr = node.ancestors().find_map(valid_target_expr)?; | 39 | let expr = node.ancestors().find_map(valid_target_expr)?; |
@@ -46,14 +46,13 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
46 | acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { | 46 | acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { |
47 | let mut buf = String::new(); | 47 | let mut buf = String::new(); |
48 | 48 | ||
49 | let cursor_offset = if wrap_in_block { | 49 | if wrap_in_block { |
50 | buf.push_str("{ let var_name = "); | 50 | buf.push_str("{ let var_name = "); |
51 | TextSize::of("{ let ") | ||
52 | } else { | 51 | } else { |
53 | buf.push_str("let var_name = "); | 52 | buf.push_str("let var_name = "); |
54 | TextSize::of("let ") | ||
55 | }; | 53 | }; |
56 | format_to!(buf, "{}", expr.syntax()); | 54 | format_to!(buf, "{}", expr.syntax()); |
55 | |||
57 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); | 56 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); |
58 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { | 57 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { |
59 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) | 58 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) |
@@ -61,32 +60,47 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
61 | false | 60 | false |
62 | }; | 61 | }; |
63 | if is_full_stmt { | 62 | if is_full_stmt { |
64 | tested_by!(test_introduce_var_expr_stmt); | 63 | mark::hit!(test_introduce_var_expr_stmt); |
65 | if full_stmt.unwrap().semicolon_token().is_none() { | 64 | if full_stmt.unwrap().semicolon_token().is_none() { |
66 | buf.push_str(";"); | 65 | buf.push_str(";"); |
67 | } | 66 | } |
68 | edit.replace(expr.syntax().text_range(), buf); | 67 | let offset = expr.syntax().text_range(); |
69 | } else { | 68 | match ctx.config.snippet_cap { |
70 | buf.push_str(";"); | 69 | Some(cap) => { |
71 | 70 | let snip = buf.replace("let var_name", "let $0var_name"); | |
72 | // We want to maintain the indent level, | 71 | edit.replace_snippet(cap, offset, snip) |
73 | // but we do not want to duplicate possible | 72 | } |
74 | // extra newlines in the indent block | 73 | None => edit.replace(offset, buf), |
75 | let text = indent.text(); | ||
76 | if text.starts_with('\n') { | ||
77 | buf.push_str("\n"); | ||
78 | buf.push_str(text.trim_start_matches('\n')); | ||
79 | } else { | ||
80 | buf.push_str(text); | ||
81 | } | 74 | } |
75 | return; | ||
76 | } | ||
82 | 77 | ||
83 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); | 78 | buf.push_str(";"); |
84 | edit.insert(anchor_stmt.text_range().start(), buf); | 79 | |
85 | if wrap_in_block { | 80 | // We want to maintain the indent level, |
86 | edit.insert(anchor_stmt.text_range().end(), " }"); | 81 | // but we do not want to duplicate possible |
82 | // extra newlines in the indent block | ||
83 | let text = indent.text(); | ||
84 | if text.starts_with('\n') { | ||
85 | buf.push_str("\n"); | ||
86 | buf.push_str(text.trim_start_matches('\n')); | ||
87 | } else { | ||
88 | buf.push_str(text); | ||
89 | } | ||
90 | |||
91 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); | ||
92 | let offset = anchor_stmt.text_range().start(); | ||
93 | match ctx.config.snippet_cap { | ||
94 | Some(cap) => { | ||
95 | let snip = buf.replace("let var_name", "let $0var_name"); | ||
96 | edit.insert_snippet(cap, offset, snip) | ||
87 | } | 97 | } |
98 | None => edit.insert(offset, buf), | ||
99 | } | ||
100 | |||
101 | if wrap_in_block { | ||
102 | edit.insert(anchor_stmt.text_range().end(), " }"); | ||
88 | } | 103 | } |
89 | edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset); | ||
90 | }) | 104 | }) |
91 | } | 105 | } |
92 | 106 | ||
@@ -113,7 +127,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { | |||
113 | expr.syntax().ancestors().find_map(|node| { | 127 | expr.syntax().ancestors().find_map(|node| { |
114 | if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { | 128 | if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { |
115 | if expr.syntax() == &node { | 129 | if expr.syntax() == &node { |
116 | tested_by!(test_introduce_var_last_expr); | 130 | mark::hit!(test_introduce_var_last_expr); |
117 | return Some((node, false)); | 131 | return Some((node, false)); |
118 | } | 132 | } |
119 | } | 133 | } |
@@ -134,7 +148,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { | |||
134 | 148 | ||
135 | #[cfg(test)] | 149 | #[cfg(test)] |
136 | mod tests { | 150 | mod tests { |
137 | use test_utils::covers; | 151 | use test_utils::mark; |
138 | 152 | ||
139 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 153 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
140 | 154 | ||
@@ -144,37 +158,37 @@ mod tests { | |||
144 | fn test_introduce_var_simple() { | 158 | fn test_introduce_var_simple() { |
145 | check_assist( | 159 | check_assist( |
146 | introduce_variable, | 160 | introduce_variable, |
147 | " | 161 | r#" |
148 | fn foo() { | 162 | fn foo() { |
149 | foo(<|>1 + 1<|>); | 163 | foo(<|>1 + 1<|>); |
150 | }", | 164 | }"#, |
151 | " | 165 | r#" |
152 | fn foo() { | 166 | fn foo() { |
153 | let <|>var_name = 1 + 1; | 167 | let $0var_name = 1 + 1; |
154 | foo(var_name); | 168 | foo(var_name); |
155 | }", | 169 | }"#, |
156 | ); | 170 | ); |
157 | } | 171 | } |
158 | 172 | ||
159 | #[test] | 173 | #[test] |
160 | fn introduce_var_in_comment_is_not_applicable() { | 174 | fn introduce_var_in_comment_is_not_applicable() { |
161 | covers!(introduce_var_in_comment_is_not_applicable); | 175 | mark::check!(introduce_var_in_comment_is_not_applicable); |
162 | check_assist_not_applicable(introduce_variable, "fn main() { 1 + /* <|>comment<|> */ 1; }"); | 176 | check_assist_not_applicable(introduce_variable, "fn main() { 1 + /* <|>comment<|> */ 1; }"); |
163 | } | 177 | } |
164 | 178 | ||
165 | #[test] | 179 | #[test] |
166 | fn test_introduce_var_expr_stmt() { | 180 | fn test_introduce_var_expr_stmt() { |
167 | covers!(test_introduce_var_expr_stmt); | 181 | mark::check!(test_introduce_var_expr_stmt); |
168 | check_assist( | 182 | check_assist( |
169 | introduce_variable, | 183 | introduce_variable, |
170 | " | 184 | r#" |
171 | fn foo() { | 185 | fn foo() { |
172 | <|>1 + 1<|>; | 186 | <|>1 + 1<|>; |
173 | }", | 187 | }"#, |
174 | " | 188 | r#" |
175 | fn foo() { | 189 | fn foo() { |
176 | let <|>var_name = 1 + 1; | 190 | let $0var_name = 1 + 1; |
177 | }", | 191 | }"#, |
178 | ); | 192 | ); |
179 | check_assist( | 193 | check_assist( |
180 | introduce_variable, | 194 | introduce_variable, |
@@ -185,7 +199,7 @@ fn foo() { | |||
185 | }", | 199 | }", |
186 | " | 200 | " |
187 | fn foo() { | 201 | fn foo() { |
188 | let <|>var_name = { let x = 0; x }; | 202 | let $0var_name = { let x = 0; x }; |
189 | something_else(); | 203 | something_else(); |
190 | }", | 204 | }", |
191 | ); | 205 | ); |
@@ -201,7 +215,7 @@ fn foo() { | |||
201 | }", | 215 | }", |
202 | " | 216 | " |
203 | fn foo() { | 217 | fn foo() { |
204 | let <|>var_name = 1; | 218 | let $0var_name = 1; |
205 | var_name + 1; | 219 | var_name + 1; |
206 | }", | 220 | }", |
207 | ); | 221 | ); |
@@ -209,7 +223,7 @@ fn foo() { | |||
209 | 223 | ||
210 | #[test] | 224 | #[test] |
211 | fn test_introduce_var_last_expr() { | 225 | fn test_introduce_var_last_expr() { |
212 | covers!(test_introduce_var_last_expr); | 226 | mark::check!(test_introduce_var_last_expr); |
213 | check_assist( | 227 | check_assist( |
214 | introduce_variable, | 228 | introduce_variable, |
215 | " | 229 | " |
@@ -218,7 +232,7 @@ fn foo() { | |||
218 | }", | 232 | }", |
219 | " | 233 | " |
220 | fn foo() { | 234 | fn foo() { |
221 | let <|>var_name = 1 + 1; | 235 | let $0var_name = 1 + 1; |
222 | bar(var_name) | 236 | bar(var_name) |
223 | }", | 237 | }", |
224 | ); | 238 | ); |
@@ -230,7 +244,7 @@ fn foo() { | |||
230 | }", | 244 | }", |
231 | " | 245 | " |
232 | fn foo() { | 246 | fn foo() { |
233 | let <|>var_name = bar(1 + 1); | 247 | let $0var_name = bar(1 + 1); |
234 | var_name | 248 | var_name |
235 | }", | 249 | }", |
236 | ) | 250 | ) |
@@ -253,7 +267,7 @@ fn main() { | |||
253 | fn main() { | 267 | fn main() { |
254 | let x = true; | 268 | let x = true; |
255 | let tuple = match x { | 269 | let tuple = match x { |
256 | true => { let <|>var_name = 2 + 2; (var_name, true) } | 270 | true => { let $0var_name = 2 + 2; (var_name, true) } |
257 | _ => (0, false) | 271 | _ => (0, false) |
258 | }; | 272 | }; |
259 | } | 273 | } |
@@ -283,7 +297,7 @@ fn main() { | |||
283 | let tuple = match x { | 297 | let tuple = match x { |
284 | true => { | 298 | true => { |
285 | let y = 1; | 299 | let y = 1; |
286 | let <|>var_name = 2 + y; | 300 | let $0var_name = 2 + y; |
287 | (var_name, true) | 301 | (var_name, true) |
288 | } | 302 | } |
289 | _ => (0, false) | 303 | _ => (0, false) |
@@ -304,7 +318,7 @@ fn main() { | |||
304 | ", | 318 | ", |
305 | " | 319 | " |
306 | fn main() { | 320 | fn main() { |
307 | let lambda = |x: u32| { let <|>var_name = x * 2; var_name }; | 321 | let lambda = |x: u32| { let $0var_name = x * 2; var_name }; |
308 | } | 322 | } |
309 | ", | 323 | ", |
310 | ); | 324 | ); |
@@ -321,7 +335,7 @@ fn main() { | |||
321 | ", | 335 | ", |
322 | " | 336 | " |
323 | fn main() { | 337 | fn main() { |
324 | let lambda = |x: u32| { let <|>var_name = x * 2; var_name }; | 338 | let lambda = |x: u32| { let $0var_name = x * 2; var_name }; |
325 | } | 339 | } |
326 | ", | 340 | ", |
327 | ); | 341 | ); |
@@ -338,7 +352,7 @@ fn main() { | |||
338 | ", | 352 | ", |
339 | " | 353 | " |
340 | fn main() { | 354 | fn main() { |
341 | let <|>var_name = Some(true); | 355 | let $0var_name = Some(true); |
342 | let o = var_name; | 356 | let o = var_name; |
343 | } | 357 | } |
344 | ", | 358 | ", |
@@ -356,7 +370,7 @@ fn main() { | |||
356 | ", | 370 | ", |
357 | " | 371 | " |
358 | fn main() { | 372 | fn main() { |
359 | let <|>var_name = bar.foo(); | 373 | let $0var_name = bar.foo(); |
360 | let v = var_name; | 374 | let v = var_name; |
361 | } | 375 | } |
362 | ", | 376 | ", |
@@ -374,7 +388,7 @@ fn foo() -> u32 { | |||
374 | ", | 388 | ", |
375 | " | 389 | " |
376 | fn foo() -> u32 { | 390 | fn foo() -> u32 { |
377 | let <|>var_name = 2 + 2; | 391 | let $0var_name = 2 + 2; |
378 | return var_name; | 392 | return var_name; |
379 | } | 393 | } |
380 | ", | 394 | ", |
@@ -396,7 +410,7 @@ fn foo() -> u32 { | |||
396 | fn foo() -> u32 { | 410 | fn foo() -> u32 { |
397 | 411 | ||
398 | 412 | ||
399 | let <|>var_name = 2 + 2; | 413 | let $0var_name = 2 + 2; |
400 | return var_name; | 414 | return var_name; |
401 | } | 415 | } |
402 | ", | 416 | ", |
@@ -413,7 +427,7 @@ fn foo() -> u32 { | |||
413 | " | 427 | " |
414 | fn foo() -> u32 { | 428 | fn foo() -> u32 { |
415 | 429 | ||
416 | let <|>var_name = 2 + 2; | 430 | let $0var_name = 2 + 2; |
417 | return var_name; | 431 | return var_name; |
418 | } | 432 | } |
419 | ", | 433 | ", |
@@ -438,7 +452,7 @@ fn foo() -> u32 { | |||
438 | // bar | 452 | // bar |
439 | 453 | ||
440 | 454 | ||
441 | let <|>var_name = 2 + 2; | 455 | let $0var_name = 2 + 2; |
442 | return var_name; | 456 | return var_name; |
443 | } | 457 | } |
444 | ", | 458 | ", |
@@ -459,7 +473,7 @@ fn main() { | |||
459 | " | 473 | " |
460 | fn main() { | 474 | fn main() { |
461 | let result = loop { | 475 | let result = loop { |
462 | let <|>var_name = 2 + 2; | 476 | let $0var_name = 2 + 2; |
463 | break var_name; | 477 | break var_name; |
464 | }; | 478 | }; |
465 | } | 479 | } |
@@ -478,7 +492,7 @@ fn main() { | |||
478 | ", | 492 | ", |
479 | " | 493 | " |
480 | fn main() { | 494 | fn main() { |
481 | let <|>var_name = 0f32 as u32; | 495 | let $0var_name = 0f32 as u32; |
482 | let v = var_name; | 496 | let v = var_name; |
483 | } | 497 | } |
484 | ", | 498 | ", |
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs index 527c7caef..59d278eb9 100644 --- a/crates/ra_assists/src/handlers/invert_if.rs +++ b/crates/ra_assists/src/handlers/invert_if.rs | |||
@@ -72,7 +72,7 @@ mod tests { | |||
72 | check_assist( | 72 | check_assist( |
73 | invert_if, | 73 | invert_if, |
74 | "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", | 74 | "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", |
75 | "fn f() { i<|>f x == 3 { 3 + 2 } else { 1 } }", | 75 | "fn f() { if x == 3 { 3 + 2 } else { 1 } }", |
76 | ) | 76 | ) |
77 | } | 77 | } |
78 | 78 | ||
@@ -81,7 +81,7 @@ mod tests { | |||
81 | check_assist( | 81 | check_assist( |
82 | invert_if, | 82 | invert_if, |
83 | "fn f() { <|>if !cond { 3 * 2 } else { 1 } }", | 83 | "fn f() { <|>if !cond { 3 * 2 } else { 1 } }", |
84 | "fn f() { <|>if cond { 1 } else { 3 * 2 } }", | 84 | "fn f() { if cond { 1 } else { 3 * 2 } }", |
85 | ) | 85 | ) |
86 | } | 86 | } |
87 | 87 | ||
@@ -90,7 +90,7 @@ mod tests { | |||
90 | check_assist( | 90 | check_assist( |
91 | invert_if, | 91 | invert_if, |
92 | "fn f() { i<|>f cond { 3 * 2 } else { 1 } }", | 92 | "fn f() { i<|>f cond { 3 * 2 } else { 1 } }", |
93 | "fn f() { i<|>f !cond { 1 } else { 3 * 2 } }", | 93 | "fn f() { if !cond { 1 } else { 3 * 2 } }", |
94 | ) | 94 | ) |
95 | } | 95 | } |
96 | 96 | ||
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index ac3e53c27..972d16241 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -58,8 +58,6 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
58 | let target = tree.syntax().text_range(); | 58 | let target = tree.syntax().text_range(); |
59 | acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { | 59 | acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { |
60 | builder.rewrite(rewriter); | 60 | builder.rewrite(rewriter); |
61 | // FIXME: we only need because our diff is imprecise | ||
62 | builder.set_cursor(offset); | ||
63 | }) | 61 | }) |
64 | } | 62 | } |
65 | 63 | ||
@@ -142,7 +140,7 @@ use std::fmt<|>::Debug; | |||
142 | use std::fmt::Display; | 140 | use std::fmt::Display; |
143 | ", | 141 | ", |
144 | r" | 142 | r" |
145 | use std::fmt<|>::{Debug, Display}; | 143 | use std::fmt::{Debug, Display}; |
146 | ", | 144 | ", |
147 | ) | 145 | ) |
148 | } | 146 | } |
@@ -156,7 +154,7 @@ use std::fmt::Debug; | |||
156 | use std::fmt<|>::Display; | 154 | use std::fmt<|>::Display; |
157 | ", | 155 | ", |
158 | r" | 156 | r" |
159 | use std::fmt:<|>:{Display, Debug}; | 157 | use std::fmt::{Display, Debug}; |
160 | ", | 158 | ", |
161 | ); | 159 | ); |
162 | } | 160 | } |
@@ -169,7 +167,7 @@ use std::fmt:<|>:{Display, Debug}; | |||
169 | use std::{fmt<|>::Debug, fmt::Display}; | 167 | use std::{fmt<|>::Debug, fmt::Display}; |
170 | ", | 168 | ", |
171 | r" | 169 | r" |
172 | use std::{fmt<|>::{Debug, Display}}; | 170 | use std::{fmt::{Debug, Display}}; |
173 | ", | 171 | ", |
174 | ); | 172 | ); |
175 | check_assist( | 173 | check_assist( |
@@ -178,7 +176,7 @@ use std::{fmt<|>::{Debug, Display}}; | |||
178 | use std::{fmt::Debug, fmt<|>::Display}; | 176 | use std::{fmt::Debug, fmt<|>::Display}; |
179 | ", | 177 | ", |
180 | r" | 178 | r" |
181 | use std::{fmt::<|>{Display, Debug}}; | 179 | use std::{fmt::{Display, Debug}}; |
182 | ", | 180 | ", |
183 | ); | 181 | ); |
184 | } | 182 | } |
@@ -192,7 +190,7 @@ use std<|>::cell::*; | |||
192 | use std::str; | 190 | use std::str; |
193 | ", | 191 | ", |
194 | r" | 192 | r" |
195 | use std<|>::{cell::*, str}; | 193 | use std::{cell::*, str}; |
196 | ", | 194 | ", |
197 | ) | 195 | ) |
198 | } | 196 | } |
@@ -206,7 +204,7 @@ use std<|>::cell::*; | |||
206 | use std::str::*; | 204 | use std::str::*; |
207 | ", | 205 | ", |
208 | r" | 206 | r" |
209 | use std<|>::{cell::*, str::*}; | 207 | use std::{cell::*, str::*}; |
210 | ", | 208 | ", |
211 | ) | 209 | ) |
212 | } | 210 | } |
@@ -222,7 +220,7 @@ use foo::baz; | |||
222 | /// Doc comment | 220 | /// Doc comment |
223 | ", | 221 | ", |
224 | r" | 222 | r" |
225 | use foo<|>::{bar, baz}; | 223 | use foo::{bar, baz}; |
226 | 224 | ||
227 | /// Doc comment | 225 | /// Doc comment |
228 | ", | 226 | ", |
@@ -241,7 +239,7 @@ use { | |||
241 | ", | 239 | ", |
242 | r" | 240 | r" |
243 | use { | 241 | use { |
244 | foo<|>::{bar, baz}, | 242 | foo::{bar, baz}, |
245 | }; | 243 | }; |
246 | ", | 244 | ", |
247 | ); | 245 | ); |
@@ -255,7 +253,7 @@ use { | |||
255 | ", | 253 | ", |
256 | r" | 254 | r" |
257 | use { | 255 | use { |
258 | foo::{bar<|>, baz}, | 256 | foo::{bar, baz}, |
259 | }; | 257 | }; |
260 | ", | 258 | ", |
261 | ); | 259 | ); |
@@ -272,7 +270,7 @@ use foo::<|>{ | |||
272 | }; | 270 | }; |
273 | ", | 271 | ", |
274 | r" | 272 | r" |
275 | use foo::{<|> | 273 | use foo::{ |
276 | FooBar, | 274 | FooBar, |
277 | bar::baz}; | 275 | bar::baz}; |
278 | ", | 276 | ", |
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index d4e38aa6a..ca04ec671 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs | |||
@@ -3,7 +3,7 @@ use std::iter::successors; | |||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::neighbor, | 4 | algo::neighbor, |
5 | ast::{self, AstNode}, | 5 | ast::{self, AstNode}, |
6 | Direction, TextSize, | 6 | Direction, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{AssistContext, AssistId, Assists, TextRange}; | 9 | use crate::{AssistContext, AssistId, Assists, TextRange}; |
@@ -41,17 +41,6 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
41 | let current_expr = current_arm.expr()?; | 41 | let current_expr = current_arm.expr()?; |
42 | let current_text_range = current_arm.syntax().text_range(); | 42 | let current_text_range = current_arm.syntax().text_range(); |
43 | 43 | ||
44 | enum CursorPos { | ||
45 | InExpr(TextSize), | ||
46 | InPat(TextSize), | ||
47 | } | ||
48 | let cursor_pos = ctx.offset(); | ||
49 | let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) { | ||
50 | CursorPos::InExpr(current_text_range.end() - cursor_pos) | ||
51 | } else { | ||
52 | CursorPos::InPat(cursor_pos) | ||
53 | }; | ||
54 | |||
55 | // We check if the following match arms match this one. We could, but don't, | 44 | // We check if the following match arms match this one. We could, but don't, |
56 | // compare to the previous match arm as well. | 45 | // compare to the previous match arm as well. |
57 | let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next)) | 46 | let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next)) |
@@ -87,10 +76,6 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
87 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); | 76 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); |
88 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); | 77 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); |
89 | 78 | ||
90 | edit.set_cursor(match cursor_pos { | ||
91 | CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset, | ||
92 | CursorPos::InPat(offset) => offset, | ||
93 | }); | ||
94 | edit.replace(TextRange::new(start, end), arm); | 79 | edit.replace(TextRange::new(start, end), arm); |
95 | }) | 80 | }) |
96 | } | 81 | } |
@@ -132,7 +117,7 @@ mod tests { | |||
132 | fn main() { | 117 | fn main() { |
133 | let x = X::A; | 118 | let x = X::A; |
134 | let y = match x { | 119 | let y = match x { |
135 | X::A | X::B => { 1i32<|> } | 120 | X::A | X::B => { 1i32 } |
136 | X::C => { 2i32 } | 121 | X::C => { 2i32 } |
137 | } | 122 | } |
138 | } | 123 | } |
@@ -164,7 +149,7 @@ mod tests { | |||
164 | fn main() { | 149 | fn main() { |
165 | let x = X::A; | 150 | let x = X::A; |
166 | let y = match x { | 151 | let y = match x { |
167 | X::A | X::B | X::C | X::D => {<|> 1i32 }, | 152 | X::A | X::B | X::C | X::D => { 1i32 }, |
168 | X::E => { 2i32 }, | 153 | X::E => { 2i32 }, |
169 | } | 154 | } |
170 | } | 155 | } |
@@ -197,7 +182,7 @@ mod tests { | |||
197 | let x = X::A; | 182 | let x = X::A; |
198 | let y = match x { | 183 | let y = match x { |
199 | X::A => { 1i32 }, | 184 | X::A => { 1i32 }, |
200 | _ => { 2i<|>32 } | 185 | _ => { 2i32 } |
201 | } | 186 | } |
202 | } | 187 | } |
203 | "#, | 188 | "#, |
@@ -226,7 +211,7 @@ mod tests { | |||
226 | 211 | ||
227 | fn main() { | 212 | fn main() { |
228 | match X::A { | 213 | match X::A { |
229 | X::A<|> | X::B | X::C => 92, | 214 | X::A | X::B | X::C => 92, |
230 | X::D => 62, | 215 | X::D => 62, |
231 | _ => panic!(), | 216 | _ => panic!(), |
232 | } | 217 | } |
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index a41aacfc3..be2a7eddc 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
@@ -99,7 +99,7 @@ mod tests { | |||
99 | fn foo<T: u32, <|>F: FnOnce(T) -> T>() {} | 99 | fn foo<T: u32, <|>F: FnOnce(T) -> T>() {} |
100 | "#, | 100 | "#, |
101 | r#" | 101 | r#" |
102 | fn foo<T, <|>F>() where T: u32, F: FnOnce(T) -> T {} | 102 | fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} |
103 | "#, | 103 | "#, |
104 | ); | 104 | ); |
105 | } | 105 | } |
@@ -112,7 +112,7 @@ mod tests { | |||
112 | impl<U: u32, <|>T> A<U, T> {} | 112 | impl<U: u32, <|>T> A<U, T> {} |
113 | "#, | 113 | "#, |
114 | r#" | 114 | r#" |
115 | impl<U, <|>T> A<U, T> where U: u32 {} | 115 | impl<U, T> A<U, T> where U: u32 {} |
116 | "#, | 116 | "#, |
117 | ); | 117 | ); |
118 | } | 118 | } |
@@ -125,7 +125,7 @@ mod tests { | |||
125 | struct A<<|>T: Iterator<Item = u32>> {} | 125 | struct A<<|>T: Iterator<Item = u32>> {} |
126 | "#, | 126 | "#, |
127 | r#" | 127 | r#" |
128 | struct A<<|>T> where T: Iterator<Item = u32> {} | 128 | struct A<T> where T: Iterator<Item = u32> {} |
129 | "#, | 129 | "#, |
130 | ); | 130 | ); |
131 | } | 131 | } |
@@ -138,7 +138,7 @@ mod tests { | |||
138 | struct Pair<<|>T: u32>(T, T); | 138 | struct Pair<<|>T: u32>(T, T); |
139 | "#, | 139 | "#, |
140 | r#" | 140 | r#" |
141 | struct Pair<<|>T>(T, T) where T: u32; | 141 | struct Pair<T>(T, T) where T: u32; |
142 | "#, | 142 | "#, |
143 | ); | 143 | ); |
144 | } | 144 | } |
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index fc0335b57..7edcf0748 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast, | 2 | ast::{AstNode, IfExpr, MatchArm}, |
3 | ast::{AstNode, AstToken, IfExpr, MatchArm}, | 3 | SyntaxKind::WHITESPACE, |
4 | TextSize, | ||
5 | }; | 4 | }; |
6 | 5 | ||
7 | use crate::{AssistContext, AssistId, Assists}; | 6 | use crate::{AssistContext, AssistId, Assists}; |
@@ -42,24 +41,15 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> | |||
42 | 41 | ||
43 | let target = guard.syntax().text_range(); | 42 | let target = guard.syntax().text_range(); |
44 | acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { | 43 | acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { |
45 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { | 44 | match space_before_guard { |
46 | Some(tok) => { | 45 | Some(element) if element.kind() == WHITESPACE => { |
47 | if ast::Whitespace::cast(tok.clone()).is_some() { | 46 | edit.delete(element.text_range()); |
48 | let ele = tok.text_range(); | ||
49 | edit.delete(ele); | ||
50 | ele.len() | ||
51 | } else { | ||
52 | TextSize::from(0) | ||
53 | } | ||
54 | } | 47 | } |
55 | _ => TextSize::from(0), | 48 | _ => (), |
56 | }; | 49 | }; |
57 | 50 | ||
58 | edit.delete(guard.syntax().text_range()); | 51 | edit.delete(guard.syntax().text_range()); |
59 | edit.replace_node_and_indent(arm_expr.syntax(), buf); | 52 | edit.replace_node_and_indent(arm_expr.syntax(), buf); |
60 | edit.set_cursor( | ||
61 | arm_expr.syntax().text_range().start() + TextSize::from(3) - offseting_amount, | ||
62 | ); | ||
63 | }) | 53 | }) |
64 | } | 54 | } |
65 | 55 | ||
@@ -124,7 +114,6 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex | |||
124 | } | 114 | } |
125 | 115 | ||
126 | edit.insert(match_pat.syntax().text_range().end(), buf); | 116 | edit.insert(match_pat.syntax().text_range().end(), buf); |
127 | edit.set_cursor(match_pat.syntax().text_range().end() + TextSize::from(1)); | ||
128 | }, | 117 | }, |
129 | ) | 118 | ) |
130 | } | 119 | } |
@@ -172,7 +161,7 @@ mod tests { | |||
172 | let t = 'a'; | 161 | let t = 'a'; |
173 | let chars = "abcd"; | 162 | let chars = "abcd"; |
174 | match t { | 163 | match t { |
175 | '\r' => if chars.clone().next() == Some('\n') { <|>false }, | 164 | '\r' => if chars.clone().next() == Some('\n') { false }, |
176 | _ => true | 165 | _ => true |
177 | } | 166 | } |
178 | } | 167 | } |
@@ -195,7 +184,7 @@ mod tests { | |||
195 | r#" | 184 | r#" |
196 | fn f() { | 185 | fn f() { |
197 | match x { | 186 | match x { |
198 | y @ 4 | y @ 5 => if y > 5 { <|>true }, | 187 | y @ 4 | y @ 5 => if y > 5 { true }, |
199 | _ => false | 188 | _ => false |
200 | } | 189 | } |
201 | } | 190 | } |
@@ -222,7 +211,7 @@ mod tests { | |||
222 | let t = 'a'; | 211 | let t = 'a'; |
223 | let chars = "abcd"; | 212 | let chars = "abcd"; |
224 | match t { | 213 | match t { |
225 | '\r' <|>if chars.clone().next() == Some('\n') => false, | 214 | '\r' if chars.clone().next() == Some('\n') => false, |
226 | _ => true | 215 | _ => true |
227 | } | 216 | } |
228 | } | 217 | } |
@@ -266,7 +255,7 @@ mod tests { | |||
266 | let t = 'a'; | 255 | let t = 'a'; |
267 | let chars = "abcd"; | 256 | let chars = "abcd"; |
268 | match t { | 257 | match t { |
269 | '\r' <|>if chars.clone().next().is_some() => { }, | 258 | '\r' if chars.clone().next().is_some() => { }, |
270 | _ => true | 259 | _ => true |
271 | } | 260 | } |
272 | } | 261 | } |
@@ -296,7 +285,7 @@ mod tests { | |||
296 | let mut t = 'a'; | 285 | let mut t = 'a'; |
297 | let chars = "abcd"; | 286 | let chars = "abcd"; |
298 | match t { | 287 | match t { |
299 | '\r' <|>if chars.clone().next().is_some() => { | 288 | '\r' if chars.clone().next().is_some() => { |
300 | t = 'e'; | 289 | t = 'e'; |
301 | false | 290 | false |
302 | }, | 291 | }, |
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index c20ffe0b3..16002d2ac 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs | |||
@@ -164,7 +164,7 @@ mod test { | |||
164 | "#, | 164 | "#, |
165 | r##" | 165 | r##" |
166 | fn f() { | 166 | fn f() { |
167 | let s = <|>r#"random | 167 | let s = r#"random |
168 | string"#; | 168 | string"#; |
169 | } | 169 | } |
170 | "##, | 170 | "##, |
@@ -182,7 +182,7 @@ string"#; | |||
182 | "#, | 182 | "#, |
183 | r##" | 183 | r##" |
184 | fn f() { | 184 | fn f() { |
185 | format!(<|>r#"x = {}"#, 92) | 185 | format!(r#"x = {}"#, 92) |
186 | } | 186 | } |
187 | "##, | 187 | "##, |
188 | ) | 188 | ) |
@@ -199,7 +199,7 @@ string"#; | |||
199 | "###, | 199 | "###, |
200 | r####" | 200 | r####" |
201 | fn f() { | 201 | fn f() { |
202 | let s = <|>r#"#random## | 202 | let s = r#"#random## |
203 | string"#; | 203 | string"#; |
204 | } | 204 | } |
205 | "####, | 205 | "####, |
@@ -217,7 +217,7 @@ string"#; | |||
217 | "###, | 217 | "###, |
218 | r####" | 218 | r####" |
219 | fn f() { | 219 | fn f() { |
220 | let s = <|>r###"#random"## | 220 | let s = r###"#random"## |
221 | string"###; | 221 | string"###; |
222 | } | 222 | } |
223 | "####, | 223 | "####, |
@@ -235,7 +235,7 @@ string"###; | |||
235 | "#, | 235 | "#, |
236 | r##" | 236 | r##" |
237 | fn f() { | 237 | fn f() { |
238 | let s = <|>r#"random string"#; | 238 | let s = r#"random string"#; |
239 | } | 239 | } |
240 | "##, | 240 | "##, |
241 | ) | 241 | ) |
@@ -289,7 +289,7 @@ string"###; | |||
289 | "#, | 289 | "#, |
290 | r##" | 290 | r##" |
291 | fn f() { | 291 | fn f() { |
292 | let s = <|>r#"random string"#; | 292 | let s = r#"random string"#; |
293 | } | 293 | } |
294 | "##, | 294 | "##, |
295 | ) | 295 | ) |
@@ -306,7 +306,7 @@ string"###; | |||
306 | "##, | 306 | "##, |
307 | r###" | 307 | r###" |
308 | fn f() { | 308 | fn f() { |
309 | let s = <|>r##"random"string"##; | 309 | let s = r##"random"string"##; |
310 | } | 310 | } |
311 | "###, | 311 | "###, |
312 | ) | 312 | ) |
@@ -348,7 +348,7 @@ string"###; | |||
348 | "##, | 348 | "##, |
349 | r#" | 349 | r#" |
350 | fn f() { | 350 | fn f() { |
351 | let s = <|>r"random string"; | 351 | let s = r"random string"; |
352 | } | 352 | } |
353 | "#, | 353 | "#, |
354 | ) | 354 | ) |
@@ -365,7 +365,7 @@ string"###; | |||
365 | "##, | 365 | "##, |
366 | r#" | 366 | r#" |
367 | fn f() { | 367 | fn f() { |
368 | let s = <|>r"random\"str\"ing"; | 368 | let s = r"random\"str\"ing"; |
369 | } | 369 | } |
370 | "#, | 370 | "#, |
371 | ) | 371 | ) |
@@ -382,7 +382,7 @@ string"###; | |||
382 | "###, | 382 | "###, |
383 | r##" | 383 | r##" |
384 | fn f() { | 384 | fn f() { |
385 | let s = <|>r#"random string"#; | 385 | let s = r#"random string"#; |
386 | } | 386 | } |
387 | "##, | 387 | "##, |
388 | ) | 388 | ) |
@@ -436,7 +436,7 @@ string"###; | |||
436 | "##, | 436 | "##, |
437 | r#" | 437 | r#" |
438 | fn f() { | 438 | fn f() { |
439 | let s = <|>"random string"; | 439 | let s = "random string"; |
440 | } | 440 | } |
441 | "#, | 441 | "#, |
442 | ) | 442 | ) |
@@ -453,7 +453,7 @@ string"###; | |||
453 | "##, | 453 | "##, |
454 | r#" | 454 | r#" |
455 | fn f() { | 455 | fn f() { |
456 | let s = <|>"random\"str\"ing"; | 456 | let s = "random\"str\"ing"; |
457 | } | 457 | } |
458 | "#, | 458 | "#, |
459 | ) | 459 | ) |
@@ -470,7 +470,7 @@ string"###; | |||
470 | "###, | 470 | "###, |
471 | r##" | 471 | r##" |
472 | fn f() { | 472 | fn f() { |
473 | let s = <|>"random string"; | 473 | let s = "random string"; |
474 | } | 474 | } |
475 | "##, | 475 | "##, |
476 | ) | 476 | ) |
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs index 8eef578cf..961ee1731 100644 --- a/crates/ra_assists/src/handlers/remove_dbg.rs +++ b/crates/ra_assists/src/handlers/remove_dbg.rs | |||
@@ -29,26 +29,6 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
29 | 29 | ||
30 | let macro_range = macro_call.syntax().text_range(); | 30 | let macro_range = macro_call.syntax().text_range(); |
31 | 31 | ||
32 | // If the cursor is inside the macro call, we'll try to maintain the cursor | ||
33 | // position by subtracting the length of dbg!( from the start of the file | ||
34 | // range, otherwise we'll default to using the start of the macro call | ||
35 | let cursor_pos = { | ||
36 | let file_range = ctx.frange.range; | ||
37 | |||
38 | let offset_start = file_range | ||
39 | .start() | ||
40 | .checked_sub(macro_range.start()) | ||
41 | .unwrap_or_else(|| TextSize::from(0)); | ||
42 | |||
43 | let dbg_size = TextSize::of("dbg!("); | ||
44 | |||
45 | if offset_start > dbg_size { | ||
46 | file_range.start() - dbg_size | ||
47 | } else { | ||
48 | macro_range.start() | ||
49 | } | ||
50 | }; | ||
51 | |||
52 | let macro_content = { | 32 | let macro_content = { |
53 | let macro_args = macro_call.token_tree()?.syntax().clone(); | 33 | let macro_args = macro_call.token_tree()?.syntax().clone(); |
54 | 34 | ||
@@ -58,9 +38,8 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
58 | }; | 38 | }; |
59 | 39 | ||
60 | let target = macro_call.syntax().text_range(); | 40 | let target = macro_call.syntax().text_range(); |
61 | acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| { | 41 | acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |builder| { |
62 | edit.replace(macro_range, macro_content); | 42 | builder.replace(macro_range, macro_content); |
63 | edit.set_cursor(cursor_pos); | ||
64 | }) | 43 | }) |
65 | } | 44 | } |
66 | 45 | ||
@@ -94,13 +73,13 @@ mod tests { | |||
94 | 73 | ||
95 | #[test] | 74 | #[test] |
96 | fn test_remove_dbg() { | 75 | fn test_remove_dbg() { |
97 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "<|>1 + 1"); | 76 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1"); |
98 | 77 | ||
99 | check_assist(remove_dbg, "dbg!<|>((1 + 1))", "<|>(1 + 1)"); | 78 | check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)"); |
100 | 79 | ||
101 | check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 <|>+ 1"); | 80 | check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1"); |
102 | 81 | ||
103 | check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = <|>1 + 1"); | 82 | check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1"); |
104 | 83 | ||
105 | check_assist( | 84 | check_assist( |
106 | remove_dbg, | 85 | remove_dbg, |
@@ -113,7 +92,7 @@ fn foo(n: usize) { | |||
113 | ", | 92 | ", |
114 | " | 93 | " |
115 | fn foo(n: usize) { | 94 | fn foo(n: usize) { |
116 | if let Some(_) = n.<|>checked_sub(4) { | 95 | if let Some(_) = n.checked_sub(4) { |
117 | // ... | 96 | // ... |
118 | } | 97 | } |
119 | } | 98 | } |
@@ -122,8 +101,8 @@ fn foo(n: usize) { | |||
122 | } | 101 | } |
123 | #[test] | 102 | #[test] |
124 | fn test_remove_dbg_with_brackets_and_braces() { | 103 | fn test_remove_dbg_with_brackets_and_braces() { |
125 | check_assist(remove_dbg, "dbg![<|>1 + 1]", "<|>1 + 1"); | 104 | check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1"); |
126 | check_assist(remove_dbg, "dbg!{<|>1 + 1}", "<|>1 + 1"); | 105 | check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1"); |
127 | } | 106 | } |
128 | 107 | ||
129 | #[test] | 108 | #[test] |
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs index dce546db7..fe4eada03 100644 --- a/crates/ra_assists/src/handlers/remove_mut.rs +++ b/crates/ra_assists/src/handlers/remove_mut.rs | |||
@@ -26,8 +26,7 @@ pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | let target = mut_token.text_range(); | 28 | let target = mut_token.text_range(); |
29 | acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { | 29 | acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |builder| { |
30 | edit.set_cursor(delete_from); | 30 | builder.delete(TextRange::new(delete_from, delete_to)); |
31 | edit.delete(TextRange::new(delete_from, delete_to)); | ||
32 | }) | 31 | }) |
33 | } | 32 | } |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 757f6406e..897da2832 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
23 | // ``` | 23 | // ``` |
24 | // | 24 | // |
25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | reorder::<ast::RecordLit>(acc, ctx.clone()).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) | 26 | reorder::<ast::RecordLit>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) |
27 | } | 27 | } |
28 | 28 | ||
29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -140,7 +140,7 @@ mod tests { | |||
140 | "#, | 140 | "#, |
141 | r#" | 141 | r#" |
142 | struct Foo {foo: i32, bar: i32}; | 142 | struct Foo {foo: i32, bar: i32}; |
143 | const test: Foo = <|>Foo {foo: 1, bar: 0} | 143 | const test: Foo = Foo {foo: 1, bar: 0} |
144 | "#, | 144 | "#, |
145 | ) | 145 | ) |
146 | } | 146 | } |
@@ -164,7 +164,7 @@ mod tests { | |||
164 | 164 | ||
165 | fn f(f: Foo) -> { | 165 | fn f(f: Foo) -> { |
166 | match f { | 166 | match f { |
167 | <|>Foo { ref mut bar, baz: 0, .. } => (), | 167 | Foo { ref mut bar, baz: 0, .. } => (), |
168 | _ => () | 168 | _ => () |
169 | } | 169 | } |
170 | } | 170 | } |
@@ -202,7 +202,7 @@ mod tests { | |||
202 | impl Foo { | 202 | impl Foo { |
203 | fn new() -> Foo { | 203 | fn new() -> Foo { |
204 | let foo = String::new(); | 204 | let foo = String::new(); |
205 | <|>Foo { | 205 | Foo { |
206 | foo, | 206 | foo, |
207 | bar: foo.clone(), | 207 | bar: foo.clone(), |
208 | extra: "Extra field", | 208 | extra: "Extra field", |
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index 65f5fc6ab..e016f51c3 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -68,7 +68,6 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
68 | .indent(IndentLevel::from_node(if_expr.syntax())) | 68 | .indent(IndentLevel::from_node(if_expr.syntax())) |
69 | }; | 69 | }; |
70 | 70 | ||
71 | edit.set_cursor(if_expr.syntax().text_range().start()); | ||
72 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); | 71 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); |
73 | }) | 72 | }) |
74 | } | 73 | } |
@@ -83,7 +82,7 @@ mod tests { | |||
83 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { | 82 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { |
84 | check_assist( | 83 | check_assist( |
85 | replace_if_let_with_match, | 84 | replace_if_let_with_match, |
86 | " | 85 | r#" |
87 | impl VariantData { | 86 | impl VariantData { |
88 | pub fn is_struct(&self) -> bool { | 87 | pub fn is_struct(&self) -> bool { |
89 | if <|>let VariantData::Struct(..) = *self { | 88 | if <|>let VariantData::Struct(..) = *self { |
@@ -92,16 +91,16 @@ impl VariantData { | |||
92 | false | 91 | false |
93 | } | 92 | } |
94 | } | 93 | } |
95 | } ", | 94 | } "#, |
96 | " | 95 | r#" |
97 | impl VariantData { | 96 | impl VariantData { |
98 | pub fn is_struct(&self) -> bool { | 97 | pub fn is_struct(&self) -> bool { |
99 | <|>match *self { | 98 | match *self { |
100 | VariantData::Struct(..) => true, | 99 | VariantData::Struct(..) => true, |
101 | _ => false, | 100 | _ => false, |
102 | } | 101 | } |
103 | } | 102 | } |
104 | } ", | 103 | } "#, |
105 | ) | 104 | ) |
106 | } | 105 | } |
107 | 106 | ||
@@ -109,7 +108,7 @@ impl VariantData { | |||
109 | fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() { | 108 | fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() { |
110 | check_assist( | 109 | check_assist( |
111 | replace_if_let_with_match, | 110 | replace_if_let_with_match, |
112 | " | 111 | r#" |
113 | fn foo() { | 112 | fn foo() { |
114 | if <|>let VariantData::Struct(..) = a { | 113 | if <|>let VariantData::Struct(..) = a { |
115 | bar( | 114 | bar( |
@@ -118,10 +117,10 @@ fn foo() { | |||
118 | } else { | 117 | } else { |
119 | false | 118 | false |
120 | } | 119 | } |
121 | } ", | 120 | } "#, |
122 | " | 121 | r#" |
123 | fn foo() { | 122 | fn foo() { |
124 | <|>match a { | 123 | match a { |
125 | VariantData::Struct(..) => { | 124 | VariantData::Struct(..) => { |
126 | bar( | 125 | bar( |
127 | 123 | 126 | 123 |
@@ -129,7 +128,7 @@ fn foo() { | |||
129 | } | 128 | } |
130 | _ => false, | 129 | _ => false, |
131 | } | 130 | } |
132 | } ", | 131 | } "#, |
133 | ) | 132 | ) |
134 | } | 133 | } |
135 | 134 | ||
@@ -137,7 +136,7 @@ fn foo() { | |||
137 | fn replace_if_let_with_match_target() { | 136 | fn replace_if_let_with_match_target() { |
138 | check_assist_target( | 137 | check_assist_target( |
139 | replace_if_let_with_match, | 138 | replace_if_let_with_match, |
140 | " | 139 | r#" |
141 | impl VariantData { | 140 | impl VariantData { |
142 | pub fn is_struct(&self) -> bool { | 141 | pub fn is_struct(&self) -> bool { |
143 | if <|>let VariantData::Struct(..) = *self { | 142 | if <|>let VariantData::Struct(..) = *self { |
@@ -146,7 +145,7 @@ impl VariantData { | |||
146 | false | 145 | false |
147 | } | 146 | } |
148 | } | 147 | } |
149 | } ", | 148 | } "#, |
150 | "if let VariantData::Struct(..) = *self { | 149 | "if let VariantData::Struct(..) = *self { |
151 | true | 150 | true |
152 | } else { | 151 | } else { |
@@ -176,7 +175,7 @@ enum Option<T> { Some(T), None } | |||
176 | use Option::*; | 175 | use Option::*; |
177 | 176 | ||
178 | fn foo(x: Option<i32>) { | 177 | fn foo(x: Option<i32>) { |
179 | <|>match x { | 178 | match x { |
180 | Some(x) => println!("{}", x), | 179 | Some(x) => println!("{}", x), |
181 | None => println!("none"), | 180 | None => println!("none"), |
182 | } | 181 | } |
@@ -206,7 +205,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
206 | use Result::*; | 205 | use Result::*; |
207 | 206 | ||
208 | fn foo(x: Result<i32, ()>) { | 207 | fn foo(x: Result<i32, ()>) { |
209 | <|>match x { | 208 | match x { |
210 | Ok(x) => println!("{}", x), | 209 | Ok(x) => println!("{}", x), |
211 | Err(_) => println!("none"), | 210 | Err(_) => println!("none"), |
212 | } | 211 | } |
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs index 482957dc6..761557ac0 100644 --- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -58,12 +58,9 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> | |||
58 | let stmt = make::expr_stmt(if_); | 58 | let stmt = make::expr_stmt(if_); |
59 | 59 | ||
60 | let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); | 60 | let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); |
61 | let target_offset = | ||
62 | let_stmt.syntax().text_range().start() + placeholder.syntax().text_range().start(); | ||
63 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); | 61 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); |
64 | 62 | ||
65 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); | 63 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); |
66 | edit.set_cursor(target_offset); | ||
67 | }) | 64 | }) |
68 | } | 65 | } |
69 | 66 | ||
@@ -88,7 +85,7 @@ fn main() { | |||
88 | enum E<T> { X(T), Y(T) } | 85 | enum E<T> { X(T), Y(T) } |
89 | 86 | ||
90 | fn main() { | 87 | fn main() { |
91 | if let <|>x = E::X(92) { | 88 | if let x = E::X(92) { |
92 | } | 89 | } |
93 | } | 90 | } |
94 | ", | 91 | ", |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index d9f84208d..0197a8cf0 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -89,7 +89,7 @@ std::fmt::Debug<|> | |||
89 | " | 89 | " |
90 | use std::fmt::Debug; | 90 | use std::fmt::Debug; |
91 | 91 | ||
92 | Debug<|> | 92 | Debug |
93 | ", | 93 | ", |
94 | ); | 94 | ); |
95 | } | 95 | } |
@@ -106,7 +106,7 @@ fn main() { | |||
106 | " | 106 | " |
107 | use std::fmt::Debug; | 107 | use std::fmt::Debug; |
108 | 108 | ||
109 | Debug<|> | 109 | Debug |
110 | 110 | ||
111 | fn main() { | 111 | fn main() { |
112 | } | 112 | } |
@@ -130,7 +130,7 @@ use std::fmt::Debug; | |||
130 | fn main() { | 130 | fn main() { |
131 | } | 131 | } |
132 | 132 | ||
133 | Debug<|> | 133 | Debug |
134 | ", | 134 | ", |
135 | ); | 135 | ); |
136 | } | 136 | } |
@@ -145,7 +145,7 @@ std::fmt<|>::Debug | |||
145 | " | 145 | " |
146 | use std::fmt; | 146 | use std::fmt; |
147 | 147 | ||
148 | fmt<|>::Debug | 148 | fmt::Debug |
149 | ", | 149 | ", |
150 | ); | 150 | ); |
151 | } | 151 | } |
@@ -164,7 +164,7 @@ impl std::fmt::Debug<|> for Foo { | |||
164 | use stdx; | 164 | use stdx; |
165 | use std::fmt::Debug; | 165 | use std::fmt::Debug; |
166 | 166 | ||
167 | impl Debug<|> for Foo { | 167 | impl Debug for Foo { |
168 | } | 168 | } |
169 | ", | 169 | ", |
170 | ); | 170 | ); |
@@ -181,7 +181,7 @@ impl std::fmt::Debug<|> for Foo { | |||
181 | " | 181 | " |
182 | use std::fmt::Debug; | 182 | use std::fmt::Debug; |
183 | 183 | ||
184 | impl Debug<|> for Foo { | 184 | impl Debug for Foo { |
185 | } | 185 | } |
186 | ", | 186 | ", |
187 | ); | 187 | ); |
@@ -198,7 +198,7 @@ impl Debug<|> for Foo { | |||
198 | " | 198 | " |
199 | use std::fmt::Debug; | 199 | use std::fmt::Debug; |
200 | 200 | ||
201 | impl Debug<|> for Foo { | 201 | impl Debug for Foo { |
202 | } | 202 | } |
203 | ", | 203 | ", |
204 | ); | 204 | ); |
@@ -217,7 +217,7 @@ impl std::io<|> for Foo { | |||
217 | " | 217 | " |
218 | use std::{io, fmt}; | 218 | use std::{io, fmt}; |
219 | 219 | ||
220 | impl io<|> for Foo { | 220 | impl io for Foo { |
221 | } | 221 | } |
222 | ", | 222 | ", |
223 | ); | 223 | ); |
@@ -236,7 +236,7 @@ impl std::fmt::Debug<|> for Foo { | |||
236 | " | 236 | " |
237 | use std::fmt::{self, Debug, }; | 237 | use std::fmt::{self, Debug, }; |
238 | 238 | ||
239 | impl Debug<|> for Foo { | 239 | impl Debug for Foo { |
240 | } | 240 | } |
241 | ", | 241 | ", |
242 | ); | 242 | ); |
@@ -255,7 +255,7 @@ impl std::fmt<|> for Foo { | |||
255 | " | 255 | " |
256 | use std::fmt::{self, Debug}; | 256 | use std::fmt::{self, Debug}; |
257 | 257 | ||
258 | impl fmt<|> for Foo { | 258 | impl fmt for Foo { |
259 | } | 259 | } |
260 | ", | 260 | ", |
261 | ); | 261 | ); |
@@ -274,7 +274,7 @@ impl std::fmt::nested<|> for Foo { | |||
274 | " | 274 | " |
275 | use std::fmt::{Debug, nested::{Display, self}}; | 275 | use std::fmt::{Debug, nested::{Display, self}}; |
276 | 276 | ||
277 | impl nested<|> for Foo { | 277 | impl nested for Foo { |
278 | } | 278 | } |
279 | ", | 279 | ", |
280 | ); | 280 | ); |
@@ -293,7 +293,7 @@ impl std::fmt::nested<|> for Foo { | |||
293 | " | 293 | " |
294 | use std::fmt::{Debug, nested::{self, Display}}; | 294 | use std::fmt::{Debug, nested::{self, Display}}; |
295 | 295 | ||
296 | impl nested<|> for Foo { | 296 | impl nested for Foo { |
297 | } | 297 | } |
298 | ", | 298 | ", |
299 | ); | 299 | ); |
@@ -312,7 +312,7 @@ impl std::fmt::nested::Debug<|> for Foo { | |||
312 | " | 312 | " |
313 | use std::fmt::{Debug, nested::{Display, Debug}}; | 313 | use std::fmt::{Debug, nested::{Display, Debug}}; |
314 | 314 | ||
315 | impl Debug<|> for Foo { | 315 | impl Debug for Foo { |
316 | } | 316 | } |
317 | ", | 317 | ", |
318 | ); | 318 | ); |
@@ -331,7 +331,7 @@ impl std::fmt::nested::Display<|> for Foo { | |||
331 | " | 331 | " |
332 | use std::fmt::{nested::Display, Debug}; | 332 | use std::fmt::{nested::Display, Debug}; |
333 | 333 | ||
334 | impl Display<|> for Foo { | 334 | impl Display for Foo { |
335 | } | 335 | } |
336 | ", | 336 | ", |
337 | ); | 337 | ); |
@@ -350,7 +350,7 @@ impl std::fmt::Display<|> for Foo { | |||
350 | " | 350 | " |
351 | use std::fmt::{Display, nested::Debug}; | 351 | use std::fmt::{Display, nested::Debug}; |
352 | 352 | ||
353 | impl Display<|> for Foo { | 353 | impl Display for Foo { |
354 | } | 354 | } |
355 | ", | 355 | ", |
356 | ); | 356 | ); |
@@ -374,7 +374,7 @@ use crate::{ | |||
374 | AssocItem, | 374 | AssocItem, |
375 | }; | 375 | }; |
376 | 376 | ||
377 | fn foo() { lower<|>::trait_env() } | 377 | fn foo() { lower::trait_env() } |
378 | ", | 378 | ", |
379 | ); | 379 | ); |
380 | } | 380 | } |
@@ -392,7 +392,7 @@ impl foo::Debug<|> for Foo { | |||
392 | " | 392 | " |
393 | use std::fmt as foo; | 393 | use std::fmt as foo; |
394 | 394 | ||
395 | impl Debug<|> for Foo { | 395 | impl Debug for Foo { |
396 | } | 396 | } |
397 | ", | 397 | ", |
398 | ); | 398 | ); |
@@ -435,7 +435,7 @@ mod foo { | |||
435 | mod bar { | 435 | mod bar { |
436 | use std::fmt::Debug; | 436 | use std::fmt::Debug; |
437 | 437 | ||
438 | Debug<|> | 438 | Debug |
439 | } | 439 | } |
440 | } | 440 | } |
441 | ", | 441 | ", |
@@ -458,7 +458,7 @@ fn main() { | |||
458 | use std::fmt::Debug; | 458 | use std::fmt::Debug; |
459 | 459 | ||
460 | fn main() { | 460 | fn main() { |
461 | Debug<|> | 461 | Debug |
462 | } | 462 | } |
463 | ", | 463 | ", |
464 | ); | 464 | ); |
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs index b379b55a8..cff7dfb81 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -9,7 +9,10 @@ use ra_syntax::{ | |||
9 | AstNode, | 9 | AstNode, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; | 12 | use crate::{ |
13 | utils::{render_snippet, Cursor, TryEnum}, | ||
14 | AssistContext, AssistId, Assists, | ||
15 | }; | ||
13 | 16 | ||
14 | // Assist: replace_unwrap_with_match | 17 | // Assist: replace_unwrap_with_match |
15 | // | 18 | // |
@@ -29,7 +32,7 @@ use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; | |||
29 | // let x: Result<i32, i32> = Result::Ok(92); | 32 | // let x: Result<i32, i32> = Result::Ok(92); |
30 | // let y = match x { | 33 | // let y = match x { |
31 | // Ok(a) => a, | 34 | // Ok(a) => a, |
32 | // _ => unreachable!(), | 35 | // $0_ => unreachable!(), |
33 | // }; | 36 | // }; |
34 | // } | 37 | // } |
35 | // ``` | 38 | // ``` |
@@ -43,7 +46,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
43 | let ty = ctx.sema.type_of_expr(&caller)?; | 46 | let ty = ctx.sema.type_of_expr(&caller)?; |
44 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); | 47 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); |
45 | let target = method_call.syntax().text_range(); | 48 | let target = method_call.syntax().text_range(); |
46 | acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |edit| { | 49 | acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |builder| { |
47 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | 50 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); |
48 | let it = make::bind_pat(make::name("a")).into(); | 51 | let it = make::bind_pat(make::name("a")).into(); |
49 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | 52 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); |
@@ -58,16 +61,30 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
58 | let match_expr = make::expr_match(caller.clone(), match_arm_list) | 61 | let match_expr = make::expr_match(caller.clone(), match_arm_list) |
59 | .indent(IndentLevel::from_node(method_call.syntax())); | 62 | .indent(IndentLevel::from_node(method_call.syntax())); |
60 | 63 | ||
61 | edit.set_cursor(caller.syntax().text_range().start()); | 64 | let range = method_call.syntax().text_range(); |
62 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); | 65 | match ctx.config.snippet_cap { |
66 | Some(cap) => { | ||
67 | let err_arm = match_expr | ||
68 | .syntax() | ||
69 | .descendants() | ||
70 | .filter_map(ast::MatchArm::cast) | ||
71 | .last() | ||
72 | .unwrap(); | ||
73 | let snippet = | ||
74 | render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax())); | ||
75 | builder.replace_snippet(cap, range, snippet) | ||
76 | } | ||
77 | None => builder.replace(range, match_expr.to_string()), | ||
78 | } | ||
63 | }) | 79 | }) |
64 | } | 80 | } |
65 | 81 | ||
66 | #[cfg(test)] | 82 | #[cfg(test)] |
67 | mod tests { | 83 | mod tests { |
68 | use super::*; | ||
69 | use crate::tests::{check_assist, check_assist_target}; | 84 | use crate::tests::{check_assist, check_assist_target}; |
70 | 85 | ||
86 | use super::*; | ||
87 | |||
71 | #[test] | 88 | #[test] |
72 | fn test_replace_result_unwrap_with_match() { | 89 | fn test_replace_result_unwrap_with_match() { |
73 | check_assist( | 90 | check_assist( |
@@ -85,9 +102,9 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
85 | fn i<T>(a: T) -> T { a } | 102 | fn i<T>(a: T) -> T { a } |
86 | fn main() { | 103 | fn main() { |
87 | let x: Result<i32, i32> = Result::Ok(92); | 104 | let x: Result<i32, i32> = Result::Ok(92); |
88 | let y = <|>match i(x) { | 105 | let y = match i(x) { |
89 | Ok(a) => a, | 106 | Ok(a) => a, |
90 | _ => unreachable!(), | 107 | $0_ => unreachable!(), |
91 | }; | 108 | }; |
92 | } | 109 | } |
93 | ", | 110 | ", |
@@ -111,9 +128,9 @@ enum Option<T> { Some(T), None } | |||
111 | fn i<T>(a: T) -> T { a } | 128 | fn i<T>(a: T) -> T { a } |
112 | fn main() { | 129 | fn main() { |
113 | let x = Option::Some(92); | 130 | let x = Option::Some(92); |
114 | let y = <|>match i(x) { | 131 | let y = match i(x) { |
115 | Some(a) => a, | 132 | Some(a) => a, |
116 | _ => unreachable!(), | 133 | $0_ => unreachable!(), |
117 | }; | 134 | }; |
118 | } | 135 | } |
119 | ", | 136 | ", |
@@ -137,9 +154,9 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
137 | fn i<T>(a: T) -> T { a } | 154 | fn i<T>(a: T) -> T { a } |
138 | fn main() { | 155 | fn main() { |
139 | let x: Result<i32, i32> = Result::Ok(92); | 156 | let x: Result<i32, i32> = Result::Ok(92); |
140 | let y = <|>match i(x) { | 157 | let y = match i(x) { |
141 | Ok(a) => a, | 158 | Ok(a) => a, |
142 | _ => unreachable!(), | 159 | $0_ => unreachable!(), |
143 | }.count_zeroes(); | 160 | }.count_zeroes(); |
144 | } | 161 | } |
145 | ", | 162 | ", |
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index b2757e50c..c7a874480 100644 --- a/crates/ra_assists/src/handlers/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs | |||
@@ -26,12 +26,10 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
26 | if new_tree == use_tree { | 26 | if new_tree == use_tree { |
27 | return None; | 27 | return None; |
28 | } | 28 | } |
29 | let cursor = ctx.offset(); | ||
30 | 29 | ||
31 | let target = colon_colon.text_range(); | 30 | let target = colon_colon.text_range(); |
32 | acc.add(AssistId("split_import"), "Split import", target, |edit| { | 31 | acc.add(AssistId("split_import"), "Split import", target, |edit| { |
33 | edit.replace_ast(use_tree, new_tree); | 32 | edit.replace_ast(use_tree, new_tree); |
34 | edit.set_cursor(cursor); | ||
35 | }) | 33 | }) |
36 | } | 34 | } |
37 | 35 | ||
@@ -46,7 +44,7 @@ mod tests { | |||
46 | check_assist( | 44 | check_assist( |
47 | split_import, | 45 | split_import, |
48 | "use crate::<|>db::RootDatabase;", | 46 | "use crate::<|>db::RootDatabase;", |
49 | "use crate::<|>{db::RootDatabase};", | 47 | "use crate::{db::RootDatabase};", |
50 | ) | 48 | ) |
51 | } | 49 | } |
52 | 50 | ||
@@ -55,7 +53,7 @@ mod tests { | |||
55 | check_assist( | 53 | check_assist( |
56 | split_import, | 54 | split_import, |
57 | "use crate:<|>:db::{RootDatabase, FileSymbol}", | 55 | "use crate:<|>:db::{RootDatabase, FileSymbol}", |
58 | "use crate:<|>:{db::{RootDatabase, FileSymbol}}", | 56 | "use crate::{db::{RootDatabase, FileSymbol}}", |
59 | ) | 57 | ) |
60 | } | 58 | } |
61 | 59 | ||
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index e52ec557e..8440c7d0f 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | use crate::{AssistContext, AssistId, Assists}; | ||
2 | |||
3 | use ast::{ElseBranch, Expr, LoopBodyOwner}; | ||
4 | use ra_fmt::unwrap_trivial_block; | 1 | use ra_fmt::unwrap_trivial_block; |
5 | use ra_syntax::{ast, match_ast, AstNode, TextRange, T}; | 2 | use ra_syntax::{ |
3 | ast::{self, ElseBranch, Expr, LoopBodyOwner}, | ||
4 | match_ast, AstNode, TextRange, T, | ||
5 | }; | ||
6 | |||
7 | use crate::{AssistContext, AssistId, Assists}; | ||
6 | 8 | ||
7 | // Assist: unwrap_block | 9 | // Assist: unwrap_block |
8 | // | 10 | // |
@@ -60,7 +62,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
60 | let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); | 62 | let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); |
61 | let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end()); | 63 | let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end()); |
62 | 64 | ||
63 | edit.set_cursor(ancestor_then_branch.syntax().text_range().end()); | ||
64 | edit.delete(range_to_del_rest); | 65 | edit.delete(range_to_del_rest); |
65 | edit.delete(range_to_del_else_if); | 66 | edit.delete(range_to_del_else_if); |
66 | edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{'])); | 67 | edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{'])); |
@@ -77,7 +78,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
77 | return acc.add(assist_id, assist_label, target, |edit| { | 78 | return acc.add(assist_id, assist_label, target, |edit| { |
78 | let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); | 79 | let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); |
79 | 80 | ||
80 | edit.set_cursor(then_branch.syntax().text_range().end()); | ||
81 | edit.delete(range_to_del); | 81 | edit.delete(range_to_del); |
82 | edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{'])); | 82 | edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{'])); |
83 | }); | 83 | }); |
@@ -95,8 +95,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
95 | 95 | ||
96 | let target = expr_to_unwrap.syntax().text_range(); | 96 | let target = expr_to_unwrap.syntax().text_range(); |
97 | acc.add(assist_id, assist_label, target, |edit| { | 97 | acc.add(assist_id, assist_label, target, |edit| { |
98 | edit.set_cursor(expr.syntax().text_range().start()); | ||
99 | |||
100 | edit.replace( | 98 | edit.replace( |
101 | expr.syntax().text_range(), | 99 | expr.syntax().text_range(), |
102 | update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), | 100 | update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), |
@@ -152,7 +150,7 @@ mod tests { | |||
152 | r#" | 150 | r#" |
153 | fn main() { | 151 | fn main() { |
154 | bar(); | 152 | bar(); |
155 | <|>foo(); | 153 | foo(); |
156 | 154 | ||
157 | //comment | 155 | //comment |
158 | bar(); | 156 | bar(); |
@@ -186,7 +184,7 @@ mod tests { | |||
186 | 184 | ||
187 | //comment | 185 | //comment |
188 | bar(); | 186 | bar(); |
189 | }<|> | 187 | } |
190 | println!("bar"); | 188 | println!("bar"); |
191 | } | 189 | } |
192 | "#, | 190 | "#, |
@@ -220,7 +218,7 @@ mod tests { | |||
220 | 218 | ||
221 | //comment | 219 | //comment |
222 | //bar(); | 220 | //bar(); |
223 | }<|> | 221 | } |
224 | println!("bar"); | 222 | println!("bar"); |
225 | } | 223 | } |
226 | "#, | 224 | "#, |
@@ -256,7 +254,7 @@ mod tests { | |||
256 | //bar(); | 254 | //bar(); |
257 | } else if false { | 255 | } else if false { |
258 | println!("bar"); | 256 | println!("bar"); |
259 | }<|> | 257 | } |
260 | println!("foo"); | 258 | println!("foo"); |
261 | } | 259 | } |
262 | "#, | 260 | "#, |
@@ -296,7 +294,7 @@ mod tests { | |||
296 | println!("bar"); | 294 | println!("bar"); |
297 | } else if true { | 295 | } else if true { |
298 | println!("foo"); | 296 | println!("foo"); |
299 | }<|> | 297 | } |
300 | println!("else"); | 298 | println!("else"); |
301 | } | 299 | } |
302 | "#, | 300 | "#, |
@@ -334,7 +332,7 @@ mod tests { | |||
334 | //bar(); | 332 | //bar(); |
335 | } else if false { | 333 | } else if false { |
336 | println!("bar"); | 334 | println!("bar"); |
337 | }<|> | 335 | } |
338 | println!("foo"); | 336 | println!("foo"); |
339 | } | 337 | } |
340 | "#, | 338 | "#, |
@@ -381,7 +379,7 @@ mod tests { | |||
381 | "#, | 379 | "#, |
382 | r#" | 380 | r#" |
383 | fn main() { | 381 | fn main() { |
384 | <|>if true { | 382 | if true { |
385 | foo(); | 383 | foo(); |
386 | 384 | ||
387 | //comment | 385 | //comment |
@@ -415,7 +413,7 @@ mod tests { | |||
415 | r#" | 413 | r#" |
416 | fn main() { | 414 | fn main() { |
417 | for i in 0..5 { | 415 | for i in 0..5 { |
418 | <|>foo(); | 416 | foo(); |
419 | 417 | ||
420 | //comment | 418 | //comment |
421 | bar(); | 419 | bar(); |
@@ -445,7 +443,7 @@ mod tests { | |||
445 | "#, | 443 | "#, |
446 | r#" | 444 | r#" |
447 | fn main() { | 445 | fn main() { |
448 | <|>if true { | 446 | if true { |
449 | foo(); | 447 | foo(); |
450 | 448 | ||
451 | //comment | 449 | //comment |
@@ -478,7 +476,7 @@ mod tests { | |||
478 | "#, | 476 | "#, |
479 | r#" | 477 | r#" |
480 | fn main() { | 478 | fn main() { |
481 | <|>if true { | 479 | if true { |
482 | foo(); | 480 | foo(); |
483 | 481 | ||
484 | //comment | 482 | //comment |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 339f24100..464bc03dd 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -12,7 +12,6 @@ macro_rules! eprintln { | |||
12 | 12 | ||
13 | mod assist_config; | 13 | mod assist_config; |
14 | mod assist_context; | 14 | mod assist_context; |
15 | mod marks; | ||
16 | #[cfg(test)] | 15 | #[cfg(test)] |
17 | mod tests; | 16 | mod tests; |
18 | pub mod utils; | 17 | pub mod utils; |
@@ -117,6 +116,7 @@ mod handlers { | |||
117 | mod change_visibility; | 116 | mod change_visibility; |
118 | mod early_return; | 117 | mod early_return; |
119 | mod fill_match_arms; | 118 | mod fill_match_arms; |
119 | mod fix_visibility; | ||
120 | mod flip_binexpr; | 120 | mod flip_binexpr; |
121 | mod flip_comma; | 121 | mod flip_comma; |
122 | mod flip_trait_bound; | 122 | mod flip_trait_bound; |
@@ -155,6 +155,7 @@ mod handlers { | |||
155 | change_visibility::change_visibility, | 155 | change_visibility::change_visibility, |
156 | early_return::convert_to_guarded_return, | 156 | early_return::convert_to_guarded_return, |
157 | fill_match_arms::fill_match_arms, | 157 | fill_match_arms::fill_match_arms, |
158 | fix_visibility::fix_visibility, | ||
158 | flip_binexpr::flip_binexpr, | 159 | flip_binexpr::flip_binexpr, |
159 | flip_comma::flip_comma, | 160 | flip_comma::flip_comma, |
160 | flip_trait_bound::flip_trait_bound, | 161 | flip_trait_bound::flip_trait_bound, |
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs deleted file mode 100644 index 722f3c6a4..000000000 --- a/crates/ra_assists/src/marks.rs +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | //! See test_utils/src/marks.rs | ||
2 | |||
3 | test_utils::marks![ | ||
4 | option_order | ||
5 | introduce_var_in_comment_is_not_applicable | ||
6 | test_introduce_var_expr_stmt | ||
7 | test_introduce_var_last_expr | ||
8 | not_applicable_outside_of_bind_pat | ||
9 | test_not_inline_mut_variable | ||
10 | test_not_applicable_if_variable_unused | ||
11 | change_visibility_field_false_positive | ||
12 | test_add_from_impl_already_exists | ||
13 | add_turbo_fish_one_fish_is_enough | ||
14 | add_turbo_fish_non_generic | ||
15 | ]; | ||
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 9ba3da786..62dd3547f 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -7,8 +7,7 @@ use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | |||
7 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | 7 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; |
8 | use ra_syntax::TextRange; | 8 | use ra_syntax::TextRange; |
9 | use test_utils::{ | 9 | use test_utils::{ |
10 | add_cursor, assert_eq_text, extract_offset, extract_range, extract_range_or_offset, | 10 | assert_eq_text, extract_offset, extract_range, extract_range_or_offset, RangeOrOffset, |
11 | RangeOrOffset, | ||
12 | }; | 11 | }; |
13 | 12 | ||
14 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; | 13 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; |
@@ -103,21 +102,6 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) { | |||
103 | 102 | ||
104 | let mut actual = db.file_text(change.file_id).as_ref().to_owned(); | 103 | let mut actual = db.file_text(change.file_id).as_ref().to_owned(); |
105 | change.edit.apply(&mut actual); | 104 | change.edit.apply(&mut actual); |
106 | |||
107 | if !source_change.is_snippet { | ||
108 | match source_change.cursor_position { | ||
109 | None => { | ||
110 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { | ||
111 | let off = change | ||
112 | .edit | ||
113 | .apply_to_offset(before_cursor_pos) | ||
114 | .expect("cursor position is affected by the edit"); | ||
115 | actual = add_cursor(&actual, off) | ||
116 | } | ||
117 | } | ||
118 | Some(off) => actual = add_cursor(&actual, off.offset), | ||
119 | }; | ||
120 | } | ||
121 | assert_eq_text!(after, &actual); | 105 | assert_eq_text!(after, &actual); |
122 | } | 106 | } |
123 | (Some(assist), ExpectedResult::Target(target)) => { | 107 | (Some(assist), ExpectedResult::Target(target)) => { |
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs index cd6129dc5..250e56a69 100644 --- a/crates/ra_assists/src/tests/generated.rs +++ b/crates/ra_assists/src/tests/generated.rs | |||
@@ -336,7 +336,7 @@ enum Action { Move { distance: u32 }, Stop } | |||
336 | 336 | ||
337 | fn handle(action: Action) { | 337 | fn handle(action: Action) { |
338 | match action { | 338 | match action { |
339 | Action::Move { distance } => {} | 339 | $0Action::Move { distance } => {} |
340 | Action::Stop => {} | 340 | Action::Stop => {} |
341 | } | 341 | } |
342 | } | 342 | } |
@@ -345,6 +345,29 @@ fn handle(action: Action) { | |||
345 | } | 345 | } |
346 | 346 | ||
347 | #[test] | 347 | #[test] |
348 | fn doctest_fix_visibility() { | ||
349 | check_doc_test( | ||
350 | "fix_visibility", | ||
351 | r#####" | ||
352 | mod m { | ||
353 | fn frobnicate() {} | ||
354 | } | ||
355 | fn main() { | ||
356 | m::frobnicate<|>() {} | ||
357 | } | ||
358 | "#####, | ||
359 | r#####" | ||
360 | mod m { | ||
361 | $0pub(crate) fn frobnicate() {} | ||
362 | } | ||
363 | fn main() { | ||
364 | m::frobnicate() {} | ||
365 | } | ||
366 | "#####, | ||
367 | ) | ||
368 | } | ||
369 | |||
370 | #[test] | ||
348 | fn doctest_flip_binexpr() { | 371 | fn doctest_flip_binexpr() { |
349 | check_doc_test( | 372 | check_doc_test( |
350 | "flip_binexpr", | 373 | "flip_binexpr", |
@@ -420,7 +443,7 @@ fn main() { | |||
420 | "#####, | 443 | "#####, |
421 | r#####" | 444 | r#####" |
422 | fn main() { | 445 | fn main() { |
423 | let var_name = (1 + 2); | 446 | let $0var_name = (1 + 2); |
424 | var_name * 4; | 447 | var_name * 4; |
425 | } | 448 | } |
426 | "#####, | 449 | "#####, |
@@ -741,7 +764,7 @@ fn main() { | |||
741 | let x: Result<i32, i32> = Result::Ok(92); | 764 | let x: Result<i32, i32> = Result::Ok(92); |
742 | let y = match x { | 765 | let y = match x { |
743 | Ok(a) => a, | 766 | Ok(a) => a, |
744 | _ => unreachable!(), | 767 | $0_ => unreachable!(), |
745 | }; | 768 | }; |
746 | } | 769 | } |
747 | "#####, | 770 | "#####, |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index c69e0efea..e08d62dd6 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -15,7 +15,7 @@ use ra_syntax::{ | |||
15 | }, | 15 | }, |
16 | AstNode, AstPtr, | 16 | AstNode, AstPtr, |
17 | }; | 17 | }; |
18 | use test_utils::tested_by; | 18 | use test_utils::mark; |
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | adt::StructKind, | 21 | adt::StructKind, |
@@ -226,7 +226,7 @@ impl ExprCollector<'_> { | |||
226 | None => self.collect_expr_opt(condition.expr()), | 226 | None => self.collect_expr_opt(condition.expr()), |
227 | // if let -- desugar to match | 227 | // if let -- desugar to match |
228 | Some(pat) => { | 228 | Some(pat) => { |
229 | tested_by!(infer_resolve_while_let); | 229 | mark::hit!(infer_resolve_while_let); |
230 | let pat = self.collect_pat(pat); | 230 | let pat = self.collect_pat(pat); |
231 | let match_expr = self.collect_expr_opt(condition.expr()); | 231 | let match_expr = self.collect_expr_opt(condition.expr()); |
232 | let placeholder_pat = self.missing_pat(); | 232 | let placeholder_pat = self.missing_pat(); |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 86f953c80..09e92b74e 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -174,7 +174,7 @@ mod tests { | |||
174 | use hir_expand::{name::AsName, InFile}; | 174 | use hir_expand::{name::AsName, InFile}; |
175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; | 175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; |
176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | 176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; |
177 | use test_utils::{assert_eq_text, covers, extract_offset}; | 177 | use test_utils::{assert_eq_text, extract_offset, mark}; |
178 | 178 | ||
179 | use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId}; | 179 | use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId}; |
180 | 180 | ||
@@ -388,7 +388,7 @@ mod tests { | |||
388 | 388 | ||
389 | #[test] | 389 | #[test] |
390 | fn while_let_desugaring() { | 390 | fn while_let_desugaring() { |
391 | covers!(infer_resolve_while_let); | 391 | mark::check!(infer_resolve_while_let); |
392 | do_check_local_name( | 392 | do_check_local_name( |
393 | r#" | 393 | r#" |
394 | fn test() { | 394 | fn test() { |
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 2f71511ba..945a0025e 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -17,6 +17,7 @@ use crate::{ | |||
17 | item_scope::ItemInNs, | 17 | item_scope::ItemInNs, |
18 | lang_item::{LangItemTarget, LangItems}, | 18 | lang_item::{LangItemTarget, LangItems}, |
19 | nameres::{raw::RawItems, CrateDefMap}, | 19 | nameres::{raw::RawItems, CrateDefMap}, |
20 | path::ModPath, | ||
20 | visibility::Visibility, | 21 | visibility::Visibility, |
21 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 22 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
22 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | 23 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, |
@@ -118,6 +119,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
118 | item: ItemInNs, | 119 | item: ItemInNs, |
119 | krate: CrateId, | 120 | krate: CrateId, |
120 | ) -> Arc<[(ModuleId, Name, Visibility)]>; | 121 | ) -> Arc<[(ModuleId, Name, Visibility)]>; |
122 | |||
123 | #[salsa::invoke(find_path::find_path_inner_query)] | ||
124 | fn find_path_inner(&self, item: ItemInNs, from: ModuleId, max_len: usize) -> Option<ModPath>; | ||
121 | } | 125 | } |
122 | 126 | ||
123 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 127 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { |
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 2eb12ec8f..4db798473 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -4,7 +4,7 @@ use std::sync::Arc; | |||
4 | 4 | ||
5 | use hir_expand::name::{known, AsName, Name}; | 5 | use hir_expand::name::{known, AsName, Name}; |
6 | use ra_prof::profile; | 6 | use ra_prof::profile; |
7 | use test_utils::tested_by; | 7 | use test_utils::mark; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | db::DefDatabase, | 10 | db::DefDatabase, |
@@ -20,7 +20,7 @@ use crate::{ | |||
20 | /// *from where* you're referring to the item, hence the `from` parameter. | 20 | /// *from where* you're referring to the item, hence the `from` parameter. |
21 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 21 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { |
22 | let _p = profile("find_path"); | 22 | let _p = profile("find_path"); |
23 | find_path_inner(db, item, from, MAX_PATH_LEN) | 23 | db.find_path_inner(item, from, MAX_PATH_LEN) |
24 | } | 24 | } |
25 | 25 | ||
26 | const MAX_PATH_LEN: usize = 15; | 26 | const MAX_PATH_LEN: usize = 15; |
@@ -49,7 +49,7 @@ impl ModPath { | |||
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | fn find_path_inner( | 52 | pub(crate) fn find_path_inner_query( |
53 | db: &dyn DefDatabase, | 53 | db: &dyn DefDatabase, |
54 | item: ItemInNs, | 54 | item: ItemInNs, |
55 | from: ModuleId, | 55 | from: ModuleId, |
@@ -140,8 +140,7 @@ fn find_path_inner( | |||
140 | let mut best_path = None; | 140 | let mut best_path = None; |
141 | let mut best_path_len = max_len; | 141 | let mut best_path_len = max_len; |
142 | for (module_id, name) in importable_locations { | 142 | for (module_id, name) in importable_locations { |
143 | let mut path = match find_path_inner( | 143 | let mut path = match db.find_path_inner( |
144 | db, | ||
145 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | 144 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), |
146 | from, | 145 | from, |
147 | best_path_len - 1, | 146 | best_path_len - 1, |
@@ -164,17 +163,19 @@ fn find_path_inner( | |||
164 | 163 | ||
165 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { | 164 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { |
166 | if old_path.starts_with_std() && new_path.can_start_with_std() { | 165 | if old_path.starts_with_std() && new_path.can_start_with_std() { |
167 | tested_by!(prefer_std_paths); | ||
168 | if prefer_no_std { | 166 | if prefer_no_std { |
167 | mark::hit!(prefer_no_std_paths); | ||
169 | new_path | 168 | new_path |
170 | } else { | 169 | } else { |
170 | mark::hit!(prefer_std_paths); | ||
171 | old_path | 171 | old_path |
172 | } | 172 | } |
173 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { | 173 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { |
174 | tested_by!(prefer_std_paths); | ||
175 | if prefer_no_std { | 174 | if prefer_no_std { |
175 | mark::hit!(prefer_no_std_paths); | ||
176 | old_path | 176 | old_path |
177 | } else { | 177 | } else { |
178 | mark::hit!(prefer_std_paths); | ||
178 | new_path | 179 | new_path |
179 | } | 180 | } |
180 | } else if new_path.len() < old_path.len() { | 181 | } else if new_path.len() < old_path.len() { |
@@ -251,12 +252,14 @@ pub(crate) fn importable_locations_of_query( | |||
251 | 252 | ||
252 | #[cfg(test)] | 253 | #[cfg(test)] |
253 | mod tests { | 254 | mod tests { |
254 | use super::*; | ||
255 | use crate::test_db::TestDB; | ||
256 | use hir_expand::hygiene::Hygiene; | 255 | use hir_expand::hygiene::Hygiene; |
257 | use ra_db::fixture::WithFixture; | 256 | use ra_db::fixture::WithFixture; |
258 | use ra_syntax::ast::AstNode; | 257 | use ra_syntax::ast::AstNode; |
259 | use test_utils::covers; | 258 | use test_utils::mark; |
259 | |||
260 | use crate::test_db::TestDB; | ||
261 | |||
262 | use super::*; | ||
260 | 263 | ||
261 | /// `code` needs to contain a cursor marker; checks that `find_path` for the | 264 | /// `code` needs to contain a cursor marker; checks that `find_path` for the |
262 | /// item the `path` refers to returns that same path when called from the | 265 | /// item the `path` refers to returns that same path when called from the |
@@ -511,7 +514,7 @@ mod tests { | |||
511 | 514 | ||
512 | #[test] | 515 | #[test] |
513 | fn prefer_std_paths_over_alloc() { | 516 | fn prefer_std_paths_over_alloc() { |
514 | covers!(prefer_std_paths); | 517 | mark::check!(prefer_std_paths); |
515 | let code = r#" | 518 | let code = r#" |
516 | //- /main.rs crate:main deps:alloc,std | 519 | //- /main.rs crate:main deps:alloc,std |
517 | <|> | 520 | <|> |
@@ -530,51 +533,50 @@ mod tests { | |||
530 | } | 533 | } |
531 | 534 | ||
532 | #[test] | 535 | #[test] |
533 | fn prefer_alloc_paths_over_std() { | 536 | fn prefer_core_paths_over_std() { |
534 | covers!(prefer_std_paths); | 537 | mark::check!(prefer_no_std_paths); |
535 | let code = r#" | 538 | let code = r#" |
536 | //- /main.rs crate:main deps:alloc,std | 539 | //- /main.rs crate:main deps:core,std |
537 | #![no_std] | 540 | #![no_std] |
538 | 541 | ||
539 | <|> | 542 | <|> |
540 | 543 | ||
541 | //- /std.rs crate:std deps:alloc | 544 | //- /std.rs crate:std deps:core |
542 | 545 | ||
543 | pub mod sync { | 546 | pub mod fmt { |
544 | pub use alloc::sync::Arc; | 547 | pub use core::fmt::Error; |
545 | } | 548 | } |
546 | 549 | ||
547 | //- /zzz.rs crate:alloc | 550 | //- /zzz.rs crate:core |
548 | 551 | ||
549 | pub mod sync { | 552 | pub mod fmt { |
550 | pub struct Arc; | 553 | pub struct Error; |
551 | } | 554 | } |
552 | "#; | 555 | "#; |
553 | check_found_path(code, "alloc::sync::Arc"); | 556 | check_found_path(code, "core::fmt::Error"); |
554 | } | 557 | } |
555 | 558 | ||
556 | #[test] | 559 | #[test] |
557 | fn prefer_core_paths_over_std() { | 560 | fn prefer_alloc_paths_over_std() { |
558 | covers!(prefer_std_paths); | ||
559 | let code = r#" | 561 | let code = r#" |
560 | //- /main.rs crate:main deps:core,std | 562 | //- /main.rs crate:main deps:alloc,std |
561 | #![no_std] | 563 | #![no_std] |
562 | 564 | ||
563 | <|> | 565 | <|> |
564 | 566 | ||
565 | //- /std.rs crate:std deps:core | 567 | //- /std.rs crate:std deps:alloc |
566 | 568 | ||
567 | pub mod fmt { | 569 | pub mod sync { |
568 | pub use core::fmt::Error; | 570 | pub use alloc::sync::Arc; |
569 | } | 571 | } |
570 | 572 | ||
571 | //- /zzz.rs crate:core | 573 | //- /zzz.rs crate:alloc |
572 | 574 | ||
573 | pub mod fmt { | 575 | pub mod sync { |
574 | pub struct Error; | 576 | pub struct Arc; |
575 | } | 577 | } |
576 | "#; | 578 | "#; |
577 | check_found_path(code, "core::fmt::Error"); | 579 | check_found_path(code, "alloc::sync::Arc"); |
578 | } | 580 | } |
579 | 581 | ||
580 | #[test] | 582 | #[test] |
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs index d96ac8c0a..d962db3cc 100644 --- a/crates/ra_hir_def/src/lang_item.rs +++ b/crates/ra_hir_def/src/lang_item.rs | |||
@@ -73,8 +73,8 @@ pub struct LangItems { | |||
73 | } | 73 | } |
74 | 74 | ||
75 | impl LangItems { | 75 | impl LangItems { |
76 | pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> { | 76 | pub fn target(&self, item: &str) -> Option<LangItemTarget> { |
77 | self.items.get(item) | 77 | self.items.get(item).copied() |
78 | } | 78 | } |
79 | 79 | ||
80 | /// Salsa query. This will look for lang items in a specific crate. | 80 | /// Salsa query. This will look for lang items in a specific crate. |
@@ -163,9 +163,13 @@ impl LangItems { | |||
163 | ) where | 163 | ) where |
164 | T: Into<AttrDefId> + Copy, | 164 | T: Into<AttrDefId> + Copy, |
165 | { | 165 | { |
166 | let attrs = db.attrs(item.into()); | 166 | if let Some(lang_item_name) = lang_attr(db, item) { |
167 | if let Some(lang_item_name) = attrs.by_key("lang").string_value() { | ||
168 | self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item)); | 167 | self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item)); |
169 | } | 168 | } |
170 | } | 169 | } |
171 | } | 170 | } |
171 | |||
172 | pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Option<SmolStr> { | ||
173 | let attrs = db.attrs(item.into()); | ||
174 | attrs.by_key("lang").string_value().cloned() | ||
175 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 518772e8a..5325a2760 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -46,8 +46,6 @@ pub mod find_path; | |||
46 | 46 | ||
47 | #[cfg(test)] | 47 | #[cfg(test)] |
48 | mod test_db; | 48 | mod test_db; |
49 | #[cfg(test)] | ||
50 | mod marks; | ||
51 | 49 | ||
52 | use std::hash::Hash; | 50 | use std::hash::Hash; |
53 | 51 | ||
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs deleted file mode 100644 index daa49d5f1..000000000 --- a/crates/ra_hir_def/src/marks.rs +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | //! See test_utils/src/marks.rs | ||
2 | |||
3 | test_utils::marks!( | ||
4 | bogus_paths | ||
5 | name_res_works_for_broken_modules | ||
6 | can_import_enum_variant | ||
7 | glob_enum | ||
8 | glob_enum_group | ||
9 | glob_across_crates | ||
10 | std_prelude | ||
11 | macro_rules_from_other_crates_are_visible_with_macro_use | ||
12 | prelude_is_macro_use | ||
13 | macro_dollar_crate_self | ||
14 | macro_dollar_crate_other | ||
15 | infer_resolve_while_let | ||
16 | prefer_std_paths | ||
17 | ); | ||
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index db994122a..353a31ad4 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -14,7 +14,7 @@ use ra_cfg::CfgOptions; | |||
14 | use ra_db::{CrateId, FileId, ProcMacroId}; | 14 | use ra_db::{CrateId, FileId, ProcMacroId}; |
15 | use ra_syntax::ast; | 15 | use ra_syntax::ast; |
16 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
17 | use test_utils::tested_by; | 17 | use test_utils::mark; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | attr::Attrs, | 20 | attr::Attrs, |
@@ -302,7 +302,7 @@ impl DefCollector<'_> { | |||
302 | ); | 302 | ); |
303 | 303 | ||
304 | if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { | 304 | if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { |
305 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | 305 | mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); |
306 | self.import_all_macros_exported(current_module_id, m.krate); | 306 | self.import_all_macros_exported(current_module_id, m.krate); |
307 | } | 307 | } |
308 | } | 308 | } |
@@ -412,10 +412,10 @@ impl DefCollector<'_> { | |||
412 | match def.take_types() { | 412 | match def.take_types() { |
413 | Some(ModuleDefId::ModuleId(m)) => { | 413 | Some(ModuleDefId::ModuleId(m)) => { |
414 | if import.is_prelude { | 414 | if import.is_prelude { |
415 | tested_by!(std_prelude); | 415 | mark::hit!(std_prelude); |
416 | self.def_map.prelude = Some(m); | 416 | self.def_map.prelude = Some(m); |
417 | } else if m.krate != self.def_map.krate { | 417 | } else if m.krate != self.def_map.krate { |
418 | tested_by!(glob_across_crates); | 418 | mark::hit!(glob_across_crates); |
419 | // glob import from other crate => we can just import everything once | 419 | // glob import from other crate => we can just import everything once |
420 | let item_map = self.db.crate_def_map(m.krate); | 420 | let item_map = self.db.crate_def_map(m.krate); |
421 | let scope = &item_map[m.local_id].scope; | 421 | let scope = &item_map[m.local_id].scope; |
@@ -461,7 +461,7 @@ impl DefCollector<'_> { | |||
461 | } | 461 | } |
462 | } | 462 | } |
463 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | 463 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { |
464 | tested_by!(glob_enum); | 464 | mark::hit!(glob_enum); |
465 | // glob import from enum => just import all the variants | 465 | // glob import from enum => just import all the variants |
466 | 466 | ||
467 | // XXX: urgh, so this works by accident! Here, we look at | 467 | // XXX: urgh, so this works by accident! Here, we look at |
@@ -510,7 +510,7 @@ impl DefCollector<'_> { | |||
510 | 510 | ||
511 | self.update(module_id, &[(name, def)], vis); | 511 | self.update(module_id, &[(name, def)], vis); |
512 | } | 512 | } |
513 | None => tested_by!(bogus_paths), | 513 | None => mark::hit!(bogus_paths), |
514 | } | 514 | } |
515 | } | 515 | } |
516 | } | 516 | } |
@@ -683,7 +683,7 @@ impl ModCollector<'_, '_> { | |||
683 | // Prelude module is always considered to be `#[macro_use]`. | 683 | // Prelude module is always considered to be `#[macro_use]`. |
684 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 684 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
685 | if prelude_module.krate != self.def_collector.def_map.krate { | 685 | if prelude_module.krate != self.def_collector.def_map.krate { |
686 | tested_by!(prelude_is_macro_use); | 686 | mark::hit!(prelude_is_macro_use); |
687 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); | 687 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); |
688 | } | 688 | } |
689 | } | 689 | } |
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs index 35a0a0c98..19692e70c 100644 --- a/crates/ra_hir_def/src/nameres/path_resolution.rs +++ b/crates/ra_hir_def/src/nameres/path_resolution.rs | |||
@@ -14,7 +14,7 @@ use std::iter::successors; | |||
14 | 14 | ||
15 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
16 | use ra_db::Edition; | 16 | use ra_db::Edition; |
17 | use test_utils::tested_by; | 17 | use test_utils::mark; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | db::DefDatabase, | 20 | db::DefDatabase, |
@@ -108,7 +108,7 @@ impl CrateDefMap { | |||
108 | let mut curr_per_ns: PerNs = match path.kind { | 108 | let mut curr_per_ns: PerNs = match path.kind { |
109 | PathKind::DollarCrate(krate) => { | 109 | PathKind::DollarCrate(krate) => { |
110 | if krate == self.krate { | 110 | if krate == self.krate { |
111 | tested_by!(macro_dollar_crate_self); | 111 | mark::hit!(macro_dollar_crate_self); |
112 | PerNs::types( | 112 | PerNs::types( |
113 | ModuleId { krate: self.krate, local_id: self.root }.into(), | 113 | ModuleId { krate: self.krate, local_id: self.root }.into(), |
114 | Visibility::Public, | 114 | Visibility::Public, |
@@ -116,7 +116,7 @@ impl CrateDefMap { | |||
116 | } else { | 116 | } else { |
117 | let def_map = db.crate_def_map(krate); | 117 | let def_map = db.crate_def_map(krate); |
118 | let module = ModuleId { krate, local_id: def_map.root }; | 118 | let module = ModuleId { krate, local_id: def_map.root }; |
119 | tested_by!(macro_dollar_crate_other); | 119 | mark::hit!(macro_dollar_crate_other); |
120 | PerNs::types(module.into(), Visibility::Public) | 120 | PerNs::types(module.into(), Visibility::Public) |
121 | } | 121 | } |
122 | } | 122 | } |
@@ -221,7 +221,7 @@ impl CrateDefMap { | |||
221 | } | 221 | } |
222 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | 222 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { |
223 | // enum variant | 223 | // enum variant |
224 | tested_by!(can_import_enum_variant); | 224 | mark::hit!(can_import_enum_variant); |
225 | let enum_data = db.enum_data(e); | 225 | let enum_data = db.enum_data(e); |
226 | match enum_data.variant(&segment) { | 226 | match enum_data.variant(&segment) { |
227 | Some(local_id) => { | 227 | Some(local_id) => { |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index f2716a295..4e628b14d 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -18,7 +18,7 @@ use ra_syntax::{ | |||
18 | ast::{self, AttrsOwner, NameOwner, VisibilityOwner}, | 18 | ast::{self, AttrsOwner, NameOwner, VisibilityOwner}, |
19 | AstNode, | 19 | AstNode, |
20 | }; | 20 | }; |
21 | use test_utils::tested_by; | 21 | use test_utils::mark; |
22 | 22 | ||
23 | use crate::{ | 23 | use crate::{ |
24 | attr::Attrs, | 24 | attr::Attrs, |
@@ -346,7 +346,7 @@ impl RawItemsCollector { | |||
346 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | 346 | self.push_item(current_module, attrs, RawItemKind::Module(item)); |
347 | return; | 347 | return; |
348 | } | 348 | } |
349 | tested_by!(name_res_works_for_broken_modules); | 349 | mark::hit!(name_res_works_for_broken_modules); |
350 | } | 350 | } |
351 | 351 | ||
352 | fn add_use_item(&mut self, current_module: Option<Idx<ModuleData>>, use_item: ast::UseItem) { | 352 | fn add_use_item(&mut self, current_module: Option<Idx<ModuleData>>, use_item: ast::UseItem) { |
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index 1b66c1aac..05cd0297d 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs | |||
@@ -8,7 +8,7 @@ use std::sync::Arc; | |||
8 | 8 | ||
9 | use insta::assert_snapshot; | 9 | use insta::assert_snapshot; |
10 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 10 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
11 | use test_utils::covers; | 11 | use test_utils::mark; |
12 | 12 | ||
13 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; | 13 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; |
14 | 14 | ||
@@ -132,7 +132,7 @@ fn crate_def_map_fn_mod_same_name() { | |||
132 | 132 | ||
133 | #[test] | 133 | #[test] |
134 | fn bogus_paths() { | 134 | fn bogus_paths() { |
135 | covers!(bogus_paths); | 135 | mark::check!(bogus_paths); |
136 | let map = def_map( | 136 | let map = def_map( |
137 | " | 137 | " |
138 | //- /lib.rs | 138 | //- /lib.rs |
@@ -247,7 +247,7 @@ fn re_exports() { | |||
247 | 247 | ||
248 | #[test] | 248 | #[test] |
249 | fn std_prelude() { | 249 | fn std_prelude() { |
250 | covers!(std_prelude); | 250 | mark::check!(std_prelude); |
251 | let map = def_map( | 251 | let map = def_map( |
252 | " | 252 | " |
253 | //- /main.rs crate:main deps:test_crate | 253 | //- /main.rs crate:main deps:test_crate |
@@ -271,7 +271,7 @@ fn std_prelude() { | |||
271 | 271 | ||
272 | #[test] | 272 | #[test] |
273 | fn can_import_enum_variant() { | 273 | fn can_import_enum_variant() { |
274 | covers!(can_import_enum_variant); | 274 | mark::check!(can_import_enum_variant); |
275 | let map = def_map( | 275 | let map = def_map( |
276 | " | 276 | " |
277 | //- /lib.rs | 277 | //- /lib.rs |
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs index ee8df3a26..2b12c0daa 100644 --- a/crates/ra_hir_def/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs | |||
@@ -152,7 +152,7 @@ fn glob_privacy_2() { | |||
152 | 152 | ||
153 | #[test] | 153 | #[test] |
154 | fn glob_across_crates() { | 154 | fn glob_across_crates() { |
155 | covers!(glob_across_crates); | 155 | mark::check!(glob_across_crates); |
156 | let map = def_map( | 156 | let map = def_map( |
157 | r" | 157 | r" |
158 | //- /main.rs crate:main deps:test_crate | 158 | //- /main.rs crate:main deps:test_crate |
@@ -171,7 +171,6 @@ fn glob_across_crates() { | |||
171 | 171 | ||
172 | #[test] | 172 | #[test] |
173 | fn glob_privacy_across_crates() { | 173 | fn glob_privacy_across_crates() { |
174 | covers!(glob_across_crates); | ||
175 | let map = def_map( | 174 | let map = def_map( |
176 | r" | 175 | r" |
177 | //- /main.rs crate:main deps:test_crate | 176 | //- /main.rs crate:main deps:test_crate |
@@ -191,7 +190,7 @@ fn glob_privacy_across_crates() { | |||
191 | 190 | ||
192 | #[test] | 191 | #[test] |
193 | fn glob_enum() { | 192 | fn glob_enum() { |
194 | covers!(glob_enum); | 193 | mark::check!(glob_enum); |
195 | let map = def_map( | 194 | let map = def_map( |
196 | " | 195 | " |
197 | //- /lib.rs | 196 | //- /lib.rs |
@@ -212,7 +211,7 @@ fn glob_enum() { | |||
212 | 211 | ||
213 | #[test] | 212 | #[test] |
214 | fn glob_enum_group() { | 213 | fn glob_enum_group() { |
215 | covers!(glob_enum_group); | 214 | mark::check!(glob_enum_group); |
216 | let map = def_map( | 215 | let map = def_map( |
217 | r" | 216 | r" |
218 | //- /lib.rs | 217 | //- /lib.rs |
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs index 40289e3ca..84480d9f6 100644 --- a/crates/ra_hir_def/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs | |||
@@ -212,7 +212,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
212 | 212 | ||
213 | #[test] | 213 | #[test] |
214 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { | 214 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { |
215 | covers!(macro_rules_from_other_crates_are_visible_with_macro_use); | 215 | mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); |
216 | let map = def_map( | 216 | let map = def_map( |
217 | " | 217 | " |
218 | //- /main.rs crate:main deps:foo | 218 | //- /main.rs crate:main deps:foo |
@@ -262,7 +262,7 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { | |||
262 | 262 | ||
263 | #[test] | 263 | #[test] |
264 | fn prelude_is_macro_use() { | 264 | fn prelude_is_macro_use() { |
265 | covers!(prelude_is_macro_use); | 265 | mark::check!(prelude_is_macro_use); |
266 | let map = def_map( | 266 | let map = def_map( |
267 | " | 267 | " |
268 | //- /main.rs crate:main deps:foo | 268 | //- /main.rs crate:main deps:foo |
@@ -544,8 +544,7 @@ fn path_qualified_macros() { | |||
544 | 544 | ||
545 | #[test] | 545 | #[test] |
546 | fn macro_dollar_crate_is_correct_in_item() { | 546 | fn macro_dollar_crate_is_correct_in_item() { |
547 | covers!(macro_dollar_crate_self); | 547 | mark::check!(macro_dollar_crate_self); |
548 | covers!(macro_dollar_crate_other); | ||
549 | let map = def_map( | 548 | let map = def_map( |
550 | " | 549 | " |
551 | //- /main.rs crate:main deps:foo | 550 | //- /main.rs crate:main deps:foo |
@@ -603,7 +602,7 @@ fn macro_dollar_crate_is_correct_in_item() { | |||
603 | 602 | ||
604 | #[test] | 603 | #[test] |
605 | fn macro_dollar_crate_is_correct_in_indirect_deps() { | 604 | fn macro_dollar_crate_is_correct_in_indirect_deps() { |
606 | covers!(macro_dollar_crate_other); | 605 | mark::check!(macro_dollar_crate_other); |
607 | // From std | 606 | // From std |
608 | let map = def_map( | 607 | let map = def_map( |
609 | r#" | 608 | r#" |
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index 37fcdfb8c..b43b294ca 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -2,7 +2,7 @@ use super::*; | |||
2 | 2 | ||
3 | #[test] | 3 | #[test] |
4 | fn name_res_works_for_broken_modules() { | 4 | fn name_res_works_for_broken_modules() { |
5 | covers!(name_res_works_for_broken_modules); | 5 | mark::check!(name_res_works_for_broken_modules); |
6 | let map = def_map( | 6 | let map = def_map( |
7 | r" | 7 | r" |
8 | //- /lib.rs | 8 | //- /lib.rs |
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs index 5b6854b0f..7cc655487 100644 --- a/crates/ra_hir_def/src/path/lower/lower_use.rs +++ b/crates/ra_hir_def/src/path/lower/lower_use.rs | |||
@@ -6,7 +6,7 @@ use std::iter; | |||
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_expand::{hygiene::Hygiene, name::AsName}; | 7 | use hir_expand::{hygiene::Hygiene, name::AsName}; |
8 | use ra_syntax::ast::{self, NameOwner}; | 8 | use ra_syntax::ast::{self, NameOwner}; |
9 | use test_utils::tested_by; | 9 | use test_utils::mark; |
10 | 10 | ||
11 | use crate::path::{ImportAlias, ModPath, PathKind}; | 11 | use crate::path::{ImportAlias, ModPath, PathKind}; |
12 | 12 | ||
@@ -54,7 +54,7 @@ pub(crate) fn lower_use_tree( | |||
54 | // FIXME: report errors somewhere | 54 | // FIXME: report errors somewhere |
55 | // We get here if we do | 55 | // We get here if we do |
56 | } else if is_glob { | 56 | } else if is_glob { |
57 | tested_by!(glob_enum_group); | 57 | mark::hit!(glob_enum_group); |
58 | if let Some(prefix) = prefix { | 58 | if let Some(prefix) = prefix { |
59 | cb(prefix, &tree, is_glob, None) | 59 | cb(prefix, &tree, is_glob, None) |
60 | } | 60 | } |
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 5fc0ec5e3..b2de7fa34 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml | |||
@@ -27,9 +27,9 @@ test_utils = { path = "../test_utils" } | |||
27 | 27 | ||
28 | scoped-tls = "1" | 28 | scoped-tls = "1" |
29 | 29 | ||
30 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" } | 30 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } |
31 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" } | 31 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } |
32 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" } | 32 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } |
33 | 33 | ||
34 | [dev-dependencies] | 34 | [dev-dependencies] |
35 | insta = "0.16.0" | 35 | insta = "0.16.0" |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index fdb49560b..0a8bb24ac 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
76 | #[salsa::interned] | 76 | #[salsa::interned] |
77 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; | 77 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; |
78 | #[salsa::interned] | 78 | #[salsa::interned] |
79 | fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId; | ||
80 | #[salsa::interned] | ||
79 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; | 81 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; |
80 | #[salsa::interned] | 82 | #[salsa::interned] |
81 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; | 83 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; |
@@ -89,11 +91,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
89 | fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; | 91 | fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; |
90 | 92 | ||
91 | #[salsa::invoke(chalk::struct_datum_query)] | 93 | #[salsa::invoke(chalk::struct_datum_query)] |
92 | fn struct_datum(&self, krate: CrateId, struct_id: chalk::StructId) -> Arc<chalk::StructDatum>; | 94 | fn struct_datum(&self, krate: CrateId, struct_id: chalk::AdtId) -> Arc<chalk::StructDatum>; |
93 | 95 | ||
94 | #[salsa::invoke(crate::traits::chalk::impl_datum_query)] | 96 | #[salsa::invoke(crate::traits::chalk::impl_datum_query)] |
95 | fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; | 97 | fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; |
96 | 98 | ||
99 | #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] | ||
100 | fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>; | ||
101 | |||
97 | #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] | 102 | #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] |
98 | fn associated_ty_value( | 103 | fn associated_ty_value( |
99 | &self, | 104 | &self, |
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 173ec59ed..2ee9adb16 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html | 5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html |
6 | 6 | ||
7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; | 7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; |
8 | use test_utils::tested_by; | 8 | use test_utils::mark; |
9 | 9 | ||
10 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; | 10 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; |
11 | 11 | ||
@@ -34,7 +34,7 @@ impl<'a> InferenceContext<'a> { | |||
34 | ty1.clone() | 34 | ty1.clone() |
35 | } else { | 35 | } else { |
36 | if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) { | 36 | if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) { |
37 | tested_by!(coerce_fn_reification); | 37 | mark::hit!(coerce_fn_reification); |
38 | // Special case: two function types. Try to coerce both to | 38 | // Special case: two function types. Try to coerce both to |
39 | // pointers to have a chance at getting a match. See | 39 | // pointers to have a chance at getting a match. See |
40 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | 40 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 |
@@ -44,7 +44,7 @@ impl<'a> InferenceContext<'a> { | |||
44 | let ptr_ty2 = Ty::fn_ptr(sig2); | 44 | let ptr_ty2 = Ty::fn_ptr(sig2); |
45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) | 45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) |
46 | } else { | 46 | } else { |
47 | tested_by!(coerce_merge_fail_fallback); | 47 | mark::hit!(coerce_merge_fail_fallback); |
48 | // For incompatible types, we use the latter one as result | 48 | // For incompatible types, we use the latter one as result |
49 | // to be better recovery for `if` without `else`. | 49 | // to be better recovery for `if` without `else`. |
50 | ty2.clone() | 50 | ty2.clone() |
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index 54ec870df..4006f595d 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs | |||
@@ -10,7 +10,7 @@ use hir_def::{ | |||
10 | FieldId, | 10 | FieldId, |
11 | }; | 11 | }; |
12 | use hir_expand::name::Name; | 12 | use hir_expand::name::Name; |
13 | use test_utils::tested_by; | 13 | use test_utils::mark; |
14 | 14 | ||
15 | use super::{BindingMode, Expectation, InferenceContext}; | 15 | use super::{BindingMode, Expectation, InferenceContext}; |
16 | use crate::{utils::variant_data, Substs, Ty, TypeCtor}; | 16 | use crate::{utils::variant_data, Substs, Ty, TypeCtor}; |
@@ -111,7 +111,7 @@ impl<'a> InferenceContext<'a> { | |||
111 | } | 111 | } |
112 | } | 112 | } |
113 | } else if let Pat::Ref { .. } = &body[pat] { | 113 | } else if let Pat::Ref { .. } = &body[pat] { |
114 | tested_by!(match_ergonomics_ref); | 114 | mark::hit!(match_ergonomics_ref); |
115 | // When you encounter a `&pat` pattern, reset to Move. | 115 | // When you encounter a `&pat` pattern, reset to Move. |
116 | // This is so that `w` is by value: `let (_, &w) = &(1, &2);` | 116 | // This is so that `w` is by value: `let (_, &w) = &(1, &2);` |
117 | default_bm = BindingMode::Move; | 117 | default_bm = BindingMode::Move; |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index ab0bc8b70..269495ca0 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -4,7 +4,7 @@ use std::borrow::Cow; | |||
4 | 4 | ||
5 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | 5 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; |
6 | 6 | ||
7 | use test_utils::tested_by; | 7 | use test_utils::mark; |
8 | 8 | ||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{ |
@@ -313,7 +313,7 @@ impl InferenceTable { | |||
313 | // more than once | 313 | // more than once |
314 | for i in 0..3 { | 314 | for i in 0..3 { |
315 | if i > 0 { | 315 | if i > 0 { |
316 | tested_by!(type_var_resolves_to_int_var); | 316 | mark::hit!(type_var_resolves_to_int_var); |
317 | } | 317 | } |
318 | match &*ty { | 318 | match &*ty { |
319 | Ty::Infer(tv) => { | 319 | Ty::Infer(tv) => { |
@@ -342,7 +342,7 @@ impl InferenceTable { | |||
342 | Ty::Infer(tv) => { | 342 | Ty::Infer(tv) => { |
343 | let inner = tv.to_inner(); | 343 | let inner = tv.to_inner(); |
344 | if tv_stack.contains(&inner) { | 344 | if tv_stack.contains(&inner) { |
345 | tested_by!(type_var_cycles_resolve_as_possible); | 345 | mark::hit!(type_var_cycles_resolve_as_possible); |
346 | // recursive type | 346 | // recursive type |
347 | return tv.fallback_value(); | 347 | return tv.fallback_value(); |
348 | } | 348 | } |
@@ -369,7 +369,7 @@ impl InferenceTable { | |||
369 | Ty::Infer(tv) => { | 369 | Ty::Infer(tv) => { |
370 | let inner = tv.to_inner(); | 370 | let inner = tv.to_inner(); |
371 | if tv_stack.contains(&inner) { | 371 | if tv_stack.contains(&inner) { |
372 | tested_by!(type_var_cycles_resolve_completely); | 372 | mark::hit!(type_var_cycles_resolve_completely); |
373 | // recursive type | 373 | // recursive type |
374 | return tv.fallback_value(); | 374 | return tv.fallback_value(); |
375 | } | 375 | } |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index daea02f88..93cb45a64 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -42,7 +42,6 @@ pub mod expr; | |||
42 | mod tests; | 42 | mod tests; |
43 | #[cfg(test)] | 43 | #[cfg(test)] |
44 | mod test_db; | 44 | mod test_db; |
45 | mod marks; | ||
46 | mod _match; | 45 | mod _match; |
47 | 46 | ||
48 | use std::ops::Deref; | 47 | use std::ops::Deref; |
@@ -156,10 +155,16 @@ pub enum TypeCtor { | |||
156 | /// This exists just for Chalk, because Chalk just has a single `StructId` where | 155 | /// This exists just for Chalk, because Chalk just has a single `StructId` where |
157 | /// we have different kinds of ADTs, primitive types and special type | 156 | /// we have different kinds of ADTs, primitive types and special type |
158 | /// constructors like tuples and function pointers. | 157 | /// constructors like tuples and function pointers. |
159 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 158 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] |
160 | pub struct TypeCtorId(salsa::InternId); | 159 | pub struct TypeCtorId(salsa::InternId); |
161 | impl_intern_key!(TypeCtorId); | 160 | impl_intern_key!(TypeCtorId); |
162 | 161 | ||
162 | /// This exists just for Chalk, because Chalk just has a single `FnDefId` where | ||
163 | /// we have different IDs for struct and enum variant constructors. | ||
164 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
165 | pub struct CallableDefId(salsa::InternId); | ||
166 | impl_intern_key!(CallableDefId); | ||
167 | |||
163 | impl TypeCtor { | 168 | impl TypeCtor { |
164 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { | 169 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { |
165 | match self { | 170 | match self { |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 9ad6dbe07..35ac86a46 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -812,7 +812,7 @@ impl TraitEnvironment { | |||
812 | // add `Self: Trait<T1, T2, ...>` to the environment in trait | 812 | // add `Self: Trait<T1, T2, ...>` to the environment in trait |
813 | // function default implementations (and hypothetical code | 813 | // function default implementations (and hypothetical code |
814 | // inside consts or type aliases) | 814 | // inside consts or type aliases) |
815 | test_utils::tested_by!(trait_self_implements_self); | 815 | test_utils::mark::hit!(trait_self_implements_self); |
816 | let substs = Substs::type_params(db, trait_id); | 816 | let substs = Substs::type_params(db, trait_id); |
817 | let trait_ref = TraitRef { trait_: trait_id, substs }; | 817 | let trait_ref = TraitRef { trait_: trait_id, substs }; |
818 | let pred = GenericPredicate::Implemented(trait_ref); | 818 | let pred = GenericPredicate::Implemented(trait_ref); |
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs deleted file mode 100644 index a39740143..000000000 --- a/crates/ra_hir_ty/src/marks.rs +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | //! See test_utils/src/marks.rs | ||
2 | |||
3 | test_utils::marks!( | ||
4 | type_var_cycles_resolve_completely | ||
5 | type_var_cycles_resolve_as_possible | ||
6 | type_var_resolves_to_int_var | ||
7 | impl_self_type_match_without_receiver | ||
8 | match_ergonomics_ref | ||
9 | coerce_merge_fail_fallback | ||
10 | coerce_fn_reification | ||
11 | trait_self_implements_self | ||
12 | ); | ||
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 0851e16a8..e19628fdf 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -469,7 +469,7 @@ fn iterate_inherent_methods<T>( | |||
469 | // already happens in `is_valid_candidate` above; if not, we | 469 | // already happens in `is_valid_candidate` above; if not, we |
470 | // check it here | 470 | // check it here |
471 | if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { | 471 | if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { |
472 | test_utils::tested_by!(impl_self_type_match_without_receiver); | 472 | test_utils::mark::hit!(impl_self_type_match_without_receiver); |
473 | continue; | 473 | continue; |
474 | } | 474 | } |
475 | if let Some(result) = callback(&self_ty.value, item) { | 475 | if let Some(result) = callback(&self_ty.value, item) { |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 6dc4b2cd1..2cc4f4bf9 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use super::infer_with_mismatches; | 1 | use super::infer_with_mismatches; |
2 | use insta::assert_snapshot; | 2 | use insta::assert_snapshot; |
3 | use test_utils::covers; | 3 | use test_utils::mark; |
4 | 4 | ||
5 | // Infer with some common definitions and impls. | 5 | // Infer with some common definitions and impls. |
6 | fn infer(source: &str) -> String { | 6 | fn infer(source: &str) -> String { |
@@ -339,7 +339,7 @@ fn test(i: i32) { | |||
339 | 339 | ||
340 | #[test] | 340 | #[test] |
341 | fn coerce_merge_one_by_one1() { | 341 | fn coerce_merge_one_by_one1() { |
342 | covers!(coerce_merge_fail_fallback); | 342 | mark::check!(coerce_merge_fail_fallback); |
343 | 343 | ||
344 | assert_snapshot!( | 344 | assert_snapshot!( |
345 | infer(r#" | 345 | infer(r#" |
@@ -547,7 +547,7 @@ fn test() { | |||
547 | 547 | ||
548 | #[test] | 548 | #[test] |
549 | fn coerce_fn_items_in_match_arms() { | 549 | fn coerce_fn_items_in_match_arms() { |
550 | covers!(coerce_fn_reification); | 550 | mark::check!(coerce_fn_reification); |
551 | assert_snapshot!( | 551 | assert_snapshot!( |
552 | infer_with_mismatches(r#" | 552 | infer_with_mismatches(r#" |
553 | fn foo1(x: u32) -> isize { 1 } | 553 | fn foo1(x: u32) -> isize { 1 } |
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 9c2c9e1d2..558a70022 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -984,7 +984,7 @@ fn test() { S2.into()<|>; } | |||
984 | 984 | ||
985 | #[test] | 985 | #[test] |
986 | fn method_resolution_overloaded_method() { | 986 | fn method_resolution_overloaded_method() { |
987 | test_utils::covers!(impl_self_type_match_without_receiver); | 987 | test_utils::mark::check!(impl_self_type_match_without_receiver); |
988 | let t = type_at( | 988 | let t = type_at( |
989 | r#" | 989 | r#" |
990 | //- main.rs | 990 | //- main.rs |
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index d83ff5e0e..0c5f972a2 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
2 | use test_utils::covers; | 2 | use test_utils::mark; |
3 | 3 | ||
4 | use super::{infer, infer_with_mismatches}; | 4 | use super::{infer, infer_with_mismatches}; |
5 | 5 | ||
@@ -197,7 +197,7 @@ fn test() { | |||
197 | 197 | ||
198 | #[test] | 198 | #[test] |
199 | fn infer_pattern_match_ergonomics_ref() { | 199 | fn infer_pattern_match_ergonomics_ref() { |
200 | covers!(match_ergonomics_ref); | 200 | mark::check!(match_ergonomics_ref); |
201 | assert_snapshot!( | 201 | assert_snapshot!( |
202 | infer(r#" | 202 | infer(r#" |
203 | fn test() { | 203 | fn test() { |
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index c2168222e..1f004bd63 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs | |||
@@ -1,9 +1,10 @@ | |||
1 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
2 | use test_utils::covers; | 2 | use ra_db::fixture::WithFixture; |
3 | use test_utils::mark; | ||
3 | 4 | ||
4 | use super::infer; | ||
5 | use crate::test_db::TestDB; | 5 | use crate::test_db::TestDB; |
6 | use ra_db::fixture::WithFixture; | 6 | |
7 | use super::infer; | ||
7 | 8 | ||
8 | #[test] | 9 | #[test] |
9 | fn bug_484() { | 10 | fn bug_484() { |
@@ -89,8 +90,8 @@ fn quux() { | |||
89 | 90 | ||
90 | #[test] | 91 | #[test] |
91 | fn recursive_vars() { | 92 | fn recursive_vars() { |
92 | covers!(type_var_cycles_resolve_completely); | 93 | mark::check!(type_var_cycles_resolve_completely); |
93 | covers!(type_var_cycles_resolve_as_possible); | 94 | mark::check!(type_var_cycles_resolve_as_possible); |
94 | assert_snapshot!( | 95 | assert_snapshot!( |
95 | infer(r#" | 96 | infer(r#" |
96 | fn test() { | 97 | fn test() { |
@@ -112,8 +113,6 @@ fn test() { | |||
112 | 113 | ||
113 | #[test] | 114 | #[test] |
114 | fn recursive_vars_2() { | 115 | fn recursive_vars_2() { |
115 | covers!(type_var_cycles_resolve_completely); | ||
116 | covers!(type_var_cycles_resolve_as_possible); | ||
117 | assert_snapshot!( | 116 | assert_snapshot!( |
118 | infer(r#" | 117 | infer(r#" |
119 | fn test() { | 118 | fn test() { |
@@ -170,7 +169,7 @@ fn write() { | |||
170 | 169 | ||
171 | #[test] | 170 | #[test] |
172 | fn infer_std_crash_2() { | 171 | fn infer_std_crash_2() { |
173 | covers!(type_var_resolves_to_int_var); | 172 | mark::check!(type_var_resolves_to_int_var); |
174 | // caused "equating two type variables, ...", taken from std | 173 | // caused "equating two type variables, ...", taken from std |
175 | assert_snapshot!( | 174 | assert_snapshot!( |
176 | infer(r#" | 175 | infer(r#" |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index c49aacf98..0419bc751 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
2 | |||
3 | use ra_db::fixture::WithFixture; | 2 | use ra_db::fixture::WithFixture; |
3 | use test_utils::mark; | ||
4 | 4 | ||
5 | use super::{infer, infer_with_mismatches, type_at, type_at_pos}; | ||
6 | use crate::test_db::TestDB; | 5 | use crate::test_db::TestDB; |
7 | 6 | ||
7 | use super::{infer, infer_with_mismatches, type_at, type_at_pos}; | ||
8 | |||
8 | #[test] | 9 | #[test] |
9 | fn infer_await() { | 10 | fn infer_await() { |
10 | let (db, pos) = TestDB::with_position( | 11 | let (db, pos) = TestDB::with_position( |
@@ -301,7 +302,7 @@ fn test() { | |||
301 | 302 | ||
302 | #[test] | 303 | #[test] |
303 | fn trait_default_method_self_bound_implements_trait() { | 304 | fn trait_default_method_self_bound_implements_trait() { |
304 | test_utils::covers!(trait_self_implements_self); | 305 | mark::check!(trait_self_implements_self); |
305 | assert_snapshot!( | 306 | assert_snapshot!( |
306 | infer(r#" | 307 | infer(r#" |
307 | trait Trait { | 308 | trait Trait { |
@@ -324,7 +325,6 @@ trait Trait { | |||
324 | 325 | ||
325 | #[test] | 326 | #[test] |
326 | fn trait_default_method_self_bound_implements_super_trait() { | 327 | fn trait_default_method_self_bound_implements_super_trait() { |
327 | test_utils::covers!(trait_self_implements_self); | ||
328 | assert_snapshot!( | 328 | assert_snapshot!( |
329 | infer(r#" | 329 | infer(r#" |
330 | trait SuperTrait { | 330 | trait SuperTrait { |
@@ -2602,3 +2602,155 @@ fn test(x: &dyn Foo) { | |||
2602 | "### | 2602 | "### |
2603 | ); | 2603 | ); |
2604 | } | 2604 | } |
2605 | |||
2606 | #[test] | ||
2607 | fn builtin_copy() { | ||
2608 | assert_snapshot!( | ||
2609 | infer_with_mismatches(r#" | ||
2610 | #[lang = "copy"] | ||
2611 | trait Copy {} | ||
2612 | |||
2613 | struct IsCopy; | ||
2614 | impl Copy for IsCopy {} | ||
2615 | struct NotCopy; | ||
2616 | |||
2617 | trait Test { fn test(&self) -> bool; } | ||
2618 | impl<T: Copy> Test for T {} | ||
2619 | |||
2620 | fn test() { | ||
2621 | IsCopy.test(); | ||
2622 | NotCopy.test(); | ||
2623 | (IsCopy, IsCopy).test(); | ||
2624 | (IsCopy, NotCopy).test(); | ||
2625 | } | ||
2626 | "#, true), | ||
2627 | @r###" | ||
2628 | 111..115 'self': &Self | ||
2629 | 167..268 '{ ...t(); }': () | ||
2630 | 173..179 'IsCopy': IsCopy | ||
2631 | 173..186 'IsCopy.test()': bool | ||
2632 | 192..199 'NotCopy': NotCopy | ||
2633 | 192..206 'NotCopy.test()': {unknown} | ||
2634 | 212..228 '(IsCop...sCopy)': (IsCopy, IsCopy) | ||
2635 | 212..235 '(IsCop...test()': bool | ||
2636 | 213..219 'IsCopy': IsCopy | ||
2637 | 221..227 'IsCopy': IsCopy | ||
2638 | 241..258 '(IsCop...tCopy)': (IsCopy, NotCopy) | ||
2639 | 241..265 '(IsCop...test()': {unknown} | ||
2640 | 242..248 'IsCopy': IsCopy | ||
2641 | 250..257 'NotCopy': NotCopy | ||
2642 | "### | ||
2643 | ); | ||
2644 | } | ||
2645 | |||
2646 | #[test] | ||
2647 | fn builtin_fn_def_copy() { | ||
2648 | assert_snapshot!( | ||
2649 | infer_with_mismatches(r#" | ||
2650 | #[lang = "copy"] | ||
2651 | trait Copy {} | ||
2652 | |||
2653 | fn foo() {} | ||
2654 | fn bar<T: Copy>(T) -> T {} | ||
2655 | struct Struct(usize); | ||
2656 | enum Enum { Variant(usize) } | ||
2657 | |||
2658 | trait Test { fn test(&self) -> bool; } | ||
2659 | impl<T: Copy> Test for T {} | ||
2660 | |||
2661 | fn test() { | ||
2662 | foo.test(); | ||
2663 | bar.test(); | ||
2664 | Struct.test(); | ||
2665 | Enum::Variant.test(); | ||
2666 | } | ||
2667 | "#, true), | ||
2668 | // wrong result, because the built-in Copy impl for fn defs doesn't exist in Chalk yet | ||
2669 | @r###" | ||
2670 | 42..44 '{}': () | ||
2671 | 61..62 'T': {unknown} | ||
2672 | 69..71 '{}': () | ||
2673 | 69..71: expected T, got () | ||
2674 | 146..150 'self': &Self | ||
2675 | 202..282 '{ ...t(); }': () | ||
2676 | 208..211 'foo': fn foo() | ||
2677 | 208..218 'foo.test()': {unknown} | ||
2678 | 224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown} | ||
2679 | 224..234 'bar.test()': {unknown} | ||
2680 | 240..246 'Struct': Struct(usize) -> Struct | ||
2681 | 240..253 'Struct.test()': {unknown} | ||
2682 | 259..272 'Enum::Variant': Variant(usize) -> Enum | ||
2683 | 259..279 'Enum::...test()': {unknown} | ||
2684 | "### | ||
2685 | ); | ||
2686 | } | ||
2687 | |||
2688 | #[test] | ||
2689 | fn builtin_fn_ptr_copy() { | ||
2690 | assert_snapshot!( | ||
2691 | infer_with_mismatches(r#" | ||
2692 | #[lang = "copy"] | ||
2693 | trait Copy {} | ||
2694 | |||
2695 | trait Test { fn test(&self) -> bool; } | ||
2696 | impl<T: Copy> Test for T {} | ||
2697 | |||
2698 | fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { | ||
2699 | f1.test(); | ||
2700 | f2.test(); | ||
2701 | f3.test(); | ||
2702 | } | ||
2703 | "#, true), | ||
2704 | @r###" | ||
2705 | 55..59 'self': &Self | ||
2706 | 109..111 'f1': fn() | ||
2707 | 119..121 'f2': fn(usize) -> u8 | ||
2708 | 140..142 'f3': fn(u8, u8) -> &u8 | ||
2709 | 163..211 '{ ...t(); }': () | ||
2710 | 169..171 'f1': fn() | ||
2711 | 169..178 'f1.test()': bool | ||
2712 | 184..186 'f2': fn(usize) -> u8 | ||
2713 | 184..193 'f2.test()': bool | ||
2714 | 199..201 'f3': fn(u8, u8) -> &u8 | ||
2715 | 199..208 'f3.test()': bool | ||
2716 | "### | ||
2717 | ); | ||
2718 | } | ||
2719 | |||
2720 | #[test] | ||
2721 | fn builtin_sized() { | ||
2722 | assert_snapshot!( | ||
2723 | infer_with_mismatches(r#" | ||
2724 | #[lang = "sized"] | ||
2725 | trait Sized {} | ||
2726 | |||
2727 | trait Test { fn test(&self) -> bool; } | ||
2728 | impl<T: Sized> Test for T {} | ||
2729 | |||
2730 | fn test() { | ||
2731 | 1u8.test(); | ||
2732 | (*"foo").test(); // not Sized | ||
2733 | (1u8, 1u8).test(); | ||
2734 | (1u8, *"foo").test(); // not Sized | ||
2735 | } | ||
2736 | "#, true), | ||
2737 | @r###" | ||
2738 | 57..61 'self': &Self | ||
2739 | 114..229 '{ ...ized }': () | ||
2740 | 120..123 '1u8': u8 | ||
2741 | 120..130 '1u8.test()': bool | ||
2742 | 136..151 '(*"foo").test()': {unknown} | ||
2743 | 137..143 '*"foo"': str | ||
2744 | 138..143 '"foo"': &str | ||
2745 | 170..180 '(1u8, 1u8)': (u8, u8) | ||
2746 | 170..187 '(1u8, ...test()': bool | ||
2747 | 171..174 '1u8': u8 | ||
2748 | 176..179 '1u8': u8 | ||
2749 | 193..206 '(1u8, *"foo")': (u8, str) | ||
2750 | 193..213 '(1u8, ...test()': {unknown} | ||
2751 | 194..197 '1u8': u8 | ||
2752 | 199..205 '*"foo"': str | ||
2753 | 200..205 '"foo"': &str | ||
2754 | "### | ||
2755 | ); | ||
2756 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 5870618a0..5b0f12a3c 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -1,301 +1,29 @@ | |||
1 | //! Conversion code from/to Chalk. | 1 | //! Conversion code from/to Chalk. |
2 | use std::{fmt, sync::Arc}; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use log::debug; | 4 | use log::debug; |
5 | 5 | ||
6 | use chalk_ir::{ | 6 | use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; |
7 | cast::Cast, fold::shift::Shift, interner::HasInterner, Goal, GoalData, Parameter, | ||
8 | PlaceholderIndex, TypeName, UniverseIndex, | ||
9 | }; | ||
10 | 7 | ||
11 | use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; | 8 | use hir_def::{ |
12 | use ra_db::{ | 9 | lang_item::{lang_attr, LangItemTarget}, |
13 | salsa::{InternId, InternKey}, | 10 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, |
14 | CrateId, | ||
15 | }; | 11 | }; |
12 | use ra_db::{salsa::InternKey, CrateId}; | ||
16 | 13 | ||
17 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; | 14 | use super::{builtin, AssocTyValue, ChalkContext, Impl}; |
18 | use crate::{ | 15 | use crate::{ |
19 | db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, | 16 | db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, |
20 | ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 17 | CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, |
21 | }; | 18 | }; |
19 | use chalk_rust_ir::WellKnownTrait; | ||
20 | use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders}; | ||
22 | 21 | ||
23 | pub(super) mod tls; | 22 | pub use self::interner::*; |
24 | |||
25 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] | ||
26 | pub struct Interner; | ||
27 | |||
28 | impl chalk_ir::interner::Interner for Interner { | ||
29 | type InternedType = Box<chalk_ir::TyData<Self>>; | ||
30 | type InternedLifetime = chalk_ir::LifetimeData<Self>; | ||
31 | type InternedParameter = chalk_ir::ParameterData<Self>; | ||
32 | type InternedGoal = Arc<GoalData<Self>>; | ||
33 | type InternedGoals = Vec<Goal<Self>>; | ||
34 | type InternedSubstitution = Vec<Parameter<Self>>; | ||
35 | type InternedProgramClause = chalk_ir::ProgramClauseData<Self>; | ||
36 | type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; | ||
37 | type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; | ||
38 | type InternedParameterKinds = Vec<chalk_ir::ParameterKind<()>>; | ||
39 | type InternedCanonicalVarKinds = Vec<chalk_ir::ParameterKind<UniverseIndex>>; | ||
40 | type Identifier = TypeAliasId; | ||
41 | type DefId = InternId; | ||
42 | |||
43 | fn debug_struct_id( | ||
44 | type_kind_id: StructId, | ||
45 | fmt: &mut fmt::Formatter<'_>, | ||
46 | ) -> Option<fmt::Result> { | ||
47 | tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) | ||
48 | } | ||
49 | |||
50 | fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
51 | tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) | ||
52 | } | ||
53 | |||
54 | fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
55 | tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) | ||
56 | } | ||
57 | |||
58 | fn debug_alias( | ||
59 | alias: &chalk_ir::AliasTy<Interner>, | ||
60 | fmt: &mut fmt::Formatter<'_>, | ||
61 | ) -> Option<fmt::Result> { | ||
62 | tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) | ||
63 | } | ||
64 | |||
65 | fn debug_projection_ty( | ||
66 | proj: &chalk_ir::ProjectionTy<Interner>, | ||
67 | fmt: &mut fmt::Formatter<'_>, | ||
68 | ) -> Option<fmt::Result> { | ||
69 | tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) | ||
70 | } | ||
71 | |||
72 | fn debug_opaque_ty( | ||
73 | opaque_ty: &chalk_ir::OpaqueTy<Interner>, | ||
74 | fmt: &mut fmt::Formatter<'_>, | ||
75 | ) -> Option<fmt::Result> { | ||
76 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) | ||
77 | } | ||
78 | |||
79 | fn debug_opaque_ty_id( | ||
80 | opaque_ty_id: chalk_ir::OpaqueTyId<Self>, | ||
81 | fmt: &mut fmt::Formatter<'_>, | ||
82 | ) -> Option<fmt::Result> { | ||
83 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) | ||
84 | } | ||
85 | |||
86 | fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
87 | tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) | ||
88 | } | ||
89 | |||
90 | fn debug_lifetime( | ||
91 | lifetime: &chalk_ir::Lifetime<Interner>, | ||
92 | fmt: &mut fmt::Formatter<'_>, | ||
93 | ) -> Option<fmt::Result> { | ||
94 | tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) | ||
95 | } | ||
96 | |||
97 | fn debug_parameter( | ||
98 | parameter: &Parameter<Interner>, | ||
99 | fmt: &mut fmt::Formatter<'_>, | ||
100 | ) -> Option<fmt::Result> { | ||
101 | tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt))) | ||
102 | } | ||
103 | |||
104 | fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
105 | tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) | ||
106 | } | ||
107 | |||
108 | fn debug_goals( | ||
109 | goals: &chalk_ir::Goals<Interner>, | ||
110 | fmt: &mut fmt::Formatter<'_>, | ||
111 | ) -> Option<fmt::Result> { | ||
112 | tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) | ||
113 | } | ||
114 | |||
115 | fn debug_program_clause_implication( | ||
116 | pci: &chalk_ir::ProgramClauseImplication<Interner>, | ||
117 | fmt: &mut fmt::Formatter<'_>, | ||
118 | ) -> Option<fmt::Result> { | ||
119 | tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) | ||
120 | } | ||
121 | |||
122 | fn debug_application_ty( | ||
123 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
124 | fmt: &mut fmt::Formatter<'_>, | ||
125 | ) -> Option<fmt::Result> { | ||
126 | tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt))) | ||
127 | } | ||
128 | |||
129 | fn debug_substitution( | ||
130 | substitution: &chalk_ir::Substitution<Interner>, | ||
131 | fmt: &mut fmt::Formatter<'_>, | ||
132 | ) -> Option<fmt::Result> { | ||
133 | tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) | ||
134 | } | ||
135 | |||
136 | fn debug_separator_trait_ref( | ||
137 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
138 | fmt: &mut fmt::Formatter<'_>, | ||
139 | ) -> Option<fmt::Result> { | ||
140 | tls::with_current_program(|prog| { | ||
141 | Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) | ||
142 | }) | ||
143 | } | ||
144 | |||
145 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { | ||
146 | Box::new(ty) | ||
147 | } | ||
148 | |||
149 | fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> { | ||
150 | ty | ||
151 | } | ||
152 | |||
153 | fn intern_lifetime( | ||
154 | &self, | ||
155 | lifetime: chalk_ir::LifetimeData<Self>, | ||
156 | ) -> chalk_ir::LifetimeData<Self> { | ||
157 | lifetime | ||
158 | } | ||
159 | |||
160 | fn lifetime_data<'a>( | ||
161 | &self, | ||
162 | lifetime: &'a chalk_ir::LifetimeData<Self>, | ||
163 | ) -> &'a chalk_ir::LifetimeData<Self> { | ||
164 | lifetime | ||
165 | } | ||
166 | |||
167 | fn intern_parameter( | ||
168 | &self, | ||
169 | parameter: chalk_ir::ParameterData<Self>, | ||
170 | ) -> chalk_ir::ParameterData<Self> { | ||
171 | parameter | ||
172 | } | ||
173 | |||
174 | fn parameter_data<'a>( | ||
175 | &self, | ||
176 | parameter: &'a chalk_ir::ParameterData<Self>, | ||
177 | ) -> &'a chalk_ir::ParameterData<Self> { | ||
178 | parameter | ||
179 | } | ||
180 | |||
181 | fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> { | ||
182 | Arc::new(goal) | ||
183 | } | ||
184 | |||
185 | fn intern_goals<E>( | ||
186 | &self, | ||
187 | data: impl IntoIterator<Item = Result<Goal<Self>, E>>, | ||
188 | ) -> Result<Self::InternedGoals, E> { | ||
189 | data.into_iter().collect() | ||
190 | } | ||
191 | |||
192 | fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> { | ||
193 | goal | ||
194 | } | ||
195 | |||
196 | fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] { | ||
197 | goals | ||
198 | } | ||
199 | |||
200 | fn intern_substitution<E>( | ||
201 | &self, | ||
202 | data: impl IntoIterator<Item = Result<Parameter<Self>, E>>, | ||
203 | ) -> Result<Vec<Parameter<Self>>, E> { | ||
204 | data.into_iter().collect() | ||
205 | } | ||
206 | |||
207 | fn substitution_data<'a>( | ||
208 | &self, | ||
209 | substitution: &'a Vec<Parameter<Self>>, | ||
210 | ) -> &'a [Parameter<Self>] { | ||
211 | substitution | ||
212 | } | ||
213 | |||
214 | fn intern_program_clause( | ||
215 | &self, | ||
216 | data: chalk_ir::ProgramClauseData<Self>, | ||
217 | ) -> chalk_ir::ProgramClauseData<Self> { | ||
218 | data | ||
219 | } | ||
220 | |||
221 | fn program_clause_data<'a>( | ||
222 | &self, | ||
223 | clause: &'a chalk_ir::ProgramClauseData<Self>, | ||
224 | ) -> &'a chalk_ir::ProgramClauseData<Self> { | ||
225 | clause | ||
226 | } | ||
227 | |||
228 | fn intern_program_clauses<E>( | ||
229 | &self, | ||
230 | data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, | ||
231 | ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> { | ||
232 | data.into_iter().collect() | ||
233 | } | ||
234 | |||
235 | fn program_clauses_data<'a>( | ||
236 | &self, | ||
237 | clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>, | ||
238 | ) -> &'a [chalk_ir::ProgramClause<Self>] { | ||
239 | &clauses | ||
240 | } | ||
241 | |||
242 | fn intern_quantified_where_clauses<E>( | ||
243 | &self, | ||
244 | data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, | ||
245 | ) -> Result<Self::InternedQuantifiedWhereClauses, E> { | ||
246 | data.into_iter().collect() | ||
247 | } | ||
248 | |||
249 | fn quantified_where_clauses_data<'a>( | ||
250 | &self, | ||
251 | clauses: &'a Self::InternedQuantifiedWhereClauses, | ||
252 | ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] { | ||
253 | clauses | ||
254 | } | ||
255 | |||
256 | fn intern_parameter_kinds<E>( | ||
257 | &self, | ||
258 | data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<()>, E>>, | ||
259 | ) -> Result<Self::InternedParameterKinds, E> { | ||
260 | data.into_iter().collect() | ||
261 | } | ||
262 | 23 | ||
263 | fn parameter_kinds_data<'a>( | 24 | pub(super) mod tls; |
264 | &self, | 25 | mod interner; |
265 | parameter_kinds: &'a Self::InternedParameterKinds, | 26 | mod mapping; |
266 | ) -> &'a [chalk_ir::ParameterKind<()>] { | ||
267 | ¶meter_kinds | ||
268 | } | ||
269 | |||
270 | fn intern_canonical_var_kinds<E>( | ||
271 | &self, | ||
272 | data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<UniverseIndex>, E>>, | ||
273 | ) -> Result<Self::InternedCanonicalVarKinds, E> { | ||
274 | data.into_iter().collect() | ||
275 | } | ||
276 | |||
277 | fn canonical_var_kinds_data<'a>( | ||
278 | &self, | ||
279 | canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, | ||
280 | ) -> &'a [chalk_ir::ParameterKind<UniverseIndex>] { | ||
281 | &canonical_var_kinds | ||
282 | } | ||
283 | } | ||
284 | |||
285 | impl chalk_ir::interner::HasInterner for Interner { | ||
286 | type Interner = Self; | ||
287 | } | ||
288 | |||
289 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | ||
290 | pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<Interner>; | ||
291 | pub type TraitId = chalk_ir::TraitId<Interner>; | ||
292 | pub type TraitDatum = chalk_rust_ir::TraitDatum<Interner>; | ||
293 | pub type StructId = chalk_ir::StructId<Interner>; | ||
294 | pub type StructDatum = chalk_rust_ir::StructDatum<Interner>; | ||
295 | pub type ImplId = chalk_ir::ImplId<Interner>; | ||
296 | pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>; | ||
297 | pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>; | ||
298 | pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>; | ||
299 | 27 | ||
300 | pub(super) trait ToChalk { | 28 | pub(super) trait ToChalk { |
301 | type Chalk; | 29 | type Chalk; |
@@ -310,508 +38,6 @@ where | |||
310 | T::from_chalk(db, chalk) | 38 | T::from_chalk(db, chalk) |
311 | } | 39 | } |
312 | 40 | ||
313 | impl ToChalk for Ty { | ||
314 | type Chalk = chalk_ir::Ty<Interner>; | ||
315 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | ||
316 | match self { | ||
317 | Ty::Apply(apply_ty) => { | ||
318 | let name = apply_ty.ctor.to_chalk(db); | ||
319 | let substitution = apply_ty.parameters.to_chalk(db); | ||
320 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
321 | } | ||
322 | Ty::Projection(proj_ty) => { | ||
323 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
324 | let substitution = proj_ty.parameters.to_chalk(db); | ||
325 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | ||
326 | associated_ty_id, | ||
327 | substitution, | ||
328 | }) | ||
329 | .cast(&Interner) | ||
330 | .intern(&Interner) | ||
331 | } | ||
332 | Ty::Placeholder(id) => { | ||
333 | let interned_id = db.intern_type_param_id(id); | ||
334 | PlaceholderIndex { | ||
335 | ui: UniverseIndex::ROOT, | ||
336 | idx: interned_id.as_intern_id().as_usize(), | ||
337 | } | ||
338 | .to_ty::<Interner>(&Interner) | ||
339 | } | ||
340 | Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), | ||
341 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | ||
342 | Ty::Dyn(predicates) => { | ||
343 | let where_clauses = chalk_ir::QuantifiedWhereClauses::from( | ||
344 | &Interner, | ||
345 | predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), | ||
346 | ); | ||
347 | let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; | ||
348 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) | ||
349 | } | ||
350 | Ty::Opaque(_) | Ty::Unknown => { | ||
351 | let substitution = chalk_ir::Substitution::empty(&Interner); | ||
352 | let name = TypeName::Error; | ||
353 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self { | ||
358 | match chalk.data(&Interner).clone() { | ||
359 | chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { | ||
360 | TypeName::Error => Ty::Unknown, | ||
361 | _ => { | ||
362 | let ctor = from_chalk(db, apply_ty.name); | ||
363 | let parameters = from_chalk(db, apply_ty.substitution); | ||
364 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
365 | } | ||
366 | }, | ||
367 | chalk_ir::TyData::Placeholder(idx) => { | ||
368 | assert_eq!(idx.ui, UniverseIndex::ROOT); | ||
369 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( | ||
370 | crate::salsa::InternId::from(idx.idx), | ||
371 | ); | ||
372 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) | ||
373 | } | ||
374 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { | ||
375 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
376 | let parameters = from_chalk(db, proj.substitution); | ||
377 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
378 | } | ||
379 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), | ||
380 | chalk_ir::TyData::Function(_) => unimplemented!(), | ||
381 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), | ||
382 | chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, | ||
383 | chalk_ir::TyData::Dyn(where_clauses) => { | ||
384 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | ||
385 | let predicates = where_clauses | ||
386 | .bounds | ||
387 | .skip_binders() | ||
388 | .iter(&Interner) | ||
389 | .map(|c| from_chalk(db, c.clone())) | ||
390 | .collect(); | ||
391 | Ty::Dyn(predicates) | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
397 | impl ToChalk for Substs { | ||
398 | type Chalk = chalk_ir::Substitution<Interner>; | ||
399 | |||
400 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> { | ||
401 | chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db))) | ||
402 | } | ||
403 | |||
404 | fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs { | ||
405 | let tys = parameters | ||
406 | .iter(&Interner) | ||
407 | .map(|p| match p.ty(&Interner) { | ||
408 | Some(ty) => from_chalk(db, ty.clone()), | ||
409 | None => unimplemented!(), | ||
410 | }) | ||
411 | .collect(); | ||
412 | Substs(tys) | ||
413 | } | ||
414 | } | ||
415 | |||
416 | impl ToChalk for TraitRef { | ||
417 | type Chalk = chalk_ir::TraitRef<Interner>; | ||
418 | |||
419 | fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { | ||
420 | let trait_id = self.trait_.to_chalk(db); | ||
421 | let substitution = self.substs.to_chalk(db); | ||
422 | chalk_ir::TraitRef { trait_id, substitution } | ||
423 | } | ||
424 | |||
425 | fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { | ||
426 | let trait_ = from_chalk(db, trait_ref.trait_id); | ||
427 | let substs = from_chalk(db, trait_ref.substitution); | ||
428 | TraitRef { trait_, substs } | ||
429 | } | ||
430 | } | ||
431 | |||
432 | impl ToChalk for hir_def::TraitId { | ||
433 | type Chalk = TraitId; | ||
434 | |||
435 | fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId { | ||
436 | chalk_ir::TraitId(self.as_intern_id()) | ||
437 | } | ||
438 | |||
439 | fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId { | ||
440 | InternKey::from_intern_id(trait_id.0) | ||
441 | } | ||
442 | } | ||
443 | |||
444 | impl ToChalk for TypeCtor { | ||
445 | type Chalk = TypeName<Interner>; | ||
446 | |||
447 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { | ||
448 | match self { | ||
449 | TypeCtor::AssociatedType(type_alias) => { | ||
450 | let type_id = type_alias.to_chalk(db); | ||
451 | TypeName::AssociatedType(type_id) | ||
452 | } | ||
453 | _ => { | ||
454 | // other TypeCtors get interned and turned into a chalk StructId | ||
455 | let struct_id = db.intern_type_ctor(self).into(); | ||
456 | TypeName::Struct(struct_id) | ||
457 | } | ||
458 | } | ||
459 | } | ||
460 | |||
461 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { | ||
462 | match type_name { | ||
463 | TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), | ||
464 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | ||
465 | TypeName::OpaqueType(_) => unreachable!(), | ||
466 | |||
467 | TypeName::Scalar(_) => unreachable!(), | ||
468 | TypeName::Tuple(_) => unreachable!(), | ||
469 | TypeName::Raw(_) => unreachable!(), | ||
470 | TypeName::Slice => unreachable!(), | ||
471 | TypeName::Ref(_) => unreachable!(), | ||
472 | TypeName::Str => unreachable!(), | ||
473 | |||
474 | TypeName::Error => { | ||
475 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | ||
476 | unreachable!() | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | |||
482 | impl ToChalk for Impl { | ||
483 | type Chalk = ImplId; | ||
484 | |||
485 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplId { | ||
486 | db.intern_chalk_impl(self).into() | ||
487 | } | ||
488 | |||
489 | fn from_chalk(db: &dyn HirDatabase, impl_id: ImplId) -> Impl { | ||
490 | db.lookup_intern_chalk_impl(impl_id.into()) | ||
491 | } | ||
492 | } | ||
493 | |||
494 | impl ToChalk for TypeAliasId { | ||
495 | type Chalk = AssocTypeId; | ||
496 | |||
497 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { | ||
498 | chalk_ir::AssocTypeId(self.as_intern_id()) | ||
499 | } | ||
500 | |||
501 | fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { | ||
502 | InternKey::from_intern_id(type_alias_id.0) | ||
503 | } | ||
504 | } | ||
505 | |||
506 | impl ToChalk for AssocTyValue { | ||
507 | type Chalk = AssociatedTyValueId; | ||
508 | |||
509 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValueId { | ||
510 | db.intern_assoc_ty_value(self).into() | ||
511 | } | ||
512 | |||
513 | fn from_chalk(db: &dyn HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue { | ||
514 | db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) | ||
515 | } | ||
516 | } | ||
517 | |||
518 | impl ToChalk for GenericPredicate { | ||
519 | type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; | ||
520 | |||
521 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { | ||
522 | match self { | ||
523 | GenericPredicate::Implemented(trait_ref) => { | ||
524 | let chalk_trait_ref = trait_ref.to_chalk(db); | ||
525 | let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); | ||
526 | make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) | ||
527 | } | ||
528 | GenericPredicate::Projection(projection_pred) => { | ||
529 | let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); | ||
530 | let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); | ||
531 | let alias = chalk_ir::AliasTy::Projection(projection); | ||
532 | make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0) | ||
533 | } | ||
534 | GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), | ||
535 | } | ||
536 | } | ||
537 | |||
538 | fn from_chalk( | ||
539 | db: &dyn HirDatabase, | ||
540 | where_clause: chalk_ir::QuantifiedWhereClause<Interner>, | ||
541 | ) -> GenericPredicate { | ||
542 | // we don't produce any where clauses with binders and can't currently deal with them | ||
543 | match where_clause | ||
544 | .skip_binders() | ||
545 | .shifted_out(&Interner) | ||
546 | .expect("unexpected bound vars in where clause") | ||
547 | { | ||
548 | chalk_ir::WhereClause::Implemented(tr) => { | ||
549 | GenericPredicate::Implemented(from_chalk(db, tr)) | ||
550 | } | ||
551 | chalk_ir::WhereClause::AliasEq(projection_eq) => { | ||
552 | let projection_ty = from_chalk( | ||
553 | db, | ||
554 | match projection_eq.alias { | ||
555 | chalk_ir::AliasTy::Projection(p) => p, | ||
556 | _ => unimplemented!(), | ||
557 | }, | ||
558 | ); | ||
559 | let ty = from_chalk(db, projection_eq.ty); | ||
560 | GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty }) | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | |||
566 | impl ToChalk for ProjectionTy { | ||
567 | type Chalk = chalk_ir::ProjectionTy<Interner>; | ||
568 | |||
569 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { | ||
570 | chalk_ir::ProjectionTy { | ||
571 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
572 | substitution: self.parameters.to_chalk(db), | ||
573 | } | ||
574 | } | ||
575 | |||
576 | fn from_chalk( | ||
577 | db: &dyn HirDatabase, | ||
578 | projection_ty: chalk_ir::ProjectionTy<Interner>, | ||
579 | ) -> ProjectionTy { | ||
580 | ProjectionTy { | ||
581 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
582 | parameters: from_chalk(db, projection_ty.substitution), | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | impl ToChalk for super::ProjectionPredicate { | ||
588 | type Chalk = chalk_ir::AliasEq<Interner>; | ||
589 | |||
590 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { | ||
591 | chalk_ir::AliasEq { | ||
592 | alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)), | ||
593 | ty: self.ty.to_chalk(db), | ||
594 | } | ||
595 | } | ||
596 | |||
597 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { | ||
598 | unimplemented!() | ||
599 | } | ||
600 | } | ||
601 | |||
602 | impl ToChalk for Obligation { | ||
603 | type Chalk = chalk_ir::DomainGoal<Interner>; | ||
604 | |||
605 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { | ||
606 | match self { | ||
607 | Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), | ||
608 | Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), | ||
609 | } | ||
610 | } | ||
611 | |||
612 | fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self { | ||
613 | unimplemented!() | ||
614 | } | ||
615 | } | ||
616 | |||
617 | impl<T> ToChalk for Canonical<T> | ||
618 | where | ||
619 | T: ToChalk, | ||
620 | T::Chalk: HasInterner<Interner = Interner>, | ||
621 | { | ||
622 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
623 | |||
624 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
625 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
626 | let value = self.value.to_chalk(db); | ||
627 | chalk_ir::Canonical { | ||
628 | value, | ||
629 | binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]), | ||
630 | } | ||
631 | } | ||
632 | |||
633 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
634 | Canonical { | ||
635 | num_vars: canonical.binders.len(&Interner), | ||
636 | value: from_chalk(db, canonical.value), | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | |||
641 | impl ToChalk for Arc<super::TraitEnvironment> { | ||
642 | type Chalk = chalk_ir::Environment<Interner>; | ||
643 | |||
644 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> { | ||
645 | let mut clauses = Vec::new(); | ||
646 | for pred in &self.predicates { | ||
647 | if pred.is_error() { | ||
648 | // for env, we just ignore errors | ||
649 | continue; | ||
650 | } | ||
651 | let program_clause: chalk_ir::ProgramClause<Interner> = | ||
652 | pred.clone().to_chalk(db).cast(&Interner); | ||
653 | clauses.push(program_clause.into_from_env_clause(&Interner)); | ||
654 | } | ||
655 | chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses) | ||
656 | } | ||
657 | |||
658 | fn from_chalk( | ||
659 | _db: &dyn HirDatabase, | ||
660 | _env: chalk_ir::Environment<Interner>, | ||
661 | ) -> Arc<super::TraitEnvironment> { | ||
662 | unimplemented!() | ||
663 | } | ||
664 | } | ||
665 | |||
666 | impl<T: ToChalk> ToChalk for super::InEnvironment<T> | ||
667 | where | ||
668 | T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>, | ||
669 | { | ||
670 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
671 | |||
672 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
673 | chalk_ir::InEnvironment { | ||
674 | environment: self.environment.to_chalk(db), | ||
675 | goal: self.value.to_chalk(db), | ||
676 | } | ||
677 | } | ||
678 | |||
679 | fn from_chalk( | ||
680 | db: &dyn HirDatabase, | ||
681 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
682 | ) -> super::InEnvironment<T> { | ||
683 | super::InEnvironment { | ||
684 | environment: from_chalk(db, in_env.environment), | ||
685 | value: from_chalk(db, in_env.goal), | ||
686 | } | ||
687 | } | ||
688 | } | ||
689 | |||
690 | impl ToChalk for builtin::BuiltinImplData { | ||
691 | type Chalk = ImplDatum; | ||
692 | |||
693 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum { | ||
694 | let impl_type = chalk_rust_ir::ImplType::External; | ||
695 | let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); | ||
696 | |||
697 | let impl_datum_bound = | ||
698 | chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; | ||
699 | let associated_ty_value_ids = | ||
700 | self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); | ||
701 | chalk_rust_ir::ImplDatum { | ||
702 | binders: make_binders(impl_datum_bound, self.num_vars), | ||
703 | impl_type, | ||
704 | polarity: chalk_rust_ir::Polarity::Positive, | ||
705 | associated_ty_value_ids, | ||
706 | } | ||
707 | } | ||
708 | |||
709 | fn from_chalk(_db: &dyn HirDatabase, _data: ImplDatum) -> Self { | ||
710 | unimplemented!() | ||
711 | } | ||
712 | } | ||
713 | |||
714 | impl ToChalk for builtin::BuiltinImplAssocTyValueData { | ||
715 | type Chalk = AssociatedTyValue; | ||
716 | |||
717 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { | ||
718 | let ty = self.value.to_chalk(db); | ||
719 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty }; | ||
720 | |||
721 | chalk_rust_ir::AssociatedTyValue { | ||
722 | associated_ty_id: self.assoc_ty_id.to_chalk(db), | ||
723 | impl_id: self.impl_.to_chalk(db), | ||
724 | value: make_binders(value_bound, self.num_vars), | ||
725 | } | ||
726 | } | ||
727 | |||
728 | fn from_chalk( | ||
729 | _db: &dyn HirDatabase, | ||
730 | _data: AssociatedTyValue, | ||
731 | ) -> builtin::BuiltinImplAssocTyValueData { | ||
732 | unimplemented!() | ||
733 | } | ||
734 | } | ||
735 | |||
736 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> | ||
737 | where | ||
738 | T: HasInterner<Interner = Interner>, | ||
739 | { | ||
740 | chalk_ir::Binders::new( | ||
741 | chalk_ir::ParameterKinds::from( | ||
742 | &Interner, | ||
743 | std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars), | ||
744 | ), | ||
745 | value, | ||
746 | ) | ||
747 | } | ||
748 | |||
749 | fn convert_where_clauses( | ||
750 | db: &dyn HirDatabase, | ||
751 | def: GenericDefId, | ||
752 | substs: &Substs, | ||
753 | ) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> { | ||
754 | let generic_predicates = db.generic_predicates(def); | ||
755 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
756 | for pred in generic_predicates.iter() { | ||
757 | if pred.value.is_error() { | ||
758 | // skip errored predicates completely | ||
759 | continue; | ||
760 | } | ||
761 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
762 | } | ||
763 | result | ||
764 | } | ||
765 | |||
766 | fn generic_predicate_to_inline_bound( | ||
767 | db: &dyn HirDatabase, | ||
768 | pred: &GenericPredicate, | ||
769 | self_ty: &Ty, | ||
770 | ) -> Option<chalk_rust_ir::InlineBound<Interner>> { | ||
771 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
772 | // We don't have a special type for this, but Chalk does. | ||
773 | match pred { | ||
774 | GenericPredicate::Implemented(trait_ref) => { | ||
775 | if &trait_ref.substs[0] != self_ty { | ||
776 | // we can only convert predicates back to type bounds if they | ||
777 | // have the expected self type | ||
778 | return None; | ||
779 | } | ||
780 | let args_no_self = trait_ref.substs[1..] | ||
781 | .iter() | ||
782 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
783 | .collect(); | ||
784 | let trait_bound = | ||
785 | chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | ||
786 | Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound)) | ||
787 | } | ||
788 | GenericPredicate::Projection(proj) => { | ||
789 | if &proj.projection_ty.parameters[0] != self_ty { | ||
790 | return None; | ||
791 | } | ||
792 | let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container { | ||
793 | AssocContainerId::TraitId(t) => t, | ||
794 | _ => panic!("associated type not in trait"), | ||
795 | }; | ||
796 | let args_no_self = proj.projection_ty.parameters[1..] | ||
797 | .iter() | ||
798 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
799 | .collect(); | ||
800 | let alias_eq_bound = chalk_rust_ir::AliasEqBound { | ||
801 | value: proj.ty.clone().to_chalk(db), | ||
802 | trait_bound: chalk_rust_ir::TraitBound { | ||
803 | trait_id: trait_.to_chalk(db), | ||
804 | args_no_self, | ||
805 | }, | ||
806 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | ||
807 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
808 | }; | ||
809 | Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | ||
810 | } | ||
811 | GenericPredicate::Error => None, | ||
812 | } | ||
813 | } | ||
814 | |||
815 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | 41 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { |
816 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { | 42 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { |
817 | self.db.associated_ty_data(id) | 43 | self.db.associated_ty_data(id) |
@@ -819,16 +45,24 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
819 | fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { | 45 | fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { |
820 | self.db.trait_datum(self.krate, trait_id) | 46 | self.db.trait_datum(self.krate, trait_id) |
821 | } | 47 | } |
822 | fn struct_datum(&self, struct_id: StructId) -> Arc<StructDatum> { | 48 | fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { |
823 | self.db.struct_datum(self.krate, struct_id) | 49 | self.db.struct_datum(self.krate, struct_id) |
824 | } | 50 | } |
825 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { | 51 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { |
826 | self.db.impl_datum(self.krate, impl_id) | 52 | self.db.impl_datum(self.krate, impl_id) |
827 | } | 53 | } |
54 | |||
55 | fn fn_def_datum( | ||
56 | &self, | ||
57 | fn_def_id: chalk_ir::FnDefId<Interner>, | ||
58 | ) -> Arc<chalk_rust_ir::FnDefDatum<Interner>> { | ||
59 | self.db.fn_def_datum(self.krate, fn_def_id) | ||
60 | } | ||
61 | |||
828 | fn impls_for_trait( | 62 | fn impls_for_trait( |
829 | &self, | 63 | &self, |
830 | trait_id: TraitId, | 64 | trait_id: TraitId, |
831 | parameters: &[Parameter<Interner>], | 65 | parameters: &[GenericArg<Interner>], |
832 | ) -> Vec<ImplId> { | 66 | ) -> Vec<ImplId> { |
833 | debug!("impls_for_trait {:?}", trait_id); | 67 | debug!("impls_for_trait {:?}", trait_id); |
834 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); | 68 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); |
@@ -859,7 +93,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
859 | debug!("impls_for_trait returned {} impls", result.len()); | 93 | debug!("impls_for_trait returned {} impls", result.len()); |
860 | result | 94 | result |
861 | } | 95 | } |
862 | fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: StructId) -> bool { | 96 | fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: AdtId) -> bool { |
863 | debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); | 97 | debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); |
864 | false // FIXME | 98 | false // FIXME |
865 | } | 99 | } |
@@ -878,10 +112,15 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
878 | } | 112 | } |
879 | fn well_known_trait_id( | 113 | fn well_known_trait_id( |
880 | &self, | 114 | &self, |
881 | _well_known_trait: chalk_rust_ir::WellKnownTrait, | 115 | well_known_trait: chalk_rust_ir::WellKnownTrait, |
882 | ) -> Option<chalk_ir::TraitId<Interner>> { | 116 | ) -> Option<chalk_ir::TraitId<Interner>> { |
883 | // FIXME tell Chalk about well-known traits (here and in trait_datum) | 117 | let lang_attr = lang_attr_from_well_known_trait(well_known_trait); |
884 | None | 118 | let lang_items = self.db.crate_lang_items(self.krate); |
119 | let trait_ = match lang_items.target(lang_attr) { | ||
120 | Some(LangItemTarget::TraitId(trait_)) => trait_, | ||
121 | _ => return None, | ||
122 | }; | ||
123 | Some(trait_.to_chalk(self.db)) | ||
885 | } | 124 | } |
886 | 125 | ||
887 | fn program_clauses_for_env( | 126 | fn program_clauses_for_env( |
@@ -983,7 +222,8 @@ pub(crate) fn trait_datum_query( | |||
983 | let associated_ty_ids = | 222 | let associated_ty_ids = |
984 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); | 223 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); |
985 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; | 224 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; |
986 | let well_known = None; // FIXME set this (depending on lang items) | 225 | let well_known = |
226 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); | ||
987 | let trait_datum = TraitDatum { | 227 | let trait_datum = TraitDatum { |
988 | id: trait_id, | 228 | id: trait_id, |
989 | binders: make_binders(trait_datum_bound, bound_vars.len()), | 229 | binders: make_binders(trait_datum_bound, bound_vars.len()), |
@@ -994,13 +234,32 @@ pub(crate) fn trait_datum_query( | |||
994 | Arc::new(trait_datum) | 234 | Arc::new(trait_datum) |
995 | } | 235 | } |
996 | 236 | ||
237 | fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> { | ||
238 | Some(match name { | ||
239 | "sized" => WellKnownTrait::SizedTrait, | ||
240 | "copy" => WellKnownTrait::CopyTrait, | ||
241 | "clone" => WellKnownTrait::CloneTrait, | ||
242 | "drop" => WellKnownTrait::DropTrait, | ||
243 | _ => return None, | ||
244 | }) | ||
245 | } | ||
246 | |||
247 | fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { | ||
248 | match attr { | ||
249 | WellKnownTrait::SizedTrait => "sized", | ||
250 | WellKnownTrait::CopyTrait => "copy", | ||
251 | WellKnownTrait::CloneTrait => "clone", | ||
252 | WellKnownTrait::DropTrait => "drop", | ||
253 | } | ||
254 | } | ||
255 | |||
997 | pub(crate) fn struct_datum_query( | 256 | pub(crate) fn struct_datum_query( |
998 | db: &dyn HirDatabase, | 257 | db: &dyn HirDatabase, |
999 | krate: CrateId, | 258 | krate: CrateId, |
1000 | struct_id: StructId, | 259 | struct_id: AdtId, |
1001 | ) -> Arc<StructDatum> { | 260 | ) -> Arc<StructDatum> { |
1002 | debug!("struct_datum {:?}", struct_id); | 261 | debug!("struct_datum {:?}", struct_id); |
1003 | let type_ctor: TypeCtor = from_chalk(db, TypeName::Struct(struct_id)); | 262 | let type_ctor: TypeCtor = from_chalk(db, TypeName::Adt(struct_id)); |
1004 | debug!("struct {:?} = {:?}", struct_id, type_ctor); | 263 | debug!("struct {:?} = {:?}", struct_id, type_ctor); |
1005 | let num_params = type_ctor.num_ty_params(db); | 264 | let num_params = type_ctor.num_ty_params(db); |
1006 | let upstream = type_ctor.krate(db) != Some(krate); | 265 | let upstream = type_ctor.krate(db) != Some(krate); |
@@ -1012,12 +271,12 @@ pub(crate) fn struct_datum_query( | |||
1012 | convert_where_clauses(db, generic_def, &bound_vars) | 271 | convert_where_clauses(db, generic_def, &bound_vars) |
1013 | }) | 272 | }) |
1014 | .unwrap_or_else(Vec::new); | 273 | .unwrap_or_else(Vec::new); |
1015 | let flags = chalk_rust_ir::StructFlags { | 274 | let flags = chalk_rust_ir::AdtFlags { |
1016 | upstream, | 275 | upstream, |
1017 | // FIXME set fundamental flag correctly | 276 | // FIXME set fundamental flag correctly |
1018 | fundamental: false, | 277 | fundamental: false, |
1019 | }; | 278 | }; |
1020 | let struct_datum_bound = chalk_rust_ir::StructDatumBound { | 279 | let struct_datum_bound = chalk_rust_ir::AdtDatumBound { |
1021 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits) | 280 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits) |
1022 | where_clauses, | 281 | where_clauses, |
1023 | }; | 282 | }; |
@@ -1145,15 +404,47 @@ fn type_alias_associated_ty_value( | |||
1145 | Arc::new(value) | 404 | Arc::new(value) |
1146 | } | 405 | } |
1147 | 406 | ||
1148 | impl From<StructId> for crate::TypeCtorId { | 407 | pub(crate) fn fn_def_datum_query( |
1149 | fn from(struct_id: StructId) -> Self { | 408 | db: &dyn HirDatabase, |
1150 | InternKey::from_intern_id(struct_id.0) | 409 | _krate: CrateId, |
410 | fn_def_id: FnDefId, | ||
411 | ) -> Arc<FnDefDatum> { | ||
412 | let callable_def: CallableDef = from_chalk(db, fn_def_id); | ||
413 | let generic_params = generics(db.upcast(), callable_def.into()); | ||
414 | let sig = db.callable_item_signature(callable_def); | ||
415 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
416 | let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); | ||
417 | let bound = chalk_rust_ir::FnDefDatumBound { | ||
418 | // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway | ||
419 | argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(), | ||
420 | return_type: sig.value.ret().clone().to_chalk(db), | ||
421 | where_clauses, | ||
422 | }; | ||
423 | let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) }; | ||
424 | Arc::new(datum) | ||
425 | } | ||
426 | |||
427 | impl From<AdtId> for crate::TypeCtorId { | ||
428 | fn from(struct_id: AdtId) -> Self { | ||
429 | struct_id.0 | ||
1151 | } | 430 | } |
1152 | } | 431 | } |
1153 | 432 | ||
1154 | impl From<crate::TypeCtorId> for StructId { | 433 | impl From<crate::TypeCtorId> for AdtId { |
1155 | fn from(type_ctor_id: crate::TypeCtorId) -> Self { | 434 | fn from(type_ctor_id: crate::TypeCtorId) -> Self { |
1156 | chalk_ir::StructId(type_ctor_id.as_intern_id()) | 435 | chalk_ir::AdtId(type_ctor_id) |
436 | } | ||
437 | } | ||
438 | |||
439 | impl From<FnDefId> for crate::CallableDefId { | ||
440 | fn from(fn_def_id: FnDefId) -> Self { | ||
441 | InternKey::from_intern_id(fn_def_id.0) | ||
442 | } | ||
443 | } | ||
444 | |||
445 | impl From<crate::CallableDefId> for FnDefId { | ||
446 | fn from(callable_def_id: crate::CallableDefId) -> Self { | ||
447 | chalk_ir::FnDefId(callable_def_id.as_intern_id()) | ||
1157 | } | 448 | } |
1158 | } | 449 | } |
1159 | 450 | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs new file mode 100644 index 000000000..2a27f8ed8 --- /dev/null +++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs | |||
@@ -0,0 +1,353 @@ | |||
1 | //! Implementation of the Chalk `Interner` trait, which allows customizing the | ||
2 | //! representation of the various objects Chalk deals with (types, goals etc.). | ||
3 | |||
4 | use super::tls; | ||
5 | use chalk_ir::{GenericArg, Goal, GoalData}; | ||
6 | use hir_def::TypeAliasId; | ||
7 | use ra_db::salsa::InternId; | ||
8 | use std::{fmt, sync::Arc}; | ||
9 | |||
10 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] | ||
11 | pub struct Interner; | ||
12 | |||
13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | ||
14 | pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<Interner>; | ||
15 | pub type TraitId = chalk_ir::TraitId<Interner>; | ||
16 | pub type TraitDatum = chalk_rust_ir::TraitDatum<Interner>; | ||
17 | pub type AdtId = chalk_ir::AdtId<Interner>; | ||
18 | pub type StructDatum = chalk_rust_ir::AdtDatum<Interner>; | ||
19 | pub type ImplId = chalk_ir::ImplId<Interner>; | ||
20 | pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>; | ||
21 | pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>; | ||
22 | pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>; | ||
23 | pub type FnDefId = chalk_ir::FnDefId<Interner>; | ||
24 | pub type FnDefDatum = chalk_rust_ir::FnDefDatum<Interner>; | ||
25 | |||
26 | impl chalk_ir::interner::Interner for Interner { | ||
27 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? | ||
28 | type InternedLifetime = chalk_ir::LifetimeData<Self>; | ||
29 | type InternedConst = Arc<chalk_ir::ConstData<Self>>; | ||
30 | type InternedConcreteConst = (); | ||
31 | type InternedGenericArg = chalk_ir::GenericArgData<Self>; | ||
32 | type InternedGoal = Arc<GoalData<Self>>; | ||
33 | type InternedGoals = Vec<Goal<Self>>; | ||
34 | type InternedSubstitution = Vec<GenericArg<Self>>; | ||
35 | type InternedProgramClause = chalk_ir::ProgramClauseData<Self>; | ||
36 | type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; | ||
37 | type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; | ||
38 | type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; | ||
39 | type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; | ||
40 | type DefId = InternId; | ||
41 | type InternedAdtId = crate::TypeCtorId; | ||
42 | type Identifier = TypeAliasId; | ||
43 | |||
44 | fn debug_adt_id(type_kind_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
45 | tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) | ||
46 | } | ||
47 | |||
48 | fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
49 | tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) | ||
50 | } | ||
51 | |||
52 | fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
53 | tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) | ||
54 | } | ||
55 | |||
56 | fn debug_alias( | ||
57 | alias: &chalk_ir::AliasTy<Interner>, | ||
58 | fmt: &mut fmt::Formatter<'_>, | ||
59 | ) -> Option<fmt::Result> { | ||
60 | tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) | ||
61 | } | ||
62 | |||
63 | fn debug_projection_ty( | ||
64 | proj: &chalk_ir::ProjectionTy<Interner>, | ||
65 | fmt: &mut fmt::Formatter<'_>, | ||
66 | ) -> Option<fmt::Result> { | ||
67 | tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) | ||
68 | } | ||
69 | |||
70 | fn debug_opaque_ty( | ||
71 | opaque_ty: &chalk_ir::OpaqueTy<Interner>, | ||
72 | fmt: &mut fmt::Formatter<'_>, | ||
73 | ) -> Option<fmt::Result> { | ||
74 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) | ||
75 | } | ||
76 | |||
77 | fn debug_opaque_ty_id( | ||
78 | opaque_ty_id: chalk_ir::OpaqueTyId<Self>, | ||
79 | fmt: &mut fmt::Formatter<'_>, | ||
80 | ) -> Option<fmt::Result> { | ||
81 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) | ||
82 | } | ||
83 | |||
84 | fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
85 | tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) | ||
86 | } | ||
87 | |||
88 | fn debug_lifetime( | ||
89 | lifetime: &chalk_ir::Lifetime<Interner>, | ||
90 | fmt: &mut fmt::Formatter<'_>, | ||
91 | ) -> Option<fmt::Result> { | ||
92 | tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) | ||
93 | } | ||
94 | |||
95 | fn debug_generic_arg( | ||
96 | parameter: &GenericArg<Interner>, | ||
97 | fmt: &mut fmt::Formatter<'_>, | ||
98 | ) -> Option<fmt::Result> { | ||
99 | tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) | ||
100 | } | ||
101 | |||
102 | fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
103 | tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) | ||
104 | } | ||
105 | |||
106 | fn debug_goals( | ||
107 | goals: &chalk_ir::Goals<Interner>, | ||
108 | fmt: &mut fmt::Formatter<'_>, | ||
109 | ) -> Option<fmt::Result> { | ||
110 | tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) | ||
111 | } | ||
112 | |||
113 | fn debug_program_clause_implication( | ||
114 | pci: &chalk_ir::ProgramClauseImplication<Interner>, | ||
115 | fmt: &mut fmt::Formatter<'_>, | ||
116 | ) -> Option<fmt::Result> { | ||
117 | tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) | ||
118 | } | ||
119 | |||
120 | fn debug_application_ty( | ||
121 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
122 | fmt: &mut fmt::Formatter<'_>, | ||
123 | ) -> Option<fmt::Result> { | ||
124 | tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt))) | ||
125 | } | ||
126 | |||
127 | fn debug_substitution( | ||
128 | substitution: &chalk_ir::Substitution<Interner>, | ||
129 | fmt: &mut fmt::Formatter<'_>, | ||
130 | ) -> Option<fmt::Result> { | ||
131 | tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) | ||
132 | } | ||
133 | |||
134 | fn debug_separator_trait_ref( | ||
135 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
136 | fmt: &mut fmt::Formatter<'_>, | ||
137 | ) -> Option<fmt::Result> { | ||
138 | tls::with_current_program(|prog| { | ||
139 | Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) | ||
140 | }) | ||
141 | } | ||
142 | |||
143 | fn debug_fn_def_id( | ||
144 | fn_def_id: chalk_ir::FnDefId<Self>, | ||
145 | fmt: &mut fmt::Formatter<'_>, | ||
146 | ) -> Option<fmt::Result> { | ||
147 | tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) | ||
148 | } | ||
149 | fn debug_const( | ||
150 | constant: &chalk_ir::Const<Self>, | ||
151 | fmt: &mut fmt::Formatter<'_>, | ||
152 | ) -> Option<fmt::Result> { | ||
153 | tls::with_current_program(|prog| Some(prog?.debug_const(constant, fmt))) | ||
154 | } | ||
155 | fn debug_variable_kinds( | ||
156 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
157 | fmt: &mut fmt::Formatter<'_>, | ||
158 | ) -> Option<fmt::Result> { | ||
159 | tls::with_current_program(|prog| Some(prog?.debug_variable_kinds(variable_kinds, fmt))) | ||
160 | } | ||
161 | fn debug_variable_kinds_with_angles( | ||
162 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
163 | fmt: &mut fmt::Formatter<'_>, | ||
164 | ) -> Option<fmt::Result> { | ||
165 | tls::with_current_program(|prog| { | ||
166 | Some(prog?.debug_variable_kinds_with_angles(variable_kinds, fmt)) | ||
167 | }) | ||
168 | } | ||
169 | fn debug_canonical_var_kinds( | ||
170 | canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Self>, | ||
171 | fmt: &mut fmt::Formatter<'_>, | ||
172 | ) -> Option<fmt::Result> { | ||
173 | tls::with_current_program(|prog| { | ||
174 | Some(prog?.debug_canonical_var_kinds(canonical_var_kinds, fmt)) | ||
175 | }) | ||
176 | } | ||
177 | fn debug_program_clause( | ||
178 | clause: &chalk_ir::ProgramClause<Self>, | ||
179 | fmt: &mut fmt::Formatter<'_>, | ||
180 | ) -> Option<fmt::Result> { | ||
181 | tls::with_current_program(|prog| Some(prog?.debug_program_clause(clause, fmt))) | ||
182 | } | ||
183 | fn debug_program_clauses( | ||
184 | clauses: &chalk_ir::ProgramClauses<Self>, | ||
185 | fmt: &mut fmt::Formatter<'_>, | ||
186 | ) -> Option<fmt::Result> { | ||
187 | tls::with_current_program(|prog| Some(prog?.debug_program_clauses(clauses, fmt))) | ||
188 | } | ||
189 | fn debug_quantified_where_clauses( | ||
190 | clauses: &chalk_ir::QuantifiedWhereClauses<Self>, | ||
191 | fmt: &mut fmt::Formatter<'_>, | ||
192 | ) -> Option<fmt::Result> { | ||
193 | tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt))) | ||
194 | } | ||
195 | |||
196 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { | ||
197 | Box::new(ty) | ||
198 | } | ||
199 | |||
200 | fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> { | ||
201 | ty | ||
202 | } | ||
203 | |||
204 | fn intern_lifetime( | ||
205 | &self, | ||
206 | lifetime: chalk_ir::LifetimeData<Self>, | ||
207 | ) -> chalk_ir::LifetimeData<Self> { | ||
208 | lifetime | ||
209 | } | ||
210 | |||
211 | fn lifetime_data<'a>( | ||
212 | &self, | ||
213 | lifetime: &'a chalk_ir::LifetimeData<Self>, | ||
214 | ) -> &'a chalk_ir::LifetimeData<Self> { | ||
215 | lifetime | ||
216 | } | ||
217 | |||
218 | fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Arc<chalk_ir::ConstData<Self>> { | ||
219 | Arc::new(constant) | ||
220 | } | ||
221 | |||
222 | fn const_data<'a>( | ||
223 | &self, | ||
224 | constant: &'a Arc<chalk_ir::ConstData<Self>>, | ||
225 | ) -> &'a chalk_ir::ConstData<Self> { | ||
226 | constant | ||
227 | } | ||
228 | |||
229 | fn const_eq(&self, _ty: &Box<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool { | ||
230 | true | ||
231 | } | ||
232 | |||
233 | fn intern_generic_arg( | ||
234 | &self, | ||
235 | parameter: chalk_ir::GenericArgData<Self>, | ||
236 | ) -> chalk_ir::GenericArgData<Self> { | ||
237 | parameter | ||
238 | } | ||
239 | |||
240 | fn generic_arg_data<'a>( | ||
241 | &self, | ||
242 | parameter: &'a chalk_ir::GenericArgData<Self>, | ||
243 | ) -> &'a chalk_ir::GenericArgData<Self> { | ||
244 | parameter | ||
245 | } | ||
246 | |||
247 | fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> { | ||
248 | Arc::new(goal) | ||
249 | } | ||
250 | |||
251 | fn intern_goals<E>( | ||
252 | &self, | ||
253 | data: impl IntoIterator<Item = Result<Goal<Self>, E>>, | ||
254 | ) -> Result<Self::InternedGoals, E> { | ||
255 | data.into_iter().collect() | ||
256 | } | ||
257 | |||
258 | fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> { | ||
259 | goal | ||
260 | } | ||
261 | |||
262 | fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] { | ||
263 | goals | ||
264 | } | ||
265 | |||
266 | fn intern_substitution<E>( | ||
267 | &self, | ||
268 | data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, | ||
269 | ) -> Result<Vec<GenericArg<Self>>, E> { | ||
270 | data.into_iter().collect() | ||
271 | } | ||
272 | |||
273 | fn substitution_data<'a>( | ||
274 | &self, | ||
275 | substitution: &'a Vec<GenericArg<Self>>, | ||
276 | ) -> &'a [GenericArg<Self>] { | ||
277 | substitution | ||
278 | } | ||
279 | |||
280 | fn intern_program_clause( | ||
281 | &self, | ||
282 | data: chalk_ir::ProgramClauseData<Self>, | ||
283 | ) -> chalk_ir::ProgramClauseData<Self> { | ||
284 | data | ||
285 | } | ||
286 | |||
287 | fn program_clause_data<'a>( | ||
288 | &self, | ||
289 | clause: &'a chalk_ir::ProgramClauseData<Self>, | ||
290 | ) -> &'a chalk_ir::ProgramClauseData<Self> { | ||
291 | clause | ||
292 | } | ||
293 | |||
294 | fn intern_program_clauses<E>( | ||
295 | &self, | ||
296 | data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, | ||
297 | ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> { | ||
298 | data.into_iter().collect() | ||
299 | } | ||
300 | |||
301 | fn program_clauses_data<'a>( | ||
302 | &self, | ||
303 | clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>, | ||
304 | ) -> &'a [chalk_ir::ProgramClause<Self>] { | ||
305 | &clauses | ||
306 | } | ||
307 | |||
308 | fn intern_quantified_where_clauses<E>( | ||
309 | &self, | ||
310 | data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, | ||
311 | ) -> Result<Self::InternedQuantifiedWhereClauses, E> { | ||
312 | data.into_iter().collect() | ||
313 | } | ||
314 | |||
315 | fn quantified_where_clauses_data<'a>( | ||
316 | &self, | ||
317 | clauses: &'a Self::InternedQuantifiedWhereClauses, | ||
318 | ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] { | ||
319 | clauses | ||
320 | } | ||
321 | |||
322 | fn intern_generic_arg_kinds<E>( | ||
323 | &self, | ||
324 | data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, | ||
325 | ) -> Result<Self::InternedVariableKinds, E> { | ||
326 | data.into_iter().collect() | ||
327 | } | ||
328 | |||
329 | fn variable_kinds_data<'a>( | ||
330 | &self, | ||
331 | parameter_kinds: &'a Self::InternedVariableKinds, | ||
332 | ) -> &'a [chalk_ir::VariableKind<Self>] { | ||
333 | ¶meter_kinds | ||
334 | } | ||
335 | |||
336 | fn intern_canonical_var_kinds<E>( | ||
337 | &self, | ||
338 | data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, | ||
339 | ) -> Result<Self::InternedCanonicalVarKinds, E> { | ||
340 | data.into_iter().collect() | ||
341 | } | ||
342 | |||
343 | fn canonical_var_kinds_data<'a>( | ||
344 | &self, | ||
345 | canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, | ||
346 | ) -> &'a [chalk_ir::CanonicalVarKind<Self>] { | ||
347 | &canonical_var_kinds | ||
348 | } | ||
349 | } | ||
350 | |||
351 | impl chalk_ir::interner::HasInterner for Interner { | ||
352 | type Interner = Self; | ||
353 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs new file mode 100644 index 000000000..7082cb095 --- /dev/null +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs | |||
@@ -0,0 +1,701 @@ | |||
1 | //! This module contains the implementations of the `ToChalk` trait, which | ||
2 | //! handles conversion between our data types and their corresponding types in | ||
3 | //! Chalk (in both directions); plus some helper functions for more specialized | ||
4 | //! conversions. | ||
5 | |||
6 | use chalk_ir::{ | ||
7 | cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, | ||
8 | UniverseIndex, | ||
9 | }; | ||
10 | |||
11 | use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId}; | ||
12 | use ra_db::salsa::InternKey; | ||
13 | |||
14 | use crate::{ | ||
15 | db::HirDatabase, | ||
16 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, | ||
17 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, | ||
18 | ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, | ||
19 | Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, | ||
20 | }; | ||
21 | |||
22 | use super::interner::*; | ||
23 | use super::*; | ||
24 | |||
25 | impl ToChalk for Ty { | ||
26 | type Chalk = chalk_ir::Ty<Interner>; | ||
27 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | ||
28 | match self { | ||
29 | Ty::Apply(apply_ty) => match apply_ty.ctor { | ||
30 | TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), | ||
31 | TypeCtor::FnPtr { num_args: _ } => { | ||
32 | let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); | ||
33 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution }) | ||
34 | .intern(&Interner) | ||
35 | } | ||
36 | _ => { | ||
37 | let name = apply_ty.ctor.to_chalk(db); | ||
38 | let substitution = apply_ty.parameters.to_chalk(db); | ||
39 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
40 | } | ||
41 | }, | ||
42 | Ty::Projection(proj_ty) => { | ||
43 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
44 | let substitution = proj_ty.parameters.to_chalk(db); | ||
45 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | ||
46 | associated_ty_id, | ||
47 | substitution, | ||
48 | }) | ||
49 | .cast(&Interner) | ||
50 | .intern(&Interner) | ||
51 | } | ||
52 | Ty::Placeholder(id) => { | ||
53 | let interned_id = db.intern_type_param_id(id); | ||
54 | PlaceholderIndex { | ||
55 | ui: UniverseIndex::ROOT, | ||
56 | idx: interned_id.as_intern_id().as_usize(), | ||
57 | } | ||
58 | .to_ty::<Interner>(&Interner) | ||
59 | } | ||
60 | Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), | ||
61 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | ||
62 | Ty::Dyn(predicates) => { | ||
63 | let where_clauses = chalk_ir::QuantifiedWhereClauses::from( | ||
64 | &Interner, | ||
65 | predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), | ||
66 | ); | ||
67 | let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; | ||
68 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) | ||
69 | } | ||
70 | Ty::Opaque(_) | Ty::Unknown => { | ||
71 | let substitution = chalk_ir::Substitution::empty(&Interner); | ||
72 | let name = TypeName::Error; | ||
73 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self { | ||
78 | match chalk.data(&Interner).clone() { | ||
79 | chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { | ||
80 | TypeName::Error => Ty::Unknown, | ||
81 | TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution), | ||
82 | _ => { | ||
83 | let ctor = from_chalk(db, apply_ty.name); | ||
84 | let parameters = from_chalk(db, apply_ty.substitution); | ||
85 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
86 | } | ||
87 | }, | ||
88 | chalk_ir::TyData::Placeholder(idx) => { | ||
89 | assert_eq!(idx.ui, UniverseIndex::ROOT); | ||
90 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( | ||
91 | crate::salsa::InternId::from(idx.idx), | ||
92 | ); | ||
93 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) | ||
94 | } | ||
95 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { | ||
96 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
97 | let parameters = from_chalk(db, proj.substitution); | ||
98 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
99 | } | ||
100 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), | ||
101 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { | ||
102 | let parameters: Substs = from_chalk(db, substitution); | ||
103 | Ty::Apply(ApplicationTy { | ||
104 | ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 }, | ||
105 | parameters, | ||
106 | }) | ||
107 | } | ||
108 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), | ||
109 | chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, | ||
110 | chalk_ir::TyData::Dyn(where_clauses) => { | ||
111 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | ||
112 | let predicates = where_clauses | ||
113 | .bounds | ||
114 | .skip_binders() | ||
115 | .iter(&Interner) | ||
116 | .map(|c| from_chalk(db, c.clone())) | ||
117 | .collect(); | ||
118 | Ty::Dyn(predicates) | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | const LIFETIME_PLACEHOLDER: PlaceholderIndex = | ||
125 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX }; | ||
126 | |||
127 | /// We currently don't model lifetimes, but Chalk does. So, we have to insert a | ||
128 | /// fake lifetime here, because Chalks built-in logic may expect it to be there. | ||
129 | fn ref_to_chalk( | ||
130 | db: &dyn HirDatabase, | ||
131 | mutability: Mutability, | ||
132 | subst: Substs, | ||
133 | ) -> chalk_ir::Ty<Interner> { | ||
134 | let arg = subst[0].clone().to_chalk(db); | ||
135 | let lifetime = LIFETIME_PLACEHOLDER.to_lifetime(&Interner); | ||
136 | chalk_ir::ApplicationTy { | ||
137 | name: TypeName::Ref(mutability.to_chalk(db)), | ||
138 | substitution: chalk_ir::Substitution::from( | ||
139 | &Interner, | ||
140 | vec![lifetime.cast(&Interner), arg.cast(&Interner)], | ||
141 | ), | ||
142 | } | ||
143 | .intern(&Interner) | ||
144 | } | ||
145 | |||
146 | /// Here we remove the lifetime from the type we got from Chalk. | ||
147 | fn ref_from_chalk( | ||
148 | db: &dyn HirDatabase, | ||
149 | mutability: chalk_ir::Mutability, | ||
150 | subst: chalk_ir::Substitution<Interner>, | ||
151 | ) -> Ty { | ||
152 | let tys = subst | ||
153 | .iter(&Interner) | ||
154 | .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone()))) | ||
155 | .collect(); | ||
156 | Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys)) | ||
157 | } | ||
158 | |||
159 | impl ToChalk for Substs { | ||
160 | type Chalk = chalk_ir::Substitution<Interner>; | ||
161 | |||
162 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> { | ||
163 | chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db))) | ||
164 | } | ||
165 | |||
166 | fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs { | ||
167 | let tys = parameters | ||
168 | .iter(&Interner) | ||
169 | .map(|p| match p.ty(&Interner) { | ||
170 | Some(ty) => from_chalk(db, ty.clone()), | ||
171 | None => unimplemented!(), | ||
172 | }) | ||
173 | .collect(); | ||
174 | Substs(tys) | ||
175 | } | ||
176 | } | ||
177 | |||
178 | impl ToChalk for TraitRef { | ||
179 | type Chalk = chalk_ir::TraitRef<Interner>; | ||
180 | |||
181 | fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { | ||
182 | let trait_id = self.trait_.to_chalk(db); | ||
183 | let substitution = self.substs.to_chalk(db); | ||
184 | chalk_ir::TraitRef { trait_id, substitution } | ||
185 | } | ||
186 | |||
187 | fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { | ||
188 | let trait_ = from_chalk(db, trait_ref.trait_id); | ||
189 | let substs = from_chalk(db, trait_ref.substitution); | ||
190 | TraitRef { trait_, substs } | ||
191 | } | ||
192 | } | ||
193 | |||
194 | impl ToChalk for hir_def::TraitId { | ||
195 | type Chalk = TraitId; | ||
196 | |||
197 | fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId { | ||
198 | chalk_ir::TraitId(self.as_intern_id()) | ||
199 | } | ||
200 | |||
201 | fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId { | ||
202 | InternKey::from_intern_id(trait_id.0) | ||
203 | } | ||
204 | } | ||
205 | |||
206 | impl ToChalk for TypeCtor { | ||
207 | type Chalk = TypeName<Interner>; | ||
208 | |||
209 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { | ||
210 | match self { | ||
211 | TypeCtor::AssociatedType(type_alias) => { | ||
212 | let type_id = type_alias.to_chalk(db); | ||
213 | TypeName::AssociatedType(type_id) | ||
214 | } | ||
215 | |||
216 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), | ||
217 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), | ||
218 | TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), | ||
219 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => { | ||
220 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) | ||
221 | } | ||
222 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => { | ||
223 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) | ||
224 | } | ||
225 | |||
226 | TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()), | ||
227 | TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)), | ||
228 | TypeCtor::Slice => TypeName::Slice, | ||
229 | TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), | ||
230 | TypeCtor::Str => TypeName::Str, | ||
231 | TypeCtor::FnDef(callable_def) => { | ||
232 | let id = callable_def.to_chalk(db); | ||
233 | TypeName::FnDef(id) | ||
234 | } | ||
235 | TypeCtor::Int(Uncertain::Unknown) | ||
236 | | TypeCtor::Float(Uncertain::Unknown) | ||
237 | | TypeCtor::Adt(_) | ||
238 | | TypeCtor::Array | ||
239 | | TypeCtor::FnPtr { .. } | ||
240 | | TypeCtor::Never | ||
241 | | TypeCtor::Closure { .. } => { | ||
242 | // other TypeCtors get interned and turned into a chalk StructId | ||
243 | let struct_id = db.intern_type_ctor(self).into(); | ||
244 | TypeName::Adt(struct_id) | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { | ||
250 | match type_name { | ||
251 | TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), | ||
252 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | ||
253 | TypeName::OpaqueType(_) => unreachable!(), | ||
254 | |||
255 | TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, | ||
256 | TypeName::Scalar(Scalar::Char) => TypeCtor::Char, | ||
257 | TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { | ||
258 | signedness: Signedness::Signed, | ||
259 | bitness: bitness_from_chalk_int(int_ty), | ||
260 | })), | ||
261 | TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { | ||
262 | signedness: Signedness::Unsigned, | ||
263 | bitness: bitness_from_chalk_uint(uint_ty), | ||
264 | })), | ||
265 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { | ||
266 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) | ||
267 | } | ||
268 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { | ||
269 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) | ||
270 | } | ||
271 | TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, | ||
272 | TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), | ||
273 | TypeName::Slice => TypeCtor::Slice, | ||
274 | TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), | ||
275 | TypeName::Str => TypeCtor::Str, | ||
276 | |||
277 | TypeName::FnDef(fn_def_id) => { | ||
278 | let callable_def = from_chalk(db, fn_def_id); | ||
279 | TypeCtor::FnDef(callable_def) | ||
280 | } | ||
281 | |||
282 | TypeName::Error => { | ||
283 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | ||
284 | unreachable!() | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | |||
290 | fn bitness_from_chalk_uint(uint_ty: chalk_ir::UintTy) -> IntBitness { | ||
291 | use chalk_ir::UintTy; | ||
292 | |||
293 | match uint_ty { | ||
294 | UintTy::Usize => IntBitness::Xsize, | ||
295 | UintTy::U8 => IntBitness::X8, | ||
296 | UintTy::U16 => IntBitness::X16, | ||
297 | UintTy::U32 => IntBitness::X32, | ||
298 | UintTy::U64 => IntBitness::X64, | ||
299 | UintTy::U128 => IntBitness::X128, | ||
300 | } | ||
301 | } | ||
302 | |||
303 | fn bitness_from_chalk_int(int_ty: chalk_ir::IntTy) -> IntBitness { | ||
304 | use chalk_ir::IntTy; | ||
305 | |||
306 | match int_ty { | ||
307 | IntTy::Isize => IntBitness::Xsize, | ||
308 | IntTy::I8 => IntBitness::X8, | ||
309 | IntTy::I16 => IntBitness::X16, | ||
310 | IntTy::I32 => IntBitness::X32, | ||
311 | IntTy::I64 => IntBitness::X64, | ||
312 | IntTy::I128 => IntBitness::X128, | ||
313 | } | ||
314 | } | ||
315 | |||
316 | fn int_ty_to_chalk(int_ty: IntTy) -> Scalar { | ||
317 | use chalk_ir::{IntTy, UintTy}; | ||
318 | |||
319 | match int_ty.signedness { | ||
320 | Signedness::Signed => Scalar::Int(match int_ty.bitness { | ||
321 | IntBitness::Xsize => IntTy::Isize, | ||
322 | IntBitness::X8 => IntTy::I8, | ||
323 | IntBitness::X16 => IntTy::I16, | ||
324 | IntBitness::X32 => IntTy::I32, | ||
325 | IntBitness::X64 => IntTy::I64, | ||
326 | IntBitness::X128 => IntTy::I128, | ||
327 | }), | ||
328 | Signedness::Unsigned => Scalar::Uint(match int_ty.bitness { | ||
329 | IntBitness::Xsize => UintTy::Usize, | ||
330 | IntBitness::X8 => UintTy::U8, | ||
331 | IntBitness::X16 => UintTy::U16, | ||
332 | IntBitness::X32 => UintTy::U32, | ||
333 | IntBitness::X64 => UintTy::U64, | ||
334 | IntBitness::X128 => UintTy::U128, | ||
335 | }), | ||
336 | } | ||
337 | } | ||
338 | |||
339 | impl ToChalk for Mutability { | ||
340 | type Chalk = chalk_ir::Mutability; | ||
341 | fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk { | ||
342 | match self { | ||
343 | Mutability::Shared => chalk_ir::Mutability::Not, | ||
344 | Mutability::Mut => chalk_ir::Mutability::Mut, | ||
345 | } | ||
346 | } | ||
347 | fn from_chalk(_db: &dyn HirDatabase, chalk: Self::Chalk) -> Self { | ||
348 | match chalk { | ||
349 | chalk_ir::Mutability::Mut => Mutability::Mut, | ||
350 | chalk_ir::Mutability::Not => Mutability::Shared, | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | |||
355 | impl ToChalk for Impl { | ||
356 | type Chalk = ImplId; | ||
357 | |||
358 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplId { | ||
359 | db.intern_chalk_impl(self).into() | ||
360 | } | ||
361 | |||
362 | fn from_chalk(db: &dyn HirDatabase, impl_id: ImplId) -> Impl { | ||
363 | db.lookup_intern_chalk_impl(impl_id.into()) | ||
364 | } | ||
365 | } | ||
366 | |||
367 | impl ToChalk for CallableDef { | ||
368 | type Chalk = FnDefId; | ||
369 | |||
370 | fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { | ||
371 | db.intern_callable_def(self).into() | ||
372 | } | ||
373 | |||
374 | fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef { | ||
375 | db.lookup_intern_callable_def(fn_def_id.into()) | ||
376 | } | ||
377 | } | ||
378 | |||
379 | impl ToChalk for TypeAliasId { | ||
380 | type Chalk = AssocTypeId; | ||
381 | |||
382 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { | ||
383 | chalk_ir::AssocTypeId(self.as_intern_id()) | ||
384 | } | ||
385 | |||
386 | fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { | ||
387 | InternKey::from_intern_id(type_alias_id.0) | ||
388 | } | ||
389 | } | ||
390 | |||
391 | impl ToChalk for AssocTyValue { | ||
392 | type Chalk = AssociatedTyValueId; | ||
393 | |||
394 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValueId { | ||
395 | db.intern_assoc_ty_value(self).into() | ||
396 | } | ||
397 | |||
398 | fn from_chalk(db: &dyn HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue { | ||
399 | db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) | ||
400 | } | ||
401 | } | ||
402 | |||
403 | impl ToChalk for GenericPredicate { | ||
404 | type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; | ||
405 | |||
406 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { | ||
407 | match self { | ||
408 | GenericPredicate::Implemented(trait_ref) => { | ||
409 | let chalk_trait_ref = trait_ref.to_chalk(db); | ||
410 | let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); | ||
411 | make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) | ||
412 | } | ||
413 | GenericPredicate::Projection(projection_pred) => { | ||
414 | let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); | ||
415 | let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); | ||
416 | let alias = chalk_ir::AliasTy::Projection(projection); | ||
417 | make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0) | ||
418 | } | ||
419 | GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), | ||
420 | } | ||
421 | } | ||
422 | |||
423 | fn from_chalk( | ||
424 | db: &dyn HirDatabase, | ||
425 | where_clause: chalk_ir::QuantifiedWhereClause<Interner>, | ||
426 | ) -> GenericPredicate { | ||
427 | // we don't produce any where clauses with binders and can't currently deal with them | ||
428 | match where_clause | ||
429 | .skip_binders() | ||
430 | .shifted_out(&Interner) | ||
431 | .expect("unexpected bound vars in where clause") | ||
432 | { | ||
433 | chalk_ir::WhereClause::Implemented(tr) => { | ||
434 | GenericPredicate::Implemented(from_chalk(db, tr)) | ||
435 | } | ||
436 | chalk_ir::WhereClause::AliasEq(projection_eq) => { | ||
437 | let projection_ty = from_chalk( | ||
438 | db, | ||
439 | match projection_eq.alias { | ||
440 | chalk_ir::AliasTy::Projection(p) => p, | ||
441 | _ => unimplemented!(), | ||
442 | }, | ||
443 | ); | ||
444 | let ty = from_chalk(db, projection_eq.ty); | ||
445 | GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty }) | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | |||
451 | impl ToChalk for ProjectionTy { | ||
452 | type Chalk = chalk_ir::ProjectionTy<Interner>; | ||
453 | |||
454 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { | ||
455 | chalk_ir::ProjectionTy { | ||
456 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
457 | substitution: self.parameters.to_chalk(db), | ||
458 | } | ||
459 | } | ||
460 | |||
461 | fn from_chalk( | ||
462 | db: &dyn HirDatabase, | ||
463 | projection_ty: chalk_ir::ProjectionTy<Interner>, | ||
464 | ) -> ProjectionTy { | ||
465 | ProjectionTy { | ||
466 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
467 | parameters: from_chalk(db, projection_ty.substitution), | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | |||
472 | impl ToChalk for ProjectionPredicate { | ||
473 | type Chalk = chalk_ir::AliasEq<Interner>; | ||
474 | |||
475 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { | ||
476 | chalk_ir::AliasEq { | ||
477 | alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)), | ||
478 | ty: self.ty.to_chalk(db), | ||
479 | } | ||
480 | } | ||
481 | |||
482 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { | ||
483 | unimplemented!() | ||
484 | } | ||
485 | } | ||
486 | |||
487 | impl ToChalk for Obligation { | ||
488 | type Chalk = chalk_ir::DomainGoal<Interner>; | ||
489 | |||
490 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { | ||
491 | match self { | ||
492 | Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), | ||
493 | Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), | ||
494 | } | ||
495 | } | ||
496 | |||
497 | fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self { | ||
498 | unimplemented!() | ||
499 | } | ||
500 | } | ||
501 | |||
502 | impl<T> ToChalk for Canonical<T> | ||
503 | where | ||
504 | T: ToChalk, | ||
505 | T::Chalk: HasInterner<Interner = Interner>, | ||
506 | { | ||
507 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
508 | |||
509 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
510 | let parameter = chalk_ir::CanonicalVarKind::new( | ||
511 | chalk_ir::VariableKind::Ty, | ||
512 | chalk_ir::UniverseIndex::ROOT, | ||
513 | ); | ||
514 | let value = self.value.to_chalk(db); | ||
515 | chalk_ir::Canonical { | ||
516 | value, | ||
517 | binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]), | ||
518 | } | ||
519 | } | ||
520 | |||
521 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
522 | Canonical { | ||
523 | num_vars: canonical.binders.len(&Interner), | ||
524 | value: from_chalk(db, canonical.value), | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | |||
529 | impl ToChalk for Arc<TraitEnvironment> { | ||
530 | type Chalk = chalk_ir::Environment<Interner>; | ||
531 | |||
532 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> { | ||
533 | let mut clauses = Vec::new(); | ||
534 | for pred in &self.predicates { | ||
535 | if pred.is_error() { | ||
536 | // for env, we just ignore errors | ||
537 | continue; | ||
538 | } | ||
539 | let program_clause: chalk_ir::ProgramClause<Interner> = | ||
540 | pred.clone().to_chalk(db).cast(&Interner); | ||
541 | clauses.push(program_clause.into_from_env_clause(&Interner)); | ||
542 | } | ||
543 | chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses) | ||
544 | } | ||
545 | |||
546 | fn from_chalk( | ||
547 | _db: &dyn HirDatabase, | ||
548 | _env: chalk_ir::Environment<Interner>, | ||
549 | ) -> Arc<TraitEnvironment> { | ||
550 | unimplemented!() | ||
551 | } | ||
552 | } | ||
553 | |||
554 | impl<T: ToChalk> ToChalk for InEnvironment<T> | ||
555 | where | ||
556 | T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>, | ||
557 | { | ||
558 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
559 | |||
560 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
561 | chalk_ir::InEnvironment { | ||
562 | environment: self.environment.to_chalk(db), | ||
563 | goal: self.value.to_chalk(db), | ||
564 | } | ||
565 | } | ||
566 | |||
567 | fn from_chalk( | ||
568 | db: &dyn HirDatabase, | ||
569 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
570 | ) -> InEnvironment<T> { | ||
571 | InEnvironment { | ||
572 | environment: from_chalk(db, in_env.environment), | ||
573 | value: from_chalk(db, in_env.goal), | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | |||
578 | impl ToChalk for builtin::BuiltinImplData { | ||
579 | type Chalk = ImplDatum; | ||
580 | |||
581 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum { | ||
582 | let impl_type = chalk_rust_ir::ImplType::External; | ||
583 | let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); | ||
584 | |||
585 | let impl_datum_bound = | ||
586 | chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; | ||
587 | let associated_ty_value_ids = | ||
588 | self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); | ||
589 | chalk_rust_ir::ImplDatum { | ||
590 | binders: make_binders(impl_datum_bound, self.num_vars), | ||
591 | impl_type, | ||
592 | polarity: chalk_rust_ir::Polarity::Positive, | ||
593 | associated_ty_value_ids, | ||
594 | } | ||
595 | } | ||
596 | |||
597 | fn from_chalk(_db: &dyn HirDatabase, _data: ImplDatum) -> Self { | ||
598 | unimplemented!() | ||
599 | } | ||
600 | } | ||
601 | |||
602 | impl ToChalk for builtin::BuiltinImplAssocTyValueData { | ||
603 | type Chalk = AssociatedTyValue; | ||
604 | |||
605 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { | ||
606 | let ty = self.value.to_chalk(db); | ||
607 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty }; | ||
608 | |||
609 | chalk_rust_ir::AssociatedTyValue { | ||
610 | associated_ty_id: self.assoc_ty_id.to_chalk(db), | ||
611 | impl_id: self.impl_.to_chalk(db), | ||
612 | value: make_binders(value_bound, self.num_vars), | ||
613 | } | ||
614 | } | ||
615 | |||
616 | fn from_chalk( | ||
617 | _db: &dyn HirDatabase, | ||
618 | _data: AssociatedTyValue, | ||
619 | ) -> builtin::BuiltinImplAssocTyValueData { | ||
620 | unimplemented!() | ||
621 | } | ||
622 | } | ||
623 | |||
624 | pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> | ||
625 | where | ||
626 | T: HasInterner<Interner = Interner>, | ||
627 | { | ||
628 | chalk_ir::Binders::new( | ||
629 | chalk_ir::VariableKinds::from( | ||
630 | &Interner, | ||
631 | std::iter::repeat(chalk_ir::VariableKind::Ty).take(num_vars), | ||
632 | ), | ||
633 | value, | ||
634 | ) | ||
635 | } | ||
636 | |||
637 | pub(super) fn convert_where_clauses( | ||
638 | db: &dyn HirDatabase, | ||
639 | def: GenericDefId, | ||
640 | substs: &Substs, | ||
641 | ) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> { | ||
642 | let generic_predicates = db.generic_predicates(def); | ||
643 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
644 | for pred in generic_predicates.iter() { | ||
645 | if pred.value.is_error() { | ||
646 | // skip errored predicates completely | ||
647 | continue; | ||
648 | } | ||
649 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
650 | } | ||
651 | result | ||
652 | } | ||
653 | |||
654 | pub(super) fn generic_predicate_to_inline_bound( | ||
655 | db: &dyn HirDatabase, | ||
656 | pred: &GenericPredicate, | ||
657 | self_ty: &Ty, | ||
658 | ) -> Option<chalk_rust_ir::InlineBound<Interner>> { | ||
659 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
660 | // We don't have a special type for this, but Chalk does. | ||
661 | match pred { | ||
662 | GenericPredicate::Implemented(trait_ref) => { | ||
663 | if &trait_ref.substs[0] != self_ty { | ||
664 | // we can only convert predicates back to type bounds if they | ||
665 | // have the expected self type | ||
666 | return None; | ||
667 | } | ||
668 | let args_no_self = trait_ref.substs[1..] | ||
669 | .iter() | ||
670 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
671 | .collect(); | ||
672 | let trait_bound = | ||
673 | chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | ||
674 | Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound)) | ||
675 | } | ||
676 | GenericPredicate::Projection(proj) => { | ||
677 | if &proj.projection_ty.parameters[0] != self_ty { | ||
678 | return None; | ||
679 | } | ||
680 | let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container { | ||
681 | AssocContainerId::TraitId(t) => t, | ||
682 | _ => panic!("associated type not in trait"), | ||
683 | }; | ||
684 | let args_no_self = proj.projection_ty.parameters[1..] | ||
685 | .iter() | ||
686 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
687 | .collect(); | ||
688 | let alias_eq_bound = chalk_rust_ir::AliasEqBound { | ||
689 | value: proj.ty.clone().to_chalk(db), | ||
690 | trait_bound: chalk_rust_ir::TraitBound { | ||
691 | trait_id: trait_.to_chalk(db), | ||
692 | args_no_self, | ||
693 | }, | ||
694 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | ||
695 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
696 | }; | ||
697 | Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | ||
698 | } | ||
699 | GenericPredicate::Error => None, | ||
700 | } | ||
701 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index 4867cb17e..d88828c7c 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Implementation of Chalk debug helper functions using TLS. | 1 | //! Implementation of Chalk debug helper functions using TLS. |
2 | use std::fmt; | 2 | use std::fmt; |
3 | 3 | ||
4 | use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; | 4 | use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName}; |
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | 6 | ||
7 | use super::{from_chalk, Interner}; | 7 | use super::{from_chalk, Interner}; |
@@ -15,10 +15,10 @@ pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a)); | |||
15 | impl DebugContext<'_> { | 15 | impl DebugContext<'_> { |
16 | pub fn debug_struct_id( | 16 | pub fn debug_struct_id( |
17 | &self, | 17 | &self, |
18 | id: super::StructId, | 18 | id: super::AdtId, |
19 | f: &mut fmt::Formatter<'_>, | 19 | f: &mut fmt::Formatter<'_>, |
20 | ) -> Result<(), fmt::Error> { | 20 | ) -> Result<(), fmt::Error> { |
21 | let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Struct(id)); | 21 | let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Adt(id)); |
22 | match type_ctor { | 22 | match type_ctor { |
23 | TypeCtor::Bool => write!(f, "bool")?, | 23 | TypeCtor::Bool => write!(f, "bool")?, |
24 | TypeCtor::Char => write!(f, "char")?, | 24 | TypeCtor::Char => write!(f, "char")?, |
@@ -188,9 +188,9 @@ impl DebugContext<'_> { | |||
188 | write!(fmt, "{:?}", lifetime.data(&Interner)) | 188 | write!(fmt, "{:?}", lifetime.data(&Interner)) |
189 | } | 189 | } |
190 | 190 | ||
191 | pub fn debug_parameter( | 191 | pub fn debug_generic_arg( |
192 | &self, | 192 | &self, |
193 | parameter: &Parameter<Interner>, | 193 | parameter: &GenericArg<Interner>, |
194 | fmt: &mut fmt::Formatter<'_>, | 194 | fmt: &mut fmt::Formatter<'_>, |
195 | ) -> Result<(), fmt::Error> { | 195 | ) -> Result<(), fmt::Error> { |
196 | write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) | 196 | write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) |
@@ -244,6 +244,79 @@ impl DebugContext<'_> { | |||
244 | ) -> Result<(), fmt::Error> { | 244 | ) -> Result<(), fmt::Error> { |
245 | write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) | 245 | write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) |
246 | } | 246 | } |
247 | |||
248 | pub fn debug_fn_def_id( | ||
249 | &self, | ||
250 | fn_def_id: chalk_ir::FnDefId<Interner>, | ||
251 | fmt: &mut fmt::Formatter<'_>, | ||
252 | ) -> Result<(), fmt::Error> { | ||
253 | let def: CallableDef = from_chalk(self.0, fn_def_id); | ||
254 | let name = match def { | ||
255 | CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(), | ||
256 | CallableDef::StructId(s) => self.0.struct_data(s).name.clone(), | ||
257 | CallableDef::EnumVariantId(e) => { | ||
258 | let enum_data = self.0.enum_data(e.parent); | ||
259 | enum_data.variants[e.local_id].name.clone() | ||
260 | } | ||
261 | }; | ||
262 | match def { | ||
263 | CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name), | ||
264 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { | ||
265 | write!(fmt, "{{ctor {}}}", name) | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | |||
270 | pub fn debug_const( | ||
271 | &self, | ||
272 | _constant: &chalk_ir::Const<Interner>, | ||
273 | fmt: &mut fmt::Formatter<'_>, | ||
274 | ) -> fmt::Result { | ||
275 | write!(fmt, "const") | ||
276 | } | ||
277 | |||
278 | pub fn debug_variable_kinds( | ||
279 | &self, | ||
280 | variable_kinds: &chalk_ir::VariableKinds<Interner>, | ||
281 | fmt: &mut fmt::Formatter<'_>, | ||
282 | ) -> fmt::Result { | ||
283 | write!(fmt, "{:?}", variable_kinds.as_slice(&Interner)) | ||
284 | } | ||
285 | pub fn debug_variable_kinds_with_angles( | ||
286 | &self, | ||
287 | variable_kinds: &chalk_ir::VariableKinds<Interner>, | ||
288 | fmt: &mut fmt::Formatter<'_>, | ||
289 | ) -> fmt::Result { | ||
290 | write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner)) | ||
291 | } | ||
292 | pub fn debug_canonical_var_kinds( | ||
293 | &self, | ||
294 | canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>, | ||
295 | fmt: &mut fmt::Formatter<'_>, | ||
296 | ) -> fmt::Result { | ||
297 | write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner)) | ||
298 | } | ||
299 | pub fn debug_program_clause( | ||
300 | &self, | ||
301 | clause: &chalk_ir::ProgramClause<Interner>, | ||
302 | fmt: &mut fmt::Formatter<'_>, | ||
303 | ) -> fmt::Result { | ||
304 | write!(fmt, "{:?}", clause.data(&Interner)) | ||
305 | } | ||
306 | pub fn debug_program_clauses( | ||
307 | &self, | ||
308 | clauses: &chalk_ir::ProgramClauses<Interner>, | ||
309 | fmt: &mut fmt::Formatter<'_>, | ||
310 | ) -> fmt::Result { | ||
311 | write!(fmt, "{:?}", clauses.as_slice(&Interner)) | ||
312 | } | ||
313 | pub fn debug_quantified_where_clauses( | ||
314 | &self, | ||
315 | clauses: &chalk_ir::QuantifiedWhereClauses<Interner>, | ||
316 | fmt: &mut fmt::Formatter<'_>, | ||
317 | ) -> fmt::Result { | ||
318 | write!(fmt, "{:?}", clauses.as_slice(&Interner)) | ||
319 | } | ||
247 | } | 320 | } |
248 | 321 | ||
249 | mod unsafe_tls { | 322 | mod unsafe_tls { |
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs index 780a03c13..aa039e6fc 100644 --- a/crates/ra_ide/src/call_info.rs +++ b/crates/ra_ide/src/call_info.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | ast::{self, ArgListOwner}, | 5 | ast::{self, ArgListOwner}, |
6 | match_ast, AstNode, SyntaxNode, SyntaxToken, | 6 | match_ast, AstNode, SyntaxNode, SyntaxToken, |
7 | }; | 7 | }; |
8 | use test_utils::tested_by; | 8 | use test_utils::mark; |
9 | 9 | ||
10 | use crate::{CallInfo, FilePosition, FunctionSignature}; | 10 | use crate::{CallInfo, FilePosition, FunctionSignature}; |
11 | 11 | ||
@@ -84,7 +84,7 @@ fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Op | |||
84 | 84 | ||
85 | let arg_list_range = arg_list.syntax().text_range(); | 85 | let arg_list_range = arg_list.syntax().text_range(); |
86 | if !arg_list_range.contains_inclusive(token.text_range().start()) { | 86 | if !arg_list_range.contains_inclusive(token.text_range().start()) { |
87 | tested_by!(call_info_bad_offset); | 87 | mark::hit!(call_info_bad_offset); |
88 | return None; | 88 | return None; |
89 | } | 89 | } |
90 | 90 | ||
@@ -213,7 +213,7 @@ impl CallInfo { | |||
213 | 213 | ||
214 | #[cfg(test)] | 214 | #[cfg(test)] |
215 | mod tests { | 215 | mod tests { |
216 | use test_utils::covers; | 216 | use test_utils::mark; |
217 | 217 | ||
218 | use crate::mock_analysis::single_file_with_position; | 218 | use crate::mock_analysis::single_file_with_position; |
219 | 219 | ||
@@ -529,7 +529,7 @@ By default this method stops actor's `Context`."# | |||
529 | 529 | ||
530 | #[test] | 530 | #[test] |
531 | fn call_info_bad_offset() { | 531 | fn call_info_bad_offset() { |
532 | covers!(call_info_bad_offset); | 532 | mark::check!(call_info_bad_offset); |
533 | let (analysis, position) = single_file_with_position( | 533 | let (analysis, position) = single_file_with_position( |
534 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 534 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} |
535 | fn bar() { foo <|> (3, ); }"#, | 535 | fn bar() { foo <|> (3, ); }"#, |
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index db7430454..02ac0166b 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; | 3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; |
4 | use ra_syntax::AstNode; | 4 | use ra_syntax::AstNode; |
5 | use rustc_hash::FxHashSet; | 5 | use rustc_hash::FxHashSet; |
6 | use test_utils::tested_by; | 6 | use test_utils::mark; |
7 | 7 | ||
8 | use crate::completion::{CompletionContext, Completions}; | 8 | use crate::completion::{CompletionContext, Completions}; |
9 | 9 | ||
@@ -40,7 +40,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
40 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | 40 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { |
41 | if name_ref.syntax().text() == name.to_string().as_str() { | 41 | if name_ref.syntax().text() == name.to_string().as_str() { |
42 | // for `use self::foo<|>`, don't suggest `foo` as a completion | 42 | // for `use self::foo<|>`, don't suggest `foo` as a completion |
43 | tested_by!(dont_complete_current_use); | 43 | mark::hit!(dont_complete_current_use); |
44 | continue; | 44 | continue; |
45 | } | 45 | } |
46 | } | 46 | } |
@@ -147,7 +147,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
147 | 147 | ||
148 | #[cfg(test)] | 148 | #[cfg(test)] |
149 | mod tests { | 149 | mod tests { |
150 | use test_utils::covers; | 150 | use test_utils::mark; |
151 | 151 | ||
152 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 152 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
153 | use insta::assert_debug_snapshot; | 153 | use insta::assert_debug_snapshot; |
@@ -158,7 +158,7 @@ mod tests { | |||
158 | 158 | ||
159 | #[test] | 159 | #[test] |
160 | fn dont_complete_current_use() { | 160 | fn dont_complete_current_use() { |
161 | covers!(dont_complete_current_use); | 161 | mark::check!(dont_complete_current_use); |
162 | let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); | 162 | let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); |
163 | assert!(completions.is_empty()); | 163 | assert!(completions.is_empty()); |
164 | } | 164 | } |
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index bd40af1cb..db791660a 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use hir::ScopeDef; | 3 | use hir::ScopeDef; |
4 | use test_utils::tested_by; | 4 | use test_utils::mark; |
5 | 5 | ||
6 | use crate::completion::{CompletionContext, Completions}; | 6 | use crate::completion::{CompletionContext, Completions}; |
7 | use hir::{Adt, ModuleDef, Type}; | 7 | use hir::{Adt, ModuleDef, Type}; |
@@ -30,7 +30,7 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
30 | if ctx.use_item_syntax.is_some() { | 30 | if ctx.use_item_syntax.is_some() { |
31 | if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { | 31 | if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { |
32 | if name_ref.syntax().text() == name.to_string().as_str() { | 32 | if name_ref.syntax().text() == name.to_string().as_str() { |
33 | tested_by!(self_fulfilling_completion); | 33 | mark::hit!(self_fulfilling_completion); |
34 | return; | 34 | return; |
35 | } | 35 | } |
36 | } | 36 | } |
@@ -66,7 +66,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
66 | #[cfg(test)] | 66 | #[cfg(test)] |
67 | mod tests { | 67 | mod tests { |
68 | use insta::assert_debug_snapshot; | 68 | use insta::assert_debug_snapshot; |
69 | use test_utils::covers; | 69 | use test_utils::mark; |
70 | 70 | ||
71 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 71 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
72 | 72 | ||
@@ -76,7 +76,7 @@ mod tests { | |||
76 | 76 | ||
77 | #[test] | 77 | #[test] |
78 | fn self_fulfilling_completion() { | 78 | fn self_fulfilling_completion() { |
79 | covers!(self_fulfilling_completion); | 79 | mark::check!(self_fulfilling_completion); |
80 | assert_debug_snapshot!( | 80 | assert_debug_snapshot!( |
81 | do_reference_completion( | 81 | do_reference_completion( |
82 | r#" | 82 | r#" |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 6021f7279..cfb7c1e38 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -63,8 +63,8 @@ impl fmt::Debug for CompletionItem { | |||
63 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 63 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
64 | let mut s = f.debug_struct("CompletionItem"); | 64 | let mut s = f.debug_struct("CompletionItem"); |
65 | s.field("label", &self.label()).field("source_range", &self.source_range()); | 65 | s.field("label", &self.label()).field("source_range", &self.source_range()); |
66 | if self.text_edit().as_indels().len() == 1 { | 66 | if self.text_edit().len() == 1 { |
67 | let atom = &self.text_edit().as_indels()[0]; | 67 | let atom = &self.text_edit().iter().next().unwrap(); |
68 | s.field("delete", &atom.delete); | 68 | s.field("delete", &atom.delete); |
69 | s.field("insert", &atom.insert); | 69 | s.field("insert", &atom.insert); |
70 | } else { | 70 | } else { |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 077cf9647..440ffa31d 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; | 3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; |
4 | use ra_syntax::ast::NameOwner; | 4 | use ra_syntax::ast::NameOwner; |
5 | use stdx::SepBy; | 5 | use stdx::SepBy; |
6 | use test_utils::tested_by; | 6 | use test_utils::mark; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | completion::{ | 9 | completion::{ |
@@ -121,7 +121,7 @@ impl Completions { | |||
121 | _ => false, | 121 | _ => false, |
122 | }; | 122 | }; |
123 | if has_non_default_type_params { | 123 | if has_non_default_type_params { |
124 | tested_by!(inserts_angle_brackets_for_generics); | 124 | mark::hit!(inserts_angle_brackets_for_generics); |
125 | completion_item = completion_item | 125 | completion_item = completion_item |
126 | .lookup_by(local_name.clone()) | 126 | .lookup_by(local_name.clone()) |
127 | .label(format!("{}<…>", local_name)) | 127 | .label(format!("{}<…>", local_name)) |
@@ -176,7 +176,7 @@ impl Completions { | |||
176 | } | 176 | } |
177 | None if needs_bang => builder.insert_text(format!("{}!", name)), | 177 | None if needs_bang => builder.insert_text(format!("{}!", name)), |
178 | _ => { | 178 | _ => { |
179 | tested_by!(dont_insert_macro_call_parens_unncessary); | 179 | mark::hit!(dont_insert_macro_call_parens_unncessary); |
180 | builder.insert_text(name) | 180 | builder.insert_text(name) |
181 | } | 181 | } |
182 | }; | 182 | }; |
@@ -330,14 +330,14 @@ pub(crate) fn compute_score( | |||
330 | // FIXME: this should not fall back to string equality. | 330 | // FIXME: this should not fall back to string equality. |
331 | let ty = &ty.display(ctx.db).to_string(); | 331 | let ty = &ty.display(ctx.db).to_string(); |
332 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { | 332 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { |
333 | tested_by!(test_struct_field_completion_in_record_lit); | 333 | mark::hit!(test_struct_field_completion_in_record_lit); |
334 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; | 334 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; |
335 | ( | 335 | ( |
336 | struct_field.name(ctx.db).to_string(), | 336 | struct_field.name(ctx.db).to_string(), |
337 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), | 337 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), |
338 | ) | 338 | ) |
339 | } else if let Some(active_parameter) = &ctx.active_parameter { | 339 | } else if let Some(active_parameter) = &ctx.active_parameter { |
340 | tested_by!(test_struct_field_completion_in_func_call); | 340 | mark::hit!(test_struct_field_completion_in_func_call); |
341 | (active_parameter.name.clone(), active_parameter.ty.clone()) | 341 | (active_parameter.name.clone(), active_parameter.ty.clone()) |
342 | } else { | 342 | } else { |
343 | return None; | 343 | return None; |
@@ -398,7 +398,7 @@ impl Builder { | |||
398 | None => return self, | 398 | None => return self, |
399 | }; | 399 | }; |
400 | // If not an import, add parenthesis automatically. | 400 | // If not an import, add parenthesis automatically. |
401 | tested_by!(inserts_parens_for_function_calls); | 401 | mark::hit!(inserts_parens_for_function_calls); |
402 | 402 | ||
403 | let (snippet, label) = if params.is_empty() { | 403 | let (snippet, label) = if params.is_empty() { |
404 | (format!("{}()$0", name), format!("{}()", name)) | 404 | (format!("{}()$0", name), format!("{}()", name)) |
@@ -457,7 +457,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s | |||
457 | #[cfg(test)] | 457 | #[cfg(test)] |
458 | mod tests { | 458 | mod tests { |
459 | use insta::assert_debug_snapshot; | 459 | use insta::assert_debug_snapshot; |
460 | use test_utils::covers; | 460 | use test_utils::mark; |
461 | 461 | ||
462 | use crate::completion::{ | 462 | use crate::completion::{ |
463 | test_utils::{do_completion, do_completion_with_options}, | 463 | test_utils::{do_completion, do_completion_with_options}, |
@@ -607,7 +607,7 @@ mod tests { | |||
607 | 607 | ||
608 | #[test] | 608 | #[test] |
609 | fn inserts_parens_for_function_calls() { | 609 | fn inserts_parens_for_function_calls() { |
610 | covers!(inserts_parens_for_function_calls); | 610 | mark::check!(inserts_parens_for_function_calls); |
611 | assert_debug_snapshot!( | 611 | assert_debug_snapshot!( |
612 | do_reference_completion( | 612 | do_reference_completion( |
613 | r" | 613 | r" |
@@ -992,7 +992,7 @@ mod tests { | |||
992 | 992 | ||
993 | #[test] | 993 | #[test] |
994 | fn inserts_angle_brackets_for_generics() { | 994 | fn inserts_angle_brackets_for_generics() { |
995 | covers!(inserts_angle_brackets_for_generics); | 995 | mark::check!(inserts_angle_brackets_for_generics); |
996 | assert_debug_snapshot!( | 996 | assert_debug_snapshot!( |
997 | do_reference_completion( | 997 | do_reference_completion( |
998 | r" | 998 | r" |
@@ -1115,7 +1115,7 @@ mod tests { | |||
1115 | 1115 | ||
1116 | #[test] | 1116 | #[test] |
1117 | fn dont_insert_macro_call_parens_unncessary() { | 1117 | fn dont_insert_macro_call_parens_unncessary() { |
1118 | covers!(dont_insert_macro_call_parens_unncessary); | 1118 | mark::check!(dont_insert_macro_call_parens_unncessary); |
1119 | assert_debug_snapshot!( | 1119 | assert_debug_snapshot!( |
1120 | do_reference_completion( | 1120 | do_reference_completion( |
1121 | r" | 1121 | r" |
@@ -1181,7 +1181,7 @@ mod tests { | |||
1181 | 1181 | ||
1182 | #[test] | 1182 | #[test] |
1183 | fn test_struct_field_completion_in_func_call() { | 1183 | fn test_struct_field_completion_in_func_call() { |
1184 | covers!(test_struct_field_completion_in_func_call); | 1184 | mark::check!(test_struct_field_completion_in_func_call); |
1185 | assert_debug_snapshot!( | 1185 | assert_debug_snapshot!( |
1186 | do_reference_completion( | 1186 | do_reference_completion( |
1187 | r" | 1187 | r" |
@@ -1271,7 +1271,7 @@ mod tests { | |||
1271 | 1271 | ||
1272 | #[test] | 1272 | #[test] |
1273 | fn test_struct_field_completion_in_record_lit() { | 1273 | fn test_struct_field_completion_in_record_lit() { |
1274 | covers!(test_struct_field_completion_in_record_lit); | 1274 | mark::check!(test_struct_field_completion_in_record_lit); |
1275 | assert_debug_snapshot!( | 1275 | assert_debug_snapshot!( |
1276 | do_reference_completion( | 1276 | do_reference_completion( |
1277 | r" | 1277 | r" |
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 54c2bcc09..3d83c0f71 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ use ra_syntax::{ | |||
21 | }; | 21 | }; |
22 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 22 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
23 | 23 | ||
24 | use crate::{Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit}; | 24 | use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceChange, SourceFileEdit}; |
25 | 25 | ||
26 | #[derive(Debug, Copy, Clone)] | 26 | #[derive(Debug, Copy, Clone)] |
27 | pub enum Severity { | 27 | pub enum Severity { |
@@ -63,8 +63,8 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
63 | .parent() | 63 | .parent() |
64 | .unwrap_or_else(|| RelativePath::new("")) | 64 | .unwrap_or_else(|| RelativePath::new("")) |
65 | .join(&d.candidate); | 65 | .join(&d.candidate); |
66 | let create_file = FileSystemEdit::CreateFile { source_root, path }; | 66 | let fix = |
67 | let fix = SourceChange::file_system_edit("Create module", create_file); | 67 | Fix::new("Create module", FileSystemEdit::CreateFile { source_root, path }.into()); |
68 | res.borrow_mut().push(Diagnostic { | 68 | res.borrow_mut().push(Diagnostic { |
69 | range: sema.diagnostics_range(d).range, | 69 | range: sema.diagnostics_range(d).range, |
70 | message: d.message(), | 70 | message: d.message(), |
@@ -88,14 +88,12 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
88 | field_list = field_list.append_field(&field); | 88 | field_list = field_list.append_field(&field); |
89 | } | 89 | } |
90 | 90 | ||
91 | let mut builder = TextEditBuilder::default(); | 91 | let edit = { |
92 | algo::diff(&d.ast(db).syntax(), &field_list.syntax()).into_text_edit(&mut builder); | 92 | let mut builder = TextEditBuilder::default(); |
93 | 93 | algo::diff(&d.ast(db).syntax(), &field_list.syntax()).into_text_edit(&mut builder); | |
94 | Some(SourceChange::source_file_edit_from( | 94 | builder.finish() |
95 | "Fill struct fields", | 95 | }; |
96 | file_id, | 96 | Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into())) |
97 | builder.finish(), | ||
98 | )) | ||
99 | }; | 97 | }; |
100 | 98 | ||
101 | res.borrow_mut().push(Diagnostic { | 99 | res.borrow_mut().push(Diagnostic { |
@@ -117,7 +115,8 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
117 | let node = d.ast(db); | 115 | let node = d.ast(db); |
118 | let replacement = format!("Ok({})", node.syntax()); | 116 | let replacement = format!("Ok({})", node.syntax()); |
119 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); | 117 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); |
120 | let fix = SourceChange::source_file_edit_from("Wrap with ok", file_id, edit); | 118 | let source_change = SourceChange::source_file_edit_from(file_id, edit); |
119 | let fix = Fix::new("Wrap with ok", source_change); | ||
121 | res.borrow_mut().push(Diagnostic { | 120 | res.borrow_mut().push(Diagnostic { |
122 | range: sema.diagnostics_range(d).range, | 121 | range: sema.diagnostics_range(d).range, |
123 | message: d.message(), | 122 | message: d.message(), |
@@ -154,9 +153,9 @@ fn check_unnecessary_braces_in_use_statement( | |||
154 | range, | 153 | range, |
155 | message: "Unnecessary braces in use statement".to_string(), | 154 | message: "Unnecessary braces in use statement".to_string(), |
156 | severity: Severity::WeakWarning, | 155 | severity: Severity::WeakWarning, |
157 | fix: Some(SourceChange::source_file_edit( | 156 | fix: Some(Fix::new( |
158 | "Remove unnecessary braces", | 157 | "Remove unnecessary braces", |
159 | SourceFileEdit { file_id, edit }, | 158 | SourceFileEdit { file_id, edit }.into(), |
160 | )), | 159 | )), |
161 | }); | 160 | }); |
162 | } | 161 | } |
@@ -198,9 +197,9 @@ fn check_struct_shorthand_initialization( | |||
198 | range: record_field.syntax().text_range(), | 197 | range: record_field.syntax().text_range(), |
199 | message: "Shorthand struct initialization".to_string(), | 198 | message: "Shorthand struct initialization".to_string(), |
200 | severity: Severity::WeakWarning, | 199 | severity: Severity::WeakWarning, |
201 | fix: Some(SourceChange::source_file_edit( | 200 | fix: Some(Fix::new( |
202 | "Use struct shorthand initialization", | 201 | "Use struct shorthand initialization", |
203 | SourceFileEdit { file_id, edit }, | 202 | SourceFileEdit { file_id, edit }.into(), |
204 | )), | 203 | )), |
205 | }); | 204 | }); |
206 | } | 205 | } |
@@ -240,7 +239,7 @@ mod tests { | |||
240 | let diagnostic = | 239 | let diagnostic = |
241 | diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before)); | 240 | diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before)); |
242 | let mut fix = diagnostic.fix.unwrap(); | 241 | let mut fix = diagnostic.fix.unwrap(); |
243 | let edit = fix.source_file_edits.pop().unwrap().edit; | 242 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
244 | let actual = { | 243 | let actual = { |
245 | let mut actual = before.to_string(); | 244 | let mut actual = before.to_string(); |
246 | edit.apply(&mut actual); | 245 | edit.apply(&mut actual); |
@@ -258,7 +257,7 @@ mod tests { | |||
258 | let (analysis, file_position) = analysis_and_position(fixture); | 257 | let (analysis, file_position) = analysis_and_position(fixture); |
259 | let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); | 258 | let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); |
260 | let mut fix = diagnostic.fix.unwrap(); | 259 | let mut fix = diagnostic.fix.unwrap(); |
261 | let edit = fix.source_file_edits.pop().unwrap().edit; | 260 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
262 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | 261 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); |
263 | let actual = { | 262 | let actual = { |
264 | let mut actual = target_file_contents.to_string(); | 263 | let mut actual = target_file_contents.to_string(); |
@@ -295,7 +294,7 @@ mod tests { | |||
295 | let (analysis, file_id) = single_file(before); | 294 | let (analysis, file_id) = single_file(before); |
296 | let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); | 295 | let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); |
297 | let mut fix = diagnostic.fix.unwrap(); | 296 | let mut fix = diagnostic.fix.unwrap(); |
298 | let edit = fix.source_file_edits.pop().unwrap().edit; | 297 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
299 | let actual = { | 298 | let actual = { |
300 | let mut actual = before.to_string(); | 299 | let mut actual = before.to_string(); |
301 | edit.apply(&mut actual); | 300 | edit.apply(&mut actual); |
@@ -616,23 +615,24 @@ mod tests { | |||
616 | Diagnostic { | 615 | Diagnostic { |
617 | message: "unresolved module", | 616 | message: "unresolved module", |
618 | range: 0..8, | 617 | range: 0..8, |
618 | severity: Error, | ||
619 | fix: Some( | 619 | fix: Some( |
620 | SourceChange { | 620 | Fix { |
621 | label: "Create module", | 621 | label: "Create module", |
622 | source_file_edits: [], | 622 | source_change: SourceChange { |
623 | file_system_edits: [ | 623 | source_file_edits: [], |
624 | CreateFile { | 624 | file_system_edits: [ |
625 | source_root: SourceRootId( | 625 | CreateFile { |
626 | 0, | 626 | source_root: SourceRootId( |
627 | ), | 627 | 0, |
628 | path: "foo.rs", | 628 | ), |
629 | }, | 629 | path: "foo.rs", |
630 | ], | 630 | }, |
631 | cursor_position: None, | 631 | ], |
632 | is_snippet: false, | 632 | is_snippet: false, |
633 | }, | ||
633 | }, | 634 | }, |
634 | ), | 635 | ), |
635 | severity: Error, | ||
636 | }, | 636 | }, |
637 | ] | 637 | ] |
638 | "###); | 638 | "###); |
@@ -666,30 +666,31 @@ mod tests { | |||
666 | Diagnostic { | 666 | Diagnostic { |
667 | message: "Missing structure fields:\n- b", | 667 | message: "Missing structure fields:\n- b", |
668 | range: 224..233, | 668 | range: 224..233, |
669 | severity: Error, | ||
669 | fix: Some( | 670 | fix: Some( |
670 | SourceChange { | 671 | Fix { |
671 | label: "Fill struct fields", | 672 | label: "Fill struct fields", |
672 | source_file_edits: [ | 673 | source_change: SourceChange { |
673 | SourceFileEdit { | 674 | source_file_edits: [ |
674 | file_id: FileId( | 675 | SourceFileEdit { |
675 | 1, | 676 | file_id: FileId( |
676 | ), | 677 | 1, |
677 | edit: TextEdit { | 678 | ), |
678 | indels: [ | 679 | edit: TextEdit { |
679 | Indel { | 680 | indels: [ |
680 | insert: "{a:42, b: ()}", | 681 | Indel { |
681 | delete: 3..9, | 682 | insert: "{a:42, b: ()}", |
682 | }, | 683 | delete: 3..9, |
683 | ], | 684 | }, |
685 | ], | ||
686 | }, | ||
684 | }, | 687 | }, |
685 | }, | 688 | ], |
686 | ], | 689 | file_system_edits: [], |
687 | file_system_edits: [], | 690 | is_snippet: false, |
688 | cursor_position: None, | 691 | }, |
689 | is_snippet: false, | ||
690 | }, | 692 | }, |
691 | ), | 693 | ), |
692 | severity: Error, | ||
693 | }, | 694 | }, |
694 | ] | 695 | ] |
695 | "###); | 696 | "###); |
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 722092de9..8bb312156 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -79,14 +79,14 @@ pub(crate) fn rust_code_markup_with_doc( | |||
79 | doc: Option<&str>, | 79 | doc: Option<&str>, |
80 | mod_path: Option<&str>, | 80 | mod_path: Option<&str>, |
81 | ) -> String { | 81 | ) -> String { |
82 | let mut buf = "```rust\n".to_owned(); | 82 | let mut buf = String::new(); |
83 | 83 | ||
84 | if let Some(mod_path) = mod_path { | 84 | if let Some(mod_path) = mod_path { |
85 | if !mod_path.is_empty() { | 85 | if !mod_path.is_empty() { |
86 | format_to!(buf, "{}\n", mod_path); | 86 | format_to!(buf, "{}\n___\n\n", mod_path); |
87 | } | 87 | } |
88 | } | 88 | } |
89 | format_to!(buf, "{}\n```", code); | 89 | format_to!(buf, "```rust\n{}\n```", code); |
90 | 90 | ||
91 | if let Some(doc) = doc { | 91 | if let Some(doc) = doc { |
92 | format_to!(buf, "\n\n{}", doc); | 92 | format_to!(buf, "\n\n{}", doc); |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 150895abb..90e85d419 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -93,7 +93,7 @@ pub(crate) fn reference_definition( | |||
93 | 93 | ||
94 | #[cfg(test)] | 94 | #[cfg(test)] |
95 | mod tests { | 95 | mod tests { |
96 | use test_utils::{assert_eq_text, covers}; | 96 | use test_utils::assert_eq_text; |
97 | 97 | ||
98 | use crate::mock_analysis::analysis_and_position; | 98 | use crate::mock_analysis::analysis_and_position; |
99 | 99 | ||
@@ -208,7 +208,6 @@ mod tests { | |||
208 | 208 | ||
209 | #[test] | 209 | #[test] |
210 | fn goto_def_for_macros() { | 210 | fn goto_def_for_macros() { |
211 | covers!(ra_ide_db::goto_def_for_macros); | ||
212 | check_goto( | 211 | check_goto( |
213 | " | 212 | " |
214 | //- /lib.rs | 213 | //- /lib.rs |
@@ -225,7 +224,6 @@ mod tests { | |||
225 | 224 | ||
226 | #[test] | 225 | #[test] |
227 | fn goto_def_for_macros_from_other_crates() { | 226 | fn goto_def_for_macros_from_other_crates() { |
228 | covers!(ra_ide_db::goto_def_for_macros); | ||
229 | check_goto( | 227 | check_goto( |
230 | " | 228 | " |
231 | //- /lib.rs | 229 | //- /lib.rs |
@@ -245,7 +243,6 @@ mod tests { | |||
245 | 243 | ||
246 | #[test] | 244 | #[test] |
247 | fn goto_def_for_use_alias() { | 245 | fn goto_def_for_use_alias() { |
248 | covers!(ra_ide_db::goto_def_for_use_alias); | ||
249 | check_goto( | 246 | check_goto( |
250 | " | 247 | " |
251 | //- /lib.rs | 248 | //- /lib.rs |
@@ -370,7 +367,6 @@ mod tests { | |||
370 | 367 | ||
371 | #[test] | 368 | #[test] |
372 | fn goto_def_for_methods() { | 369 | fn goto_def_for_methods() { |
373 | covers!(ra_ide_db::goto_def_for_methods); | ||
374 | check_goto( | 370 | check_goto( |
375 | " | 371 | " |
376 | //- /lib.rs | 372 | //- /lib.rs |
@@ -390,7 +386,6 @@ mod tests { | |||
390 | 386 | ||
391 | #[test] | 387 | #[test] |
392 | fn goto_def_for_fields() { | 388 | fn goto_def_for_fields() { |
393 | covers!(ra_ide_db::goto_def_for_fields); | ||
394 | check_goto( | 389 | check_goto( |
395 | r" | 390 | r" |
396 | //- /lib.rs | 391 | //- /lib.rs |
@@ -409,7 +404,6 @@ mod tests { | |||
409 | 404 | ||
410 | #[test] | 405 | #[test] |
411 | fn goto_def_for_record_fields() { | 406 | fn goto_def_for_record_fields() { |
412 | covers!(ra_ide_db::goto_def_for_record_fields); | ||
413 | check_goto( | 407 | check_goto( |
414 | r" | 408 | r" |
415 | //- /lib.rs | 409 | //- /lib.rs |
@@ -430,7 +424,6 @@ mod tests { | |||
430 | 424 | ||
431 | #[test] | 425 | #[test] |
432 | fn goto_def_for_record_pat_fields() { | 426 | fn goto_def_for_record_pat_fields() { |
433 | covers!(ra_ide_db::goto_def_for_record_field_pats); | ||
434 | check_goto( | 427 | check_goto( |
435 | r" | 428 | r" |
436 | //- /lib.rs | 429 | //- /lib.rs |
@@ -873,7 +866,6 @@ mod tests { | |||
873 | 866 | ||
874 | #[test] | 867 | #[test] |
875 | fn goto_def_for_field_init_shorthand() { | 868 | fn goto_def_for_field_init_shorthand() { |
876 | covers!(ra_ide_db::goto_def_for_field_init_shorthand); | ||
877 | check_goto( | 869 | check_goto( |
878 | " | 870 | " |
879 | //- /lib.rs | 871 | //- /lib.rs |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index befa977c7..1f4f6b848 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -405,7 +405,7 @@ mod tests { | |||
405 | }; | 405 | }; |
406 | } | 406 | } |
407 | "#, | 407 | "#, |
408 | &["Foo\nfield_a: u32"], | 408 | &["Foo\n___\n\n```rust\nfield_a: u32"], |
409 | ); | 409 | ); |
410 | 410 | ||
411 | // Hovering over the field in the definition | 411 | // Hovering over the field in the definition |
@@ -422,7 +422,7 @@ mod tests { | |||
422 | }; | 422 | }; |
423 | } | 423 | } |
424 | "#, | 424 | "#, |
425 | &["Foo\nfield_a: u32"], | 425 | &["Foo\n___\n\n```rust\nfield_a: u32"], |
426 | ); | 426 | ); |
427 | } | 427 | } |
428 | 428 | ||
@@ -475,7 +475,7 @@ fn main() { | |||
475 | ", | 475 | ", |
476 | ); | 476 | ); |
477 | let hover = analysis.hover(position).unwrap().unwrap(); | 477 | let hover = analysis.hover(position).unwrap().unwrap(); |
478 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\nSome")); | 478 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\n___\n\n```rust\nSome")); |
479 | 479 | ||
480 | let (analysis, position) = single_file_with_position( | 480 | let (analysis, position) = single_file_with_position( |
481 | " | 481 | " |
@@ -503,6 +503,9 @@ fn main() { | |||
503 | "#, | 503 | "#, |
504 | &[" | 504 | &[" |
505 | Option | 505 | Option |
506 | ___ | ||
507 | |||
508 | ```rust | ||
506 | None | 509 | None |
507 | ``` | 510 | ``` |
508 | 511 | ||
@@ -524,6 +527,9 @@ The None variant | |||
524 | "#, | 527 | "#, |
525 | &[" | 528 | &[" |
526 | Option | 529 | Option |
530 | ___ | ||
531 | |||
532 | ```rust | ||
527 | Some | 533 | Some |
528 | ``` | 534 | ``` |
529 | 535 | ||
@@ -606,7 +612,10 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
606 | ", | 612 | ", |
607 | ); | 613 | ); |
608 | let hover = analysis.hover(position).unwrap().unwrap(); | 614 | let hover = analysis.hover(position).unwrap().unwrap(); |
609 | assert_eq!(trim_markup_opt(hover.info.first()), Some("wrapper::Thing\nfn new() -> Thing")); | 615 | assert_eq!( |
616 | trim_markup_opt(hover.info.first()), | ||
617 | Some("wrapper::Thing\n___\n\n```rust\nfn new() -> Thing") | ||
618 | ); | ||
610 | } | 619 | } |
611 | 620 | ||
612 | #[test] | 621 | #[test] |
diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs index d3af780c4..af1ade8a1 100644 --- a/crates/ra_ide/src/join_lines.rs +++ b/crates/ra_ide/src/join_lines.rs | |||
@@ -166,16 +166,28 @@ fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | |||
166 | 166 | ||
167 | #[cfg(test)] | 167 | #[cfg(test)] |
168 | mod tests { | 168 | mod tests { |
169 | use crate::test_utils::{assert_eq_text, check_action, extract_range}; | 169 | use ra_syntax::SourceFile; |
170 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; | ||
170 | 171 | ||
171 | use super::*; | 172 | use super::*; |
172 | 173 | ||
173 | fn check_join_lines(before: &str, after: &str) { | 174 | fn check_join_lines(before: &str, after: &str) { |
174 | check_action(before, after, |file, offset| { | 175 | let (before_cursor_pos, before) = extract_offset(before); |
175 | let range = TextRange::empty(offset); | 176 | let file = SourceFile::parse(&before).ok().unwrap(); |
176 | let res = join_lines(file, range); | 177 | |
177 | Some(res) | 178 | let range = TextRange::empty(before_cursor_pos); |
178 | }) | 179 | let result = join_lines(&file, range); |
180 | |||
181 | let actual = { | ||
182 | let mut actual = before.to_string(); | ||
183 | result.apply(&mut actual); | ||
184 | actual | ||
185 | }; | ||
186 | let actual_cursor_pos = result | ||
187 | .apply_to_offset(before_cursor_pos) | ||
188 | .expect("cursor position is affected by the edit"); | ||
189 | let actual = add_cursor(&actual, actual_cursor_pos); | ||
190 | assert_eq_text!(after, &actual); | ||
179 | } | 191 | } |
180 | 192 | ||
181 | #[test] | 193 | #[test] |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 66125f2f5..5ac002d82 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -42,11 +42,6 @@ mod inlay_hints; | |||
42 | mod expand_macro; | 42 | mod expand_macro; |
43 | mod ssr; | 43 | mod ssr; |
44 | 44 | ||
45 | #[cfg(test)] | ||
46 | mod marks; | ||
47 | #[cfg(test)] | ||
48 | mod test_utils; | ||
49 | |||
50 | use std::sync::Arc; | 45 | use std::sync::Arc; |
51 | 46 | ||
52 | use ra_cfg::CfgOptions; | 47 | use ra_cfg::CfgOptions; |
@@ -89,12 +84,12 @@ pub use ra_db::{ | |||
89 | pub use ra_ide_db::{ | 84 | pub use ra_ide_db::{ |
90 | change::{AnalysisChange, LibraryData}, | 85 | change::{AnalysisChange, LibraryData}, |
91 | line_index::{LineCol, LineIndex}, | 86 | line_index::{LineCol, LineIndex}, |
92 | line_index_utils::translate_offset_with_edit, | ||
93 | search::SearchScope, | 87 | search::SearchScope, |
94 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, | 88 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
95 | symbol_index::Query, | 89 | symbol_index::Query, |
96 | RootDatabase, | 90 | RootDatabase, |
97 | }; | 91 | }; |
92 | pub use ra_text_edit::{Indel, TextEdit}; | ||
98 | 93 | ||
99 | pub type Cancelable<T> = Result<T, Canceled>; | 94 | pub type Cancelable<T> = Result<T, Canceled>; |
100 | 95 | ||
@@ -102,8 +97,22 @@ pub type Cancelable<T> = Result<T, Canceled>; | |||
102 | pub struct Diagnostic { | 97 | pub struct Diagnostic { |
103 | pub message: String, | 98 | pub message: String, |
104 | pub range: TextRange, | 99 | pub range: TextRange, |
105 | pub fix: Option<SourceChange>, | ||
106 | pub severity: Severity, | 100 | pub severity: Severity, |
101 | pub fix: Option<Fix>, | ||
102 | } | ||
103 | |||
104 | #[derive(Debug)] | ||
105 | pub struct Fix { | ||
106 | pub label: String, | ||
107 | pub source_change: SourceChange, | ||
108 | } | ||
109 | |||
110 | impl Fix { | ||
111 | pub fn new(label: impl Into<String>, source_change: SourceChange) -> Self { | ||
112 | let label = label.into(); | ||
113 | assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.')); | ||
114 | Self { label, source_change } | ||
115 | } | ||
107 | } | 116 | } |
108 | 117 | ||
109 | /// Info associated with a text range. | 118 | /// Info associated with a text range. |
@@ -291,14 +300,10 @@ impl Analysis { | |||
291 | 300 | ||
292 | /// Returns an edit to remove all newlines in the range, cleaning up minor | 301 | /// Returns an edit to remove all newlines in the range, cleaning up minor |
293 | /// stuff like trailing commas. | 302 | /// stuff like trailing commas. |
294 | pub fn join_lines(&self, frange: FileRange) -> Cancelable<SourceChange> { | 303 | pub fn join_lines(&self, frange: FileRange) -> Cancelable<TextEdit> { |
295 | self.with_db(|db| { | 304 | self.with_db(|db| { |
296 | let parse = db.parse(frange.file_id); | 305 | let parse = db.parse(frange.file_id); |
297 | let file_edit = SourceFileEdit { | 306 | join_lines::join_lines(&parse.tree(), frange.range) |
298 | file_id: frange.file_id, | ||
299 | edit: join_lines::join_lines(&parse.tree(), frange.range), | ||
300 | }; | ||
301 | SourceChange::source_file_edit("Join lines", file_edit) | ||
302 | }) | 307 | }) |
303 | } | 308 | } |
304 | 309 | ||
@@ -502,7 +507,7 @@ impl Analysis { | |||
502 | ) -> Cancelable<Result<SourceChange, SsrError>> { | 507 | ) -> Cancelable<Result<SourceChange, SsrError>> { |
503 | self.with_db(|db| { | 508 | self.with_db(|db| { |
504 | let edits = ssr::parse_search_replace(query, parse_only, db)?; | 509 | let edits = ssr::parse_search_replace(query, parse_only, db)?; |
505 | Ok(SourceChange::source_file_edits("Structural Search Replace", edits)) | 510 | Ok(SourceChange::source_file_edits(edits)) |
506 | }) | 511 | }) |
507 | } | 512 | } |
508 | 513 | ||
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs deleted file mode 100644 index 51ca4dde3..000000000 --- a/crates/ra_ide/src/marks.rs +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | //! See test_utils/src/marks.rs | ||
2 | |||
3 | test_utils::marks!( | ||
4 | inserts_angle_brackets_for_generics | ||
5 | inserts_parens_for_function_calls | ||
6 | call_info_bad_offset | ||
7 | dont_complete_current_use | ||
8 | test_resolve_parent_module_on_module_decl | ||
9 | search_filters_by_range | ||
10 | dont_insert_macro_call_parens_unncessary | ||
11 | self_fulfilling_completion | ||
12 | test_struct_field_completion_in_func_call | ||
13 | test_struct_field_completion_in_record_lit | ||
14 | test_rename_struct_field_for_shorthand | ||
15 | test_rename_local_for_field_shorthand | ||
16 | ); | ||
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs index aaf4460df..a083fb1eb 100644 --- a/crates/ra_ide/src/parent_module.rs +++ b/crates/ra_ide/src/parent_module.rs | |||
@@ -7,7 +7,7 @@ use ra_syntax::{ | |||
7 | algo::find_node_at_offset, | 7 | algo::find_node_at_offset, |
8 | ast::{self, AstNode}, | 8 | ast::{self, AstNode}, |
9 | }; | 9 | }; |
10 | use test_utils::tested_by; | 10 | use test_utils::mark; |
11 | 11 | ||
12 | use crate::NavigationTarget; | 12 | use crate::NavigationTarget; |
13 | 13 | ||
@@ -25,7 +25,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na | |||
25 | .item_list() | 25 | .item_list() |
26 | .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset)) | 26 | .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset)) |
27 | { | 27 | { |
28 | tested_by!(test_resolve_parent_module_on_module_decl); | 28 | mark::hit!(test_resolve_parent_module_on_module_decl); |
29 | module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); | 29 | module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); |
30 | } | 30 | } |
31 | } | 31 | } |
@@ -57,7 +57,7 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { | |||
57 | mod tests { | 57 | mod tests { |
58 | use ra_cfg::CfgOptions; | 58 | use ra_cfg::CfgOptions; |
59 | use ra_db::Env; | 59 | use ra_db::Env; |
60 | use test_utils::covers; | 60 | use test_utils::mark; |
61 | 61 | ||
62 | use crate::{ | 62 | use crate::{ |
63 | mock_analysis::{analysis_and_position, MockAnalysis}, | 63 | mock_analysis::{analysis_and_position, MockAnalysis}, |
@@ -81,7 +81,7 @@ mod tests { | |||
81 | 81 | ||
82 | #[test] | 82 | #[test] |
83 | fn test_resolve_parent_module_on_module_decl() { | 83 | fn test_resolve_parent_module_on_module_decl() { |
84 | covers!(test_resolve_parent_module_on_module_decl); | 84 | mark::check!(test_resolve_parent_module_on_module_decl); |
85 | let (analysis, pos) = analysis_and_position( | 85 | let (analysis, pos) = analysis_and_position( |
86 | " | 86 | " |
87 | //- /lib.rs | 87 | //- /lib.rs |
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 074284b42..96444bf6a 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -190,8 +190,6 @@ fn get_struct_def_name_for_struct_literal_search( | |||
190 | 190 | ||
191 | #[cfg(test)] | 191 | #[cfg(test)] |
192 | mod tests { | 192 | mod tests { |
193 | use test_utils::covers; | ||
194 | |||
195 | use crate::{ | 193 | use crate::{ |
196 | mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis}, | 194 | mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis}, |
197 | Declaration, Reference, ReferenceSearchResult, SearchScope, | 195 | Declaration, Reference, ReferenceSearchResult, SearchScope, |
@@ -301,7 +299,6 @@ mod tests { | |||
301 | 299 | ||
302 | #[test] | 300 | #[test] |
303 | fn search_filters_by_range() { | 301 | fn search_filters_by_range() { |
304 | covers!(ra_ide_db::search_filters_by_range); | ||
305 | let code = r#" | 302 | let code = r#" |
306 | fn foo() { | 303 | fn foo() { |
307 | let spam<|> = 92; | 304 | let spam<|> = 92; |
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index 68a53ad4b..28c6349b1 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | }; | 9 | }; |
10 | use ra_text_edit::TextEdit; | 10 | use ra_text_edit::TextEdit; |
11 | use std::convert::TryInto; | 11 | use std::convert::TryInto; |
12 | use test_utils::tested_by; | 12 | use test_utils::mark; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, | 15 | references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, |
@@ -57,13 +57,13 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil | |||
57 | let file_id = reference.file_range.file_id; | 57 | let file_id = reference.file_range.file_id; |
58 | let range = match reference.kind { | 58 | let range = match reference.kind { |
59 | ReferenceKind::FieldShorthandForField => { | 59 | ReferenceKind::FieldShorthandForField => { |
60 | tested_by!(test_rename_struct_field_for_shorthand); | 60 | mark::hit!(test_rename_struct_field_for_shorthand); |
61 | replacement_text.push_str(new_name); | 61 | replacement_text.push_str(new_name); |
62 | replacement_text.push_str(": "); | 62 | replacement_text.push_str(": "); |
63 | TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) | 63 | TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) |
64 | } | 64 | } |
65 | ReferenceKind::FieldShorthandForLocal => { | 65 | ReferenceKind::FieldShorthandForLocal => { |
66 | tested_by!(test_rename_local_for_field_shorthand); | 66 | mark::hit!(test_rename_local_for_field_shorthand); |
67 | replacement_text.push_str(": "); | 67 | replacement_text.push_str(": "); |
68 | replacement_text.push_str(new_name); | 68 | replacement_text.push_str(new_name); |
69 | TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) | 69 | TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) |
@@ -128,7 +128,7 @@ fn rename_mod( | |||
128 | source_file_edits.extend(ref_edits); | 128 | source_file_edits.extend(ref_edits); |
129 | } | 129 | } |
130 | 130 | ||
131 | Some(SourceChange::from_edits("Rename", source_file_edits, file_system_edits)) | 131 | Some(SourceChange::from_edits(source_file_edits, file_system_edits)) |
132 | } | 132 | } |
133 | 133 | ||
134 | fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> { | 134 | fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> { |
@@ -171,7 +171,7 @@ fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo | |||
171 | ), | 171 | ), |
172 | }); | 172 | }); |
173 | 173 | ||
174 | Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edits))) | 174 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edits))) |
175 | } | 175 | } |
176 | 176 | ||
177 | fn text_edit_from_self_param( | 177 | fn text_edit_from_self_param( |
@@ -234,7 +234,7 @@ fn rename_self_to_param( | |||
234 | let range = ast::SelfParam::cast(self_token.parent()) | 234 | let range = ast::SelfParam::cast(self_token.parent()) |
235 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); | 235 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); |
236 | 236 | ||
237 | Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edits))) | 237 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edits))) |
238 | } | 238 | } |
239 | 239 | ||
240 | fn rename_reference( | 240 | fn rename_reference( |
@@ -253,14 +253,14 @@ fn rename_reference( | |||
253 | return None; | 253 | return None; |
254 | } | 254 | } |
255 | 255 | ||
256 | Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edit))) | 256 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edit))) |
257 | } | 257 | } |
258 | 258 | ||
259 | #[cfg(test)] | 259 | #[cfg(test)] |
260 | mod tests { | 260 | mod tests { |
261 | use insta::assert_debug_snapshot; | 261 | use insta::assert_debug_snapshot; |
262 | use ra_text_edit::TextEditBuilder; | 262 | use ra_text_edit::TextEditBuilder; |
263 | use test_utils::{assert_eq_text, covers}; | 263 | use test_utils::{assert_eq_text, mark}; |
264 | 264 | ||
265 | use crate::{ | 265 | use crate::{ |
266 | mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, | 266 | mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, |
@@ -492,7 +492,7 @@ mod tests { | |||
492 | 492 | ||
493 | #[test] | 493 | #[test] |
494 | fn test_rename_struct_field_for_shorthand() { | 494 | fn test_rename_struct_field_for_shorthand() { |
495 | covers!(test_rename_struct_field_for_shorthand); | 495 | mark::check!(test_rename_struct_field_for_shorthand); |
496 | test_rename( | 496 | test_rename( |
497 | r#" | 497 | r#" |
498 | struct Foo { | 498 | struct Foo { |
@@ -522,7 +522,7 @@ mod tests { | |||
522 | 522 | ||
523 | #[test] | 523 | #[test] |
524 | fn test_rename_local_for_field_shorthand() { | 524 | fn test_rename_local_for_field_shorthand() { |
525 | covers!(test_rename_local_for_field_shorthand); | 525 | mark::check!(test_rename_local_for_field_shorthand); |
526 | test_rename( | 526 | test_rename( |
527 | r#" | 527 | r#" |
528 | struct Foo { | 528 | struct Foo { |
@@ -642,7 +642,6 @@ mod tests { | |||
642 | RangeInfo { | 642 | RangeInfo { |
643 | range: 4..7, | 643 | range: 4..7, |
644 | info: SourceChange { | 644 | info: SourceChange { |
645 | label: "Rename", | ||
646 | source_file_edits: [ | 645 | source_file_edits: [ |
647 | SourceFileEdit { | 646 | SourceFileEdit { |
648 | file_id: FileId( | 647 | file_id: FileId( |
@@ -669,7 +668,6 @@ mod tests { | |||
669 | dst_path: "bar/foo2.rs", | 668 | dst_path: "bar/foo2.rs", |
670 | }, | 669 | }, |
671 | ], | 670 | ], |
672 | cursor_position: None, | ||
673 | is_snippet: false, | 671 | is_snippet: false, |
674 | }, | 672 | }, |
675 | }, | 673 | }, |
@@ -695,7 +693,6 @@ mod tests { | |||
695 | RangeInfo { | 693 | RangeInfo { |
696 | range: 4..7, | 694 | range: 4..7, |
697 | info: SourceChange { | 695 | info: SourceChange { |
698 | label: "Rename", | ||
699 | source_file_edits: [ | 696 | source_file_edits: [ |
700 | SourceFileEdit { | 697 | SourceFileEdit { |
701 | file_id: FileId( | 698 | file_id: FileId( |
@@ -722,7 +719,6 @@ mod tests { | |||
722 | dst_path: "foo2/mod.rs", | 719 | dst_path: "foo2/mod.rs", |
723 | }, | 720 | }, |
724 | ], | 721 | ], |
725 | cursor_position: None, | ||
726 | is_snippet: false, | 722 | is_snippet: false, |
727 | }, | 723 | }, |
728 | }, | 724 | }, |
@@ -779,7 +775,6 @@ mod tests { | |||
779 | RangeInfo { | 775 | RangeInfo { |
780 | range: 8..11, | 776 | range: 8..11, |
781 | info: SourceChange { | 777 | info: SourceChange { |
782 | label: "Rename", | ||
783 | source_file_edits: [ | 778 | source_file_edits: [ |
784 | SourceFileEdit { | 779 | SourceFileEdit { |
785 | file_id: FileId( | 780 | file_id: FileId( |
@@ -819,7 +814,6 @@ mod tests { | |||
819 | dst_path: "bar/foo2.rs", | 814 | dst_path: "bar/foo2.rs", |
820 | }, | 815 | }, |
821 | ], | 816 | ], |
822 | cursor_position: None, | ||
823 | is_snippet: false, | 817 | is_snippet: false, |
824 | }, | 818 | }, |
825 | }, | 819 | }, |
@@ -986,8 +980,8 @@ mod tests { | |||
986 | if let Some(change) = source_change { | 980 | if let Some(change) = source_change { |
987 | for edit in change.info.source_file_edits { | 981 | for edit in change.info.source_file_edits { |
988 | file_id = Some(edit.file_id); | 982 | file_id = Some(edit.file_id); |
989 | for indel in edit.edit.as_indels() { | 983 | for indel in edit.edit.into_iter() { |
990 | text_edit_builder.replace(indel.delete, indel.insert.clone()); | 984 | text_edit_builder.replace(indel.delete, indel.insert); |
991 | } | 985 | } |
992 | } | 986 | } |
993 | } | 987 | } |
diff --git a/crates/ra_ide/src/test_utils.rs b/crates/ra_ide/src/test_utils.rs deleted file mode 100644 index 48c8fd1f4..000000000 --- a/crates/ra_ide/src/test_utils.rs +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use ra_syntax::{SourceFile, TextSize}; | ||
4 | use ra_text_edit::TextEdit; | ||
5 | |||
6 | pub use test_utils::*; | ||
7 | |||
8 | pub fn check_action<F: Fn(&SourceFile, TextSize) -> Option<TextEdit>>( | ||
9 | before: &str, | ||
10 | after: &str, | ||
11 | f: F, | ||
12 | ) { | ||
13 | let (before_cursor_pos, before) = extract_offset(before); | ||
14 | let file = SourceFile::parse(&before).ok().unwrap(); | ||
15 | let result = f(&file, before_cursor_pos).expect("code action is not applicable"); | ||
16 | let actual = { | ||
17 | let mut actual = before.to_string(); | ||
18 | result.apply(&mut actual); | ||
19 | actual | ||
20 | }; | ||
21 | let actual_cursor_pos = | ||
22 | result.apply_to_offset(before_cursor_pos).expect("cursor position is affected by the edit"); | ||
23 | let actual = add_cursor(&actual, actual_cursor_pos); | ||
24 | assert_eq_text!(after, &actual); | ||
25 | } | ||
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 6f04f0be4..39bb3b357 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -17,7 +17,7 @@ mod on_enter; | |||
17 | 17 | ||
18 | use ra_db::{FilePosition, SourceDatabase}; | 18 | use ra_db::{FilePosition, SourceDatabase}; |
19 | use ra_fmt::leading_indent; | 19 | use ra_fmt::leading_indent; |
20 | use ra_ide_db::{source_change::SingleFileChange, RootDatabase}; | 20 | use ra_ide_db::RootDatabase; |
21 | use ra_syntax::{ | 21 | use ra_syntax::{ |
22 | algo::find_node_at_offset, | 22 | algo::find_node_at_offset, |
23 | ast::{self, AstToken}, | 23 | ast::{self, AstToken}, |
@@ -40,15 +40,11 @@ pub(crate) fn on_char_typed( | |||
40 | assert!(TRIGGER_CHARS.contains(char_typed)); | 40 | assert!(TRIGGER_CHARS.contains(char_typed)); |
41 | let file = &db.parse(position.file_id).tree(); | 41 | let file = &db.parse(position.file_id).tree(); |
42 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); | 42 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); |
43 | let single_file_change = on_char_typed_inner(file, position.offset, char_typed)?; | 43 | let text_edit = on_char_typed_inner(file, position.offset, char_typed)?; |
44 | Some(single_file_change.into_source_change(position.file_id)) | 44 | Some(SourceChange::source_file_edit_from(position.file_id, text_edit)) |
45 | } | 45 | } |
46 | 46 | ||
47 | fn on_char_typed_inner( | 47 | fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { |
48 | file: &SourceFile, | ||
49 | offset: TextSize, | ||
50 | char_typed: char, | ||
51 | ) -> Option<SingleFileChange> { | ||
52 | assert!(TRIGGER_CHARS.contains(char_typed)); | 48 | assert!(TRIGGER_CHARS.contains(char_typed)); |
53 | match char_typed { | 49 | match char_typed { |
54 | '.' => on_dot_typed(file, offset), | 50 | '.' => on_dot_typed(file, offset), |
@@ -61,7 +57,7 @@ fn on_char_typed_inner( | |||
61 | /// Returns an edit which should be applied after `=` was typed. Primarily, | 57 | /// Returns an edit which should be applied after `=` was typed. Primarily, |
62 | /// this works when adding `let =`. | 58 | /// this works when adding `let =`. |
63 | // FIXME: use a snippet completion instead of this hack here. | 59 | // FIXME: use a snippet completion instead of this hack here. |
64 | fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> { | 60 | fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
65 | assert_eq!(file.syntax().text().char_at(offset), Some('=')); | 61 | assert_eq!(file.syntax().text().char_at(offset), Some('=')); |
66 | let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; | 62 | let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; |
67 | if let_stmt.semicolon_token().is_some() { | 63 | if let_stmt.semicolon_token().is_some() { |
@@ -79,15 +75,11 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> | |||
79 | return None; | 75 | return None; |
80 | } | 76 | } |
81 | let offset = let_stmt.syntax().text_range().end(); | 77 | let offset = let_stmt.syntax().text_range().end(); |
82 | Some(SingleFileChange { | 78 | Some(TextEdit::insert(offset, ";".to_string())) |
83 | label: "add semicolon".to_string(), | ||
84 | edit: TextEdit::insert(offset, ";".to_string()), | ||
85 | cursor_position: None, | ||
86 | }) | ||
87 | } | 79 | } |
88 | 80 | ||
89 | /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. | 81 | /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. |
90 | fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> { | 82 | fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
91 | assert_eq!(file.syntax().text().char_at(offset), Some('.')); | 83 | assert_eq!(file.syntax().text().char_at(offset), Some('.')); |
92 | let whitespace = | 84 | let whitespace = |
93 | file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; | 85 | file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; |
@@ -108,15 +100,11 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> | |||
108 | return None; | 100 | return None; |
109 | } | 101 | } |
110 | 102 | ||
111 | Some(SingleFileChange { | 103 | Some(TextEdit::replace(TextRange::new(offset - current_indent_len, offset), target_indent)) |
112 | label: "reindent dot".to_string(), | ||
113 | edit: TextEdit::replace(TextRange::new(offset - current_indent_len, offset), target_indent), | ||
114 | cursor_position: Some(offset + target_indent_len - current_indent_len + TextSize::of('.')), | ||
115 | }) | ||
116 | } | 104 | } |
117 | 105 | ||
118 | /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` | 106 | /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` |
119 | fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> { | 107 | fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
120 | let file_text = file.syntax().text(); | 108 | let file_text = file.syntax().text(); |
121 | assert_eq!(file_text.char_at(offset), Some('>')); | 109 | assert_eq!(file_text.char_at(offset), Some('>')); |
122 | let after_arrow = offset + TextSize::of('>'); | 110 | let after_arrow = offset + TextSize::of('>'); |
@@ -127,11 +115,7 @@ fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChang | |||
127 | return None; | 115 | return None; |
128 | } | 116 | } |
129 | 117 | ||
130 | Some(SingleFileChange { | 118 | Some(TextEdit::insert(after_arrow, " ".to_string())) |
131 | label: "add space after return type".to_string(), | ||
132 | edit: TextEdit::insert(after_arrow, " ".to_string()), | ||
133 | cursor_position: Some(after_arrow), | ||
134 | }) | ||
135 | } | 119 | } |
136 | 120 | ||
137 | #[cfg(test)] | 121 | #[cfg(test)] |
@@ -140,29 +124,23 @@ mod tests { | |||
140 | 124 | ||
141 | use super::*; | 125 | use super::*; |
142 | 126 | ||
143 | fn do_type_char(char_typed: char, before: &str) -> Option<(String, SingleFileChange)> { | 127 | fn do_type_char(char_typed: char, before: &str) -> Option<String> { |
144 | let (offset, before) = extract_offset(before); | 128 | let (offset, before) = extract_offset(before); |
145 | let edit = TextEdit::insert(offset, char_typed.to_string()); | 129 | let edit = TextEdit::insert(offset, char_typed.to_string()); |
146 | let mut before = before.to_string(); | 130 | let mut before = before.to_string(); |
147 | edit.apply(&mut before); | 131 | edit.apply(&mut before); |
148 | let parse = SourceFile::parse(&before); | 132 | let parse = SourceFile::parse(&before); |
149 | on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { | 133 | on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { |
150 | it.edit.apply(&mut before); | 134 | it.apply(&mut before); |
151 | (before.to_string(), it) | 135 | before.to_string() |
152 | }) | 136 | }) |
153 | } | 137 | } |
154 | 138 | ||
155 | fn type_char(char_typed: char, before: &str, after: &str) { | 139 | fn type_char(char_typed: char, before: &str, after: &str) { |
156 | let (actual, file_change) = do_type_char(char_typed, before) | 140 | let actual = do_type_char(char_typed, before) |
157 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); | 141 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); |
158 | 142 | ||
159 | if after.contains("<|>") { | 143 | assert_eq_text!(after, &actual); |
160 | let (offset, after) = extract_offset(after); | ||
161 | assert_eq_text!(&after, &actual); | ||
162 | assert_eq!(file_change.cursor_position, Some(offset)) | ||
163 | } else { | ||
164 | assert_eq_text!(after, &actual); | ||
165 | } | ||
166 | } | 144 | } |
167 | 145 | ||
168 | fn type_char_noop(char_typed: char, before: &str) { | 146 | fn type_char_noop(char_typed: char, before: &str) { |
@@ -350,6 +328,6 @@ fn foo() { | |||
350 | 328 | ||
351 | #[test] | 329 | #[test] |
352 | fn adds_space_after_return_type() { | 330 | fn adds_space_after_return_type() { |
353 | type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -><|> { 92 }") | 331 | type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -> { 92 }") |
354 | } | 332 | } |
355 | } | 333 | } |
diff --git a/crates/ra_ide/src/typing/on_enter.rs b/crates/ra_ide/src/typing/on_enter.rs index 78a40cc94..e7d64b4f6 100644 --- a/crates/ra_ide/src/typing/on_enter.rs +++ b/crates/ra_ide/src/typing/on_enter.rs | |||
@@ -38,17 +38,12 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour | |||
38 | } | 38 | } |
39 | 39 | ||
40 | let indent = node_indent(&file, comment.syntax())?; | 40 | let indent = node_indent(&file, comment.syntax())?; |
41 | let inserted = format!("\n{}{} ", indent, prefix); | 41 | let inserted = format!("\n{}{} $0", indent, prefix); |
42 | let cursor_position = position.offset + TextSize::of(&inserted); | ||
43 | let edit = TextEdit::insert(position.offset, inserted); | 42 | let edit = TextEdit::insert(position.offset, inserted); |
44 | 43 | ||
45 | Some( | 44 | let mut res = SourceChange::from(SourceFileEdit { edit, file_id: position.file_id }); |
46 | SourceChange::source_file_edit( | 45 | res.is_snippet = true; |
47 | "On enter", | 46 | Some(res) |
48 | SourceFileEdit { edit, file_id: position.file_id }, | ||
49 | ) | ||
50 | .with_cursor(FilePosition { offset: cursor_position, file_id: position.file_id }), | ||
51 | ) | ||
52 | } | 47 | } |
53 | 48 | ||
54 | fn followed_by_comment(comment: &ast::Comment) -> bool { | 49 | fn followed_by_comment(comment: &ast::Comment) -> bool { |
@@ -84,7 +79,7 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> { | |||
84 | 79 | ||
85 | #[cfg(test)] | 80 | #[cfg(test)] |
86 | mod tests { | 81 | mod tests { |
87 | use test_utils::{add_cursor, assert_eq_text, extract_offset}; | 82 | use test_utils::{assert_eq_text, extract_offset}; |
88 | 83 | ||
89 | use crate::mock_analysis::single_file; | 84 | use crate::mock_analysis::single_file; |
90 | 85 | ||
@@ -98,7 +93,6 @@ mod tests { | |||
98 | assert_eq!(result.source_file_edits.len(), 1); | 93 | assert_eq!(result.source_file_edits.len(), 1); |
99 | let mut actual = before.to_string(); | 94 | let mut actual = before.to_string(); |
100 | result.source_file_edits[0].edit.apply(&mut actual); | 95 | result.source_file_edits[0].edit.apply(&mut actual); |
101 | let actual = add_cursor(&actual, result.cursor_position.unwrap().offset); | ||
102 | Some(actual) | 96 | Some(actual) |
103 | } | 97 | } |
104 | 98 | ||
@@ -121,7 +115,7 @@ fn foo() { | |||
121 | ", | 115 | ", |
122 | r" | 116 | r" |
123 | /// Some docs | 117 | /// Some docs |
124 | /// <|> | 118 | /// $0 |
125 | fn foo() { | 119 | fn foo() { |
126 | } | 120 | } |
127 | ", | 121 | ", |
@@ -137,7 +131,7 @@ impl S { | |||
137 | r" | 131 | r" |
138 | impl S { | 132 | impl S { |
139 | /// Some | 133 | /// Some |
140 | /// <|> docs. | 134 | /// $0 docs. |
141 | fn foo() {} | 135 | fn foo() {} |
142 | } | 136 | } |
143 | ", | 137 | ", |
@@ -151,7 +145,7 @@ fn foo() { | |||
151 | ", | 145 | ", |
152 | r" | 146 | r" |
153 | /// | 147 | /// |
154 | /// <|> Some docs | 148 | /// $0 Some docs |
155 | fn foo() { | 149 | fn foo() { |
156 | } | 150 | } |
157 | ", | 151 | ", |
@@ -175,7 +169,7 @@ fn main() { | |||
175 | r" | 169 | r" |
176 | fn main() { | 170 | fn main() { |
177 | // Fix | 171 | // Fix |
178 | // <|> me | 172 | // $0 me |
179 | let x = 1 + 1; | 173 | let x = 1 + 1; |
180 | } | 174 | } |
181 | ", | 175 | ", |
@@ -195,7 +189,7 @@ fn main() { | |||
195 | r" | 189 | r" |
196 | fn main() { | 190 | fn main() { |
197 | // Fix | 191 | // Fix |
198 | // <|> | 192 | // $0 |
199 | // me | 193 | // me |
200 | let x = 1 + 1; | 194 | let x = 1 + 1; |
201 | } | 195 | } |
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 60c11178e..8b06cbfc5 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -14,7 +14,6 @@ use ra_syntax::{ | |||
14 | ast::{self, AstNode}, | 14 | ast::{self, AstNode}, |
15 | match_ast, | 15 | match_ast, |
16 | }; | 16 | }; |
17 | use test_utils::tested_by; | ||
18 | 17 | ||
19 | use crate::RootDatabase; | 18 | use crate::RootDatabase; |
20 | 19 | ||
@@ -118,7 +117,6 @@ fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Opti | |||
118 | match_ast! { | 117 | match_ast! { |
119 | match parent { | 118 | match parent { |
120 | ast::Alias(it) => { | 119 | ast::Alias(it) => { |
121 | tested_by!(goto_def_for_use_alias; force); | ||
122 | let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?; | 120 | let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?; |
123 | let path = use_tree.path()?; | 121 | let path = use_tree.path()?; |
124 | let path_segment = path.segment()?; | 122 | let path_segment = path.segment()?; |
@@ -203,6 +201,8 @@ impl NameRefClass { | |||
203 | } | 201 | } |
204 | } | 202 | } |
205 | 203 | ||
204 | // Note: we don't have unit-tests for this rather important function. | ||
205 | // It is primarily exercised via goto definition tests in `ra_ide`. | ||
206 | pub fn classify_name_ref( | 206 | pub fn classify_name_ref( |
207 | sema: &Semantics<RootDatabase>, | 207 | sema: &Semantics<RootDatabase>, |
208 | name_ref: &ast::NameRef, | 208 | name_ref: &ast::NameRef, |
@@ -212,22 +212,18 @@ pub fn classify_name_ref( | |||
212 | let parent = name_ref.syntax().parent()?; | 212 | let parent = name_ref.syntax().parent()?; |
213 | 213 | ||
214 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | 214 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { |
215 | tested_by!(goto_def_for_methods; force); | ||
216 | if let Some(func) = sema.resolve_method_call(&method_call) { | 215 | if let Some(func) = sema.resolve_method_call(&method_call) { |
217 | return Some(NameRefClass::Definition(Definition::ModuleDef(func.into()))); | 216 | return Some(NameRefClass::Definition(Definition::ModuleDef(func.into()))); |
218 | } | 217 | } |
219 | } | 218 | } |
220 | 219 | ||
221 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | 220 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { |
222 | tested_by!(goto_def_for_fields; force); | ||
223 | if let Some(field) = sema.resolve_field(&field_expr) { | 221 | if let Some(field) = sema.resolve_field(&field_expr) { |
224 | return Some(NameRefClass::Definition(Definition::Field(field))); | 222 | return Some(NameRefClass::Definition(Definition::Field(field))); |
225 | } | 223 | } |
226 | } | 224 | } |
227 | 225 | ||
228 | if let Some(record_field) = ast::RecordField::for_field_name(name_ref) { | 226 | if let Some(record_field) = ast::RecordField::for_field_name(name_ref) { |
229 | tested_by!(goto_def_for_record_fields; force); | ||
230 | tested_by!(goto_def_for_field_init_shorthand; force); | ||
231 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { | 227 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { |
232 | let field = Definition::Field(field); | 228 | let field = Definition::Field(field); |
233 | let res = match local { | 229 | let res = match local { |
@@ -239,7 +235,6 @@ pub fn classify_name_ref( | |||
239 | } | 235 | } |
240 | 236 | ||
241 | if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) { | 237 | if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) { |
242 | tested_by!(goto_def_for_record_field_pats; force); | ||
243 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { | 238 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { |
244 | let field = Definition::Field(field); | 239 | let field = Definition::Field(field); |
245 | return Some(NameRefClass::Definition(field)); | 240 | return Some(NameRefClass::Definition(field)); |
@@ -247,7 +242,6 @@ pub fn classify_name_ref( | |||
247 | } | 242 | } |
248 | 243 | ||
249 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { | 244 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { |
250 | tested_by!(goto_def_for_macros; force); | ||
251 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { | 245 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { |
252 | return Some(NameRefClass::Definition(Definition::Macro(macro_def))); | 246 | return Some(NameRefClass::Definition(Definition::Macro(macro_def))); |
253 | } | 247 | } |
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 52fcd7b6f..1b74e6558 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -2,9 +2,7 @@ | |||
2 | //! | 2 | //! |
3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. | 3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. |
4 | 4 | ||
5 | pub mod marks; | ||
6 | pub mod line_index; | 5 | pub mod line_index; |
7 | pub mod line_index_utils; | ||
8 | pub mod symbol_index; | 6 | pub mod symbol_index; |
9 | pub mod change; | 7 | pub mod change; |
10 | pub mod defs; | 8 | pub mod defs; |
diff --git a/crates/ra_ide_db/src/line_index_utils.rs b/crates/ra_ide_db/src/line_index_utils.rs deleted file mode 100644 index 7fa6fc448..000000000 --- a/crates/ra_ide_db/src/line_index_utils.rs +++ /dev/null | |||
@@ -1,302 +0,0 @@ | |||
1 | //! Code actions can specify desirable final position of the cursor. | ||
2 | //! | ||
3 | //! The position is specified as a `TextSize` in the final file. We need to send | ||
4 | //! it in `(Line, Column)` coordinate though. However, we only have a LineIndex | ||
5 | //! for a file pre-edit! | ||
6 | //! | ||
7 | //! Code in this module applies this "to (Line, Column) after edit" | ||
8 | //! transformation. | ||
9 | |||
10 | use std::convert::TryInto; | ||
11 | |||
12 | use ra_syntax::{TextRange, TextSize}; | ||
13 | use ra_text_edit::{Indel, TextEdit}; | ||
14 | |||
15 | use crate::line_index::{LineCol, LineIndex, Utf16Char}; | ||
16 | |||
17 | pub fn translate_offset_with_edit( | ||
18 | line_index: &LineIndex, | ||
19 | offset: TextSize, | ||
20 | text_edit: &TextEdit, | ||
21 | ) -> LineCol { | ||
22 | let mut state = Edits::from_text_edit(&text_edit); | ||
23 | |||
24 | let mut res = RunningLineCol::new(); | ||
25 | |||
26 | macro_rules! test_step { | ||
27 | ($x:ident) => { | ||
28 | match &$x { | ||
29 | Step::Newline(n) => { | ||
30 | if offset < *n { | ||
31 | return res.to_line_col(offset); | ||
32 | } else { | ||
33 | res.add_line(*n); | ||
34 | } | ||
35 | } | ||
36 | Step::Utf16Char(x) => { | ||
37 | if offset < x.end() { | ||
38 | // if the offset is inside a multibyte char it's invalid | ||
39 | // clamp it to the start of the char | ||
40 | let clamp = offset.min(x.start()); | ||
41 | return res.to_line_col(clamp); | ||
42 | } else { | ||
43 | res.adjust_col(*x); | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | }; | ||
48 | } | ||
49 | |||
50 | for orig_step in LineIndexStepIter::from(line_index) { | ||
51 | loop { | ||
52 | let translated_step = state.translate_step(&orig_step); | ||
53 | match state.next_steps(&translated_step) { | ||
54 | NextSteps::Use => { | ||
55 | test_step!(translated_step); | ||
56 | break; | ||
57 | } | ||
58 | NextSteps::ReplaceMany(ns) => { | ||
59 | for n in ns { | ||
60 | test_step!(n); | ||
61 | } | ||
62 | break; | ||
63 | } | ||
64 | NextSteps::AddMany(ns) => { | ||
65 | for n in ns { | ||
66 | test_step!(n); | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | loop { | ||
74 | match state.next_inserted_steps() { | ||
75 | None => break, | ||
76 | Some(ns) => { | ||
77 | for n in ns { | ||
78 | test_step!(n); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | res.to_line_col(offset) | ||
85 | } | ||
86 | |||
87 | #[derive(Debug, Clone)] | ||
88 | enum Step { | ||
89 | Newline(TextSize), | ||
90 | Utf16Char(TextRange), | ||
91 | } | ||
92 | |||
93 | #[derive(Debug)] | ||
94 | struct LineIndexStepIter<'a> { | ||
95 | line_index: &'a LineIndex, | ||
96 | next_newline_idx: usize, | ||
97 | utf16_chars: Option<(TextSize, std::slice::Iter<'a, Utf16Char>)>, | ||
98 | } | ||
99 | |||
100 | impl LineIndexStepIter<'_> { | ||
101 | fn from(line_index: &LineIndex) -> LineIndexStepIter { | ||
102 | let mut x = LineIndexStepIter { line_index, next_newline_idx: 0, utf16_chars: None }; | ||
103 | // skip first newline since it's not real | ||
104 | x.next(); | ||
105 | x | ||
106 | } | ||
107 | } | ||
108 | |||
109 | impl Iterator for LineIndexStepIter<'_> { | ||
110 | type Item = Step; | ||
111 | fn next(&mut self) -> Option<Step> { | ||
112 | self.utf16_chars | ||
113 | .as_mut() | ||
114 | .and_then(|(newline, x)| { | ||
115 | let x = x.next()?; | ||
116 | Some(Step::Utf16Char(TextRange::new(*newline + x.start, *newline + x.end))) | ||
117 | }) | ||
118 | .or_else(|| { | ||
119 | let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?; | ||
120 | self.utf16_chars = self | ||
121 | .line_index | ||
122 | .utf16_lines | ||
123 | .get(&(self.next_newline_idx as u32)) | ||
124 | .map(|x| (next_newline, x.iter())); | ||
125 | self.next_newline_idx += 1; | ||
126 | Some(Step::Newline(next_newline)) | ||
127 | }) | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #[derive(Debug)] | ||
132 | struct OffsetStepIter<'a> { | ||
133 | text: &'a str, | ||
134 | offset: TextSize, | ||
135 | } | ||
136 | |||
137 | impl Iterator for OffsetStepIter<'_> { | ||
138 | type Item = Step; | ||
139 | fn next(&mut self) -> Option<Step> { | ||
140 | let (next, next_offset) = self | ||
141 | .text | ||
142 | .char_indices() | ||
143 | .filter_map(|(i, c)| { | ||
144 | let i: TextSize = i.try_into().unwrap(); | ||
145 | let char_len = TextSize::of(c); | ||
146 | if c == '\n' { | ||
147 | let next_offset = self.offset + i + char_len; | ||
148 | let next = Step::Newline(next_offset); | ||
149 | Some((next, next_offset)) | ||
150 | } else { | ||
151 | if !c.is_ascii() { | ||
152 | let start = self.offset + i; | ||
153 | let end = start + char_len; | ||
154 | let next = Step::Utf16Char(TextRange::new(start, end)); | ||
155 | let next_offset = end; | ||
156 | Some((next, next_offset)) | ||
157 | } else { | ||
158 | None | ||
159 | } | ||
160 | } | ||
161 | }) | ||
162 | .next()?; | ||
163 | let next_idx: usize = (next_offset - self.offset).into(); | ||
164 | self.text = &self.text[next_idx..]; | ||
165 | self.offset = next_offset; | ||
166 | Some(next) | ||
167 | } | ||
168 | } | ||
169 | |||
170 | #[derive(Debug)] | ||
171 | enum NextSteps<'a> { | ||
172 | Use, | ||
173 | ReplaceMany(OffsetStepIter<'a>), | ||
174 | AddMany(OffsetStepIter<'a>), | ||
175 | } | ||
176 | |||
177 | #[derive(Debug)] | ||
178 | struct TranslatedEdit<'a> { | ||
179 | delete: TextRange, | ||
180 | insert: &'a str, | ||
181 | diff: i64, | ||
182 | } | ||
183 | |||
184 | struct Edits<'a> { | ||
185 | edits: &'a [Indel], | ||
186 | current: Option<TranslatedEdit<'a>>, | ||
187 | acc_diff: i64, | ||
188 | } | ||
189 | |||
190 | impl<'a> Edits<'a> { | ||
191 | fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> { | ||
192 | let mut x = Edits { edits: text_edit.as_indels(), current: None, acc_diff: 0 }; | ||
193 | x.advance_edit(); | ||
194 | x | ||
195 | } | ||
196 | fn advance_edit(&mut self) { | ||
197 | self.acc_diff += self.current.as_ref().map_or(0, |x| x.diff); | ||
198 | match self.edits.split_first() { | ||
199 | Some((next, rest)) => { | ||
200 | let delete = self.translate_range(next.delete); | ||
201 | let diff = next.insert.len() as i64 - usize::from(next.delete.len()) as i64; | ||
202 | self.current = Some(TranslatedEdit { delete, insert: &next.insert, diff }); | ||
203 | self.edits = rest; | ||
204 | } | ||
205 | None => { | ||
206 | self.current = None; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | fn next_inserted_steps(&mut self) -> Option<OffsetStepIter<'a>> { | ||
212 | let cur = self.current.as_ref()?; | ||
213 | let res = Some(OffsetStepIter { offset: cur.delete.start(), text: &cur.insert }); | ||
214 | self.advance_edit(); | ||
215 | res | ||
216 | } | ||
217 | |||
218 | fn next_steps(&mut self, step: &Step) -> NextSteps { | ||
219 | let step_pos = match *step { | ||
220 | Step::Newline(n) => n, | ||
221 | Step::Utf16Char(r) => r.end(), | ||
222 | }; | ||
223 | match &mut self.current { | ||
224 | Some(edit) => { | ||
225 | if step_pos <= edit.delete.start() { | ||
226 | NextSteps::Use | ||
227 | } else if step_pos <= edit.delete.end() { | ||
228 | let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert }; | ||
229 | // empty slice to avoid returning steps again | ||
230 | edit.insert = &edit.insert[edit.insert.len()..]; | ||
231 | NextSteps::ReplaceMany(iter) | ||
232 | } else { | ||
233 | let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert }; | ||
234 | // empty slice to avoid returning steps again | ||
235 | edit.insert = &edit.insert[edit.insert.len()..]; | ||
236 | self.advance_edit(); | ||
237 | NextSteps::AddMany(iter) | ||
238 | } | ||
239 | } | ||
240 | None => NextSteps::Use, | ||
241 | } | ||
242 | } | ||
243 | |||
244 | fn translate_range(&self, range: TextRange) -> TextRange { | ||
245 | if self.acc_diff == 0 { | ||
246 | range | ||
247 | } else { | ||
248 | let start = self.translate(range.start()); | ||
249 | let end = self.translate(range.end()); | ||
250 | TextRange::new(start, end) | ||
251 | } | ||
252 | } | ||
253 | |||
254 | fn translate(&self, x: TextSize) -> TextSize { | ||
255 | if self.acc_diff == 0 { | ||
256 | x | ||
257 | } else { | ||
258 | TextSize::from((usize::from(x) as i64 + self.acc_diff) as u32) | ||
259 | } | ||
260 | } | ||
261 | |||
262 | fn translate_step(&self, x: &Step) -> Step { | ||
263 | if self.acc_diff == 0 { | ||
264 | x.clone() | ||
265 | } else { | ||
266 | match *x { | ||
267 | Step::Newline(n) => Step::Newline(self.translate(n)), | ||
268 | Step::Utf16Char(r) => Step::Utf16Char(self.translate_range(r)), | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | #[derive(Debug)] | ||
275 | struct RunningLineCol { | ||
276 | line: u32, | ||
277 | last_newline: TextSize, | ||
278 | col_adjust: TextSize, | ||
279 | } | ||
280 | |||
281 | impl RunningLineCol { | ||
282 | fn new() -> RunningLineCol { | ||
283 | RunningLineCol { line: 0, last_newline: TextSize::from(0), col_adjust: TextSize::from(0) } | ||
284 | } | ||
285 | |||
286 | fn to_line_col(&self, offset: TextSize) -> LineCol { | ||
287 | LineCol { | ||
288 | line: self.line, | ||
289 | col_utf16: ((offset - self.last_newline) - self.col_adjust).into(), | ||
290 | } | ||
291 | } | ||
292 | |||
293 | fn add_line(&mut self, newline: TextSize) { | ||
294 | self.line += 1; | ||
295 | self.last_newline = newline; | ||
296 | self.col_adjust = TextSize::from(0); | ||
297 | } | ||
298 | |||
299 | fn adjust_col(&mut self, range: TextRange) { | ||
300 | self.col_adjust += range.len() - TextSize::from(1); | ||
301 | } | ||
302 | } | ||
diff --git a/crates/ra_ide_db/src/marks.rs b/crates/ra_ide_db/src/marks.rs deleted file mode 100644 index 386fe605c..000000000 --- a/crates/ra_ide_db/src/marks.rs +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | //! See test_utils/src/marks.rs | ||
2 | |||
3 | test_utils::marks![ | ||
4 | goto_def_for_macros | ||
5 | goto_def_for_use_alias | ||
6 | goto_def_for_methods | ||
7 | goto_def_for_fields | ||
8 | goto_def_for_record_fields | ||
9 | goto_def_for_field_init_shorthand | ||
10 | goto_def_for_record_field_pats | ||
11 | search_filters_by_range | ||
12 | ]; | ||
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs index b464959fc..589f44771 100644 --- a/crates/ra_ide_db/src/search.rs +++ b/crates/ra_ide_db/src/search.rs | |||
@@ -12,7 +12,6 @@ use ra_db::{FileId, FileRange, SourceDatabaseExt}; | |||
12 | use ra_prof::profile; | 12 | use ra_prof::profile; |
13 | use ra_syntax::{ast, match_ast, AstNode, TextRange, TextSize}; | 13 | use ra_syntax::{ast, match_ast, AstNode, TextRange, TextSize}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
15 | use test_utils::tested_by; | ||
16 | 15 | ||
17 | use crate::{ | 16 | use crate::{ |
18 | defs::{classify_name_ref, Definition, NameRefClass}, | 17 | defs::{classify_name_ref, Definition, NameRefClass}, |
@@ -209,7 +208,6 @@ impl Definition { | |||
209 | for (idx, _) in text.match_indices(pat) { | 208 | for (idx, _) in text.match_indices(pat) { |
210 | let offset: TextSize = idx.try_into().unwrap(); | 209 | let offset: TextSize = idx.try_into().unwrap(); |
211 | if !search_range.contains_inclusive(offset) { | 210 | if !search_range.contains_inclusive(offset) { |
212 | tested_by!(search_filters_by_range; force); | ||
213 | continue; | 211 | continue; |
214 | } | 212 | } |
215 | 213 | ||
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs index c64165f3a..e713f4b7e 100644 --- a/crates/ra_ide_db/src/source_change.rs +++ b/crates/ra_ide_db/src/source_change.rs | |||
@@ -3,94 +3,35 @@ | |||
3 | //! | 3 | //! |
4 | //! It can be viewed as a dual for `AnalysisChange`. | 4 | //! It can be viewed as a dual for `AnalysisChange`. |
5 | 5 | ||
6 | use ra_db::{FileId, FilePosition, RelativePathBuf, SourceRootId}; | 6 | use ra_db::{FileId, RelativePathBuf, SourceRootId}; |
7 | use ra_text_edit::{TextEdit, TextSize}; | 7 | use ra_text_edit::TextEdit; |
8 | 8 | ||
9 | #[derive(Debug, Clone)] | 9 | #[derive(Debug, Clone)] |
10 | pub struct SourceChange { | 10 | pub struct SourceChange { |
11 | /// For display in the undo log in the editor | ||
12 | pub label: String, | ||
13 | pub source_file_edits: Vec<SourceFileEdit>, | 11 | pub source_file_edits: Vec<SourceFileEdit>, |
14 | pub file_system_edits: Vec<FileSystemEdit>, | 12 | pub file_system_edits: Vec<FileSystemEdit>, |
15 | pub cursor_position: Option<FilePosition>, | ||
16 | pub is_snippet: bool, | 13 | pub is_snippet: bool, |
17 | } | 14 | } |
18 | 15 | ||
19 | impl SourceChange { | 16 | impl SourceChange { |
20 | /// Creates a new SourceChange with the given label | 17 | /// Creates a new SourceChange with the given label |
21 | /// from the edits. | 18 | /// from the edits. |
22 | pub fn from_edits<L: Into<String>>( | 19 | pub fn from_edits( |
23 | label: L, | ||
24 | source_file_edits: Vec<SourceFileEdit>, | 20 | source_file_edits: Vec<SourceFileEdit>, |
25 | file_system_edits: Vec<FileSystemEdit>, | 21 | file_system_edits: Vec<FileSystemEdit>, |
26 | ) -> Self { | 22 | ) -> Self { |
27 | SourceChange { | 23 | SourceChange { source_file_edits, file_system_edits, is_snippet: false } |
28 | label: label.into(), | ||
29 | source_file_edits, | ||
30 | file_system_edits, | ||
31 | cursor_position: None, | ||
32 | is_snippet: false, | ||
33 | } | ||
34 | } | 24 | } |
35 | 25 | ||
36 | /// Creates a new SourceChange with the given label, | 26 | /// Creates a new SourceChange with the given label, |
37 | /// containing only the given `SourceFileEdits`. | 27 | /// containing only the given `SourceFileEdits`. |
38 | pub fn source_file_edits<L: Into<String>>(label: L, edits: Vec<SourceFileEdit>) -> Self { | 28 | pub fn source_file_edits(edits: Vec<SourceFileEdit>) -> Self { |
39 | let label = label.into(); | 29 | SourceChange { source_file_edits: edits, file_system_edits: vec![], is_snippet: false } |
40 | assert!(label.starts_with(char::is_uppercase)); | ||
41 | SourceChange { | ||
42 | label: label, | ||
43 | source_file_edits: edits, | ||
44 | file_system_edits: vec![], | ||
45 | cursor_position: None, | ||
46 | is_snippet: false, | ||
47 | } | ||
48 | } | ||
49 | |||
50 | /// Creates a new SourceChange with the given label, | ||
51 | /// containing only the given `FileSystemEdits`. | ||
52 | pub(crate) fn file_system_edits<L: Into<String>>(label: L, edits: Vec<FileSystemEdit>) -> Self { | ||
53 | SourceChange { | ||
54 | label: label.into(), | ||
55 | source_file_edits: vec![], | ||
56 | file_system_edits: edits, | ||
57 | cursor_position: None, | ||
58 | is_snippet: false, | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /// Creates a new SourceChange with the given label, | ||
63 | /// containing only a single `SourceFileEdit`. | ||
64 | pub fn source_file_edit<L: Into<String>>(label: L, edit: SourceFileEdit) -> Self { | ||
65 | SourceChange::source_file_edits(label, vec![edit]) | ||
66 | } | ||
67 | |||
68 | /// Creates a new SourceChange with the given label | ||
69 | /// from the given `FileId` and `TextEdit` | ||
70 | pub fn source_file_edit_from<L: Into<String>>( | ||
71 | label: L, | ||
72 | file_id: FileId, | ||
73 | edit: TextEdit, | ||
74 | ) -> Self { | ||
75 | SourceChange::source_file_edit(label, SourceFileEdit { file_id, edit }) | ||
76 | } | 30 | } |
77 | |||
78 | /// Creates a new SourceChange with the given label | 31 | /// Creates a new SourceChange with the given label |
79 | /// from the given `FileId` and `TextEdit` | 32 | /// from the given `FileId` and `TextEdit` |
80 | pub fn file_system_edit<L: Into<String>>(label: L, edit: FileSystemEdit) -> Self { | 33 | pub fn source_file_edit_from(file_id: FileId, edit: TextEdit) -> Self { |
81 | SourceChange::file_system_edits(label, vec![edit]) | 34 | SourceFileEdit { file_id, edit }.into() |
82 | } | ||
83 | |||
84 | /// Sets the cursor position to the given `FilePosition` | ||
85 | pub fn with_cursor(mut self, cursor_position: FilePosition) -> Self { | ||
86 | self.cursor_position = Some(cursor_position); | ||
87 | self | ||
88 | } | ||
89 | |||
90 | /// Sets the cursor position to the given `FilePosition` | ||
91 | pub fn with_cursor_opt(mut self, cursor_position: Option<FilePosition>) -> Self { | ||
92 | self.cursor_position = cursor_position; | ||
93 | self | ||
94 | } | 35 | } |
95 | } | 36 | } |
96 | 37 | ||
@@ -100,25 +41,27 @@ pub struct SourceFileEdit { | |||
100 | pub edit: TextEdit, | 41 | pub edit: TextEdit, |
101 | } | 42 | } |
102 | 43 | ||
44 | impl From<SourceFileEdit> for SourceChange { | ||
45 | fn from(edit: SourceFileEdit) -> SourceChange { | ||
46 | SourceChange { | ||
47 | source_file_edits: vec![edit], | ||
48 | file_system_edits: Vec::new(), | ||
49 | is_snippet: false, | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
103 | #[derive(Debug, Clone)] | 54 | #[derive(Debug, Clone)] |
104 | pub enum FileSystemEdit { | 55 | pub enum FileSystemEdit { |
105 | CreateFile { source_root: SourceRootId, path: RelativePathBuf }, | 56 | CreateFile { source_root: SourceRootId, path: RelativePathBuf }, |
106 | MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, | 57 | MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, |
107 | } | 58 | } |
108 | 59 | ||
109 | pub struct SingleFileChange { | 60 | impl From<FileSystemEdit> for SourceChange { |
110 | pub label: String, | 61 | fn from(edit: FileSystemEdit) -> SourceChange { |
111 | pub edit: TextEdit, | ||
112 | pub cursor_position: Option<TextSize>, | ||
113 | } | ||
114 | |||
115 | impl SingleFileChange { | ||
116 | pub fn into_source_change(self, file_id: FileId) -> SourceChange { | ||
117 | SourceChange { | 62 | SourceChange { |
118 | label: self.label, | 63 | source_file_edits: Vec::new(), |
119 | source_file_edits: vec![SourceFileEdit { file_id, edit: self.edit }], | 64 | file_system_edits: vec![edit], |
120 | file_system_edits: Vec::new(), | ||
121 | cursor_position: self.cursor_position.map(|offset| FilePosition { file_id, offset }), | ||
122 | is_snippet: false, | 65 | is_snippet: false, |
123 | } | 66 | } |
124 | } | 67 | } |
diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs index c4f945101..25554f583 100644 --- a/crates/ra_text_edit/src/lib.rs +++ b/crates/ra_text_edit/src/lib.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | //! `rust-analyzer` never mutates text itself and only sends diffs to clients, | 3 | //! `rust-analyzer` never mutates text itself and only sends diffs to clients, |
4 | //! so `TextEdit` is the ultimate representation of the work done by | 4 | //! so `TextEdit` is the ultimate representation of the work done by |
5 | //! rust-analyzer. | 5 | //! rust-analyzer. |
6 | use std::{slice, vec}; | ||
6 | 7 | ||
7 | pub use text_size::{TextRange, TextSize}; | 8 | pub use text_size::{TextRange, TextSize}; |
8 | 9 | ||
@@ -16,7 +17,7 @@ pub struct Indel { | |||
16 | pub delete: TextRange, | 17 | pub delete: TextRange, |
17 | } | 18 | } |
18 | 19 | ||
19 | #[derive(Debug, Clone)] | 20 | #[derive(Default, Debug, Clone)] |
20 | pub struct TextEdit { | 21 | pub struct TextEdit { |
21 | indels: Vec<Indel>, | 22 | indels: Vec<Indel>, |
22 | } | 23 | } |
@@ -63,25 +64,24 @@ impl TextEdit { | |||
63 | builder.finish() | 64 | builder.finish() |
64 | } | 65 | } |
65 | 66 | ||
66 | pub(crate) fn from_indels(mut indels: Vec<Indel>) -> TextEdit { | 67 | pub fn len(&self) -> usize { |
67 | indels.sort_by_key(|a| (a.delete.start(), a.delete.end())); | 68 | self.indels.len() |
68 | for (a1, a2) in indels.iter().zip(indels.iter().skip(1)) { | ||
69 | assert!(a1.delete.end() <= a2.delete.start()) | ||
70 | } | ||
71 | TextEdit { indels } | ||
72 | } | 69 | } |
73 | 70 | ||
74 | pub fn is_empty(&self) -> bool { | 71 | pub fn is_empty(&self) -> bool { |
75 | self.indels.is_empty() | 72 | self.indels.is_empty() |
76 | } | 73 | } |
77 | 74 | ||
78 | // FXME: impl IntoIter instead | 75 | pub fn iter(&self) -> slice::Iter<'_, Indel> { |
79 | pub fn as_indels(&self) -> &[Indel] { | 76 | self.indels.iter() |
80 | &self.indels | 77 | } |
78 | |||
79 | pub fn into_iter(self) -> vec::IntoIter<Indel> { | ||
80 | self.indels.into_iter() | ||
81 | } | 81 | } |
82 | 82 | ||
83 | pub fn apply(&self, text: &mut String) { | 83 | pub fn apply(&self, text: &mut String) { |
84 | match self.indels.len() { | 84 | match self.len() { |
85 | 0 => return, | 85 | 0 => return, |
86 | 1 => { | 86 | 1 => { |
87 | self.indels[0].apply(text); | 87 | self.indels[0].apply(text); |
@@ -114,6 +114,17 @@ impl TextEdit { | |||
114 | *text = buf | 114 | *text = buf |
115 | } | 115 | } |
116 | 116 | ||
117 | pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> { | ||
118 | // FIXME: can be done without allocating intermediate vector | ||
119 | let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>(); | ||
120 | if !check_disjoint(&mut all) { | ||
121 | return Err(other); | ||
122 | } | ||
123 | self.indels.extend(other.indels); | ||
124 | assert!(check_disjoint(&mut self.indels)); | ||
125 | Ok(()) | ||
126 | } | ||
127 | |||
117 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { | 128 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { |
118 | let mut res = offset; | 129 | let mut res = offset; |
119 | for indel in self.indels.iter() { | 130 | for indel in self.indels.iter() { |
@@ -141,9 +152,19 @@ impl TextEditBuilder { | |||
141 | self.indels.push(Indel::insert(offset, text)) | 152 | self.indels.push(Indel::insert(offset, text)) |
142 | } | 153 | } |
143 | pub fn finish(self) -> TextEdit { | 154 | pub fn finish(self) -> TextEdit { |
144 | TextEdit::from_indels(self.indels) | 155 | let mut indels = self.indels; |
156 | assert!(check_disjoint(&mut indels)); | ||
157 | TextEdit { indels } | ||
145 | } | 158 | } |
146 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { | 159 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { |
147 | self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) | 160 | self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) |
148 | } | 161 | } |
149 | } | 162 | } |
163 | |||
164 | fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool { | ||
165 | indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end())); | ||
166 | indels | ||
167 | .iter() | ||
168 | .zip(indels.iter().skip(1)) | ||
169 | .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start()) | ||
170 | } | ||
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 09908458d..e82fd57de 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -74,12 +74,25 @@ fn run_server() -> Result<()> { | |||
74 | log::info!("lifecycle: server started"); | 74 | log::info!("lifecycle: server started"); |
75 | 75 | ||
76 | let (connection, io_threads) = Connection::stdio(); | 76 | let (connection, io_threads) = Connection::stdio(); |
77 | let server_capabilities = serde_json::to_value(rust_analyzer::server_capabilities()).unwrap(); | ||
78 | 77 | ||
79 | let initialize_params = connection.initialize(server_capabilities)?; | 78 | let (initialize_id, initialize_params) = connection.initialize_start()?; |
80 | let initialize_params = | 79 | let initialize_params = |
81 | from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?; | 80 | from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?; |
82 | 81 | ||
82 | let server_capabilities = rust_analyzer::server_capabilities(&initialize_params.capabilities); | ||
83 | |||
84 | let initialize_result = lsp_types::InitializeResult { | ||
85 | capabilities: server_capabilities, | ||
86 | server_info: Some(lsp_types::ServerInfo { | ||
87 | name: String::from("rust-analyzer"), | ||
88 | version: Some(String::from(env!("REV"))), | ||
89 | }), | ||
90 | }; | ||
91 | |||
92 | let initialize_result = serde_json::to_value(initialize_result).unwrap(); | ||
93 | |||
94 | connection.initialize_finish(initialize_id, initialize_result)?; | ||
95 | |||
83 | if let Some(client_info) = initialize_params.client_info { | 96 | if let Some(client_info) = initialize_params.client_info { |
84 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); | 97 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); |
85 | } | 98 | } |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 110c9a442..780fc9317 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -1,19 +1,23 @@ | |||
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 crate::semantic_tokens; | ||
5 | |||
6 | use lsp_types::{ | 4 | use lsp_types::{ |
7 | CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability, | 5 | CallHierarchyServerCapability, ClientCapabilities, CodeActionOptions, |
8 | CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, | 6 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, |
9 | FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions, | 7 | DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, |
10 | RenameProviderCapability, SaveOptions, SelectionRangeProviderCapability, | 8 | ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, |
11 | SemanticTokensDocumentProvider, SemanticTokensLegend, SemanticTokensOptions, | 9 | SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, |
12 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, | 10 | SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, |
13 | TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, | 11 | TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, |
12 | WorkDoneProgressOptions, | ||
14 | }; | 13 | }; |
14 | use serde_json::json; | ||
15 | |||
16 | use crate::semantic_tokens; | ||
17 | |||
18 | pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { | ||
19 | let code_action_provider = code_action_capabilities(client_caps); | ||
15 | 20 | ||
16 | pub fn server_capabilities() -> ServerCapabilities { | ||
17 | ServerCapabilities { | 21 | ServerCapabilities { |
18 | text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { | 22 | text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { |
19 | open_close: Some(true), | 23 | open_close: Some(true), |
@@ -45,20 +49,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
45 | document_highlight_provider: Some(true), | 49 | document_highlight_provider: Some(true), |
46 | document_symbol_provider: Some(true), | 50 | document_symbol_provider: Some(true), |
47 | workspace_symbol_provider: Some(true), | 51 | workspace_symbol_provider: Some(true), |
48 | code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions { | 52 | code_action_provider: Some(code_action_provider), |
49 | // Advertise support for all built-in CodeActionKinds | ||
50 | code_action_kinds: Some(vec![ | ||
51 | lsp_types::code_action_kind::EMPTY.to_string(), | ||
52 | lsp_types::code_action_kind::QUICKFIX.to_string(), | ||
53 | lsp_types::code_action_kind::REFACTOR.to_string(), | ||
54 | lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), | ||
55 | lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), | ||
56 | lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), | ||
57 | lsp_types::code_action_kind::SOURCE.to_string(), | ||
58 | lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(), | ||
59 | ]), | ||
60 | work_done_progress_options: Default::default(), | ||
61 | })), | ||
62 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), | 53 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), |
63 | document_formatting_provider: Some(true), | 54 | document_formatting_provider: Some(true), |
64 | document_range_formatting_provider: None, | 55 | document_range_formatting_provider: None, |
@@ -91,6 +82,35 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
91 | } | 82 | } |
92 | .into(), | 83 | .into(), |
93 | ), | 84 | ), |
94 | experimental: Default::default(), | 85 | experimental: Some(json!({ |
86 | "joinLines": true, | ||
87 | "ssr": true, | ||
88 | })), | ||
95 | } | 89 | } |
96 | } | 90 | } |
91 | |||
92 | fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { | ||
93 | client_caps | ||
94 | .text_document | ||
95 | .as_ref() | ||
96 | .and_then(|it| it.code_action.as_ref()) | ||
97 | .and_then(|it| it.code_action_literal_support.as_ref()) | ||
98 | .map_or(CodeActionProviderCapability::Simple(true), |_| { | ||
99 | CodeActionProviderCapability::Options(CodeActionOptions { | ||
100 | // Advertise support for all built-in CodeActionKinds. | ||
101 | // Ideally we would base this off of the client capabilities | ||
102 | // but the client is supposed to fall back gracefully for unknown values. | ||
103 | code_action_kinds: Some(vec![ | ||
104 | lsp_types::code_action_kind::EMPTY.to_string(), | ||
105 | lsp_types::code_action_kind::QUICKFIX.to_string(), | ||
106 | lsp_types::code_action_kind::REFACTOR.to_string(), | ||
107 | lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), | ||
108 | lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), | ||
109 | lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), | ||
110 | lsp_types::code_action_kind::SOURCE.to_string(), | ||
111 | lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(), | ||
112 | ]), | ||
113 | work_done_progress_options: Default::default(), | ||
114 | }) | ||
115 | }) | ||
116 | } | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d75c48597..c0f7c2c0c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -102,6 +102,7 @@ pub struct ClientCapsConfig { | |||
102 | pub hierarchical_symbols: bool, | 102 | pub hierarchical_symbols: bool, |
103 | pub code_action_literals: bool, | 103 | pub code_action_literals: bool, |
104 | pub work_done_progress: bool, | 104 | pub work_done_progress: bool, |
105 | pub code_action_group: bool, | ||
105 | } | 106 | } |
106 | 107 | ||
107 | impl Default for Config { | 108 | impl Default for Config { |
@@ -268,10 +269,8 @@ impl Config { | |||
268 | { | 269 | { |
269 | self.client_caps.hierarchical_symbols = value | 270 | self.client_caps.hierarchical_symbols = value |
270 | } | 271 | } |
271 | if let Some(value) = doc_caps | 272 | if let Some(value) = |
272 | .code_action | 273 | doc_caps.code_action.as_ref().map(|it| it.code_action_literal_support.is_some()) |
273 | .as_ref() | ||
274 | .and_then(|it| Some(it.code_action_literal_support.is_some())) | ||
275 | { | 274 | { |
276 | self.client_caps.code_action_literals = value; | 275 | self.client_caps.code_action_literals = value; |
277 | } | 276 | } |
@@ -294,9 +293,13 @@ impl Config { | |||
294 | 293 | ||
295 | self.assist.allow_snippets(false); | 294 | self.assist.allow_snippets(false); |
296 | if let Some(experimental) = &caps.experimental { | 295 | if let Some(experimental) = &caps.experimental { |
297 | let enable = | 296 | let snippet_text_edit = |
298 | experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true); | 297 | experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true); |
299 | self.assist.allow_snippets(enable); | 298 | self.assist.allow_snippets(snippet_text_edit); |
299 | |||
300 | let code_action_group = | ||
301 | experimental.get("codeActionGroup").and_then(|it| it.as_bool()) == Some(true); | ||
302 | self.client_caps.code_action_group = code_action_group | ||
300 | } | 303 | } |
301 | } | 304 | } |
302 | } | 305 | } |
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap index 96466b5c9..c40cfdcdc 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap | |||
@@ -65,6 +65,7 @@ expression: diag | |||
65 | fixes: [ | 65 | fixes: [ |
66 | CodeAction { | 66 | CodeAction { |
67 | title: "return the expression directly", | 67 | title: "return the expression directly", |
68 | group: None, | ||
68 | kind: Some( | 69 | kind: Some( |
69 | "quickfix", | 70 | "quickfix", |
70 | ), | 71 | ), |
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap index 8f962277f..6dd3fcb2e 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap | |||
@@ -50,6 +50,7 @@ expression: diag | |||
50 | fixes: [ | 50 | fixes: [ |
51 | CodeAction { | 51 | CodeAction { |
52 | title: "consider prefixing with an underscore", | 52 | title: "consider prefixing with an underscore", |
53 | group: None, | ||
53 | kind: Some( | 54 | kind: Some( |
54 | "quickfix", | 55 | "quickfix", |
55 | ), | 56 | ), |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index afea59525..a500d670a 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -145,6 +145,7 @@ fn map_rust_child_diagnostic( | |||
145 | } else { | 145 | } else { |
146 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { | 146 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { |
147 | title: rd.message.clone(), | 147 | title: rd.message.clone(), |
148 | group: None, | ||
148 | kind: Some("quickfix".to_string()), | 149 | kind: Some("quickfix".to_string()), |
149 | edit: Some(lsp_ext::SnippetWorkspaceEdit { | 150 | edit: Some(lsp_ext::SnippetWorkspaceEdit { |
150 | // FIXME: there's no good reason to use edit_map here.... | 151 | // FIXME: there's no good reason to use edit_map here.... |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index f75a26eb7..c25d90a50 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -87,22 +87,22 @@ pub enum JoinLines {} | |||
87 | 87 | ||
88 | impl Request for JoinLines { | 88 | impl Request for JoinLines { |
89 | type Params = JoinLinesParams; | 89 | type Params = JoinLinesParams; |
90 | type Result = SourceChange; | 90 | type Result = Vec<lsp_types::TextEdit>; |
91 | const METHOD: &'static str = "rust-analyzer/joinLines"; | 91 | const METHOD: &'static str = "experimental/joinLines"; |
92 | } | 92 | } |
93 | 93 | ||
94 | #[derive(Deserialize, Serialize, Debug)] | 94 | #[derive(Deserialize, Serialize, Debug)] |
95 | #[serde(rename_all = "camelCase")] | 95 | #[serde(rename_all = "camelCase")] |
96 | pub struct JoinLinesParams { | 96 | pub struct JoinLinesParams { |
97 | pub text_document: TextDocumentIdentifier, | 97 | pub text_document: TextDocumentIdentifier, |
98 | pub range: Range, | 98 | pub ranges: Vec<Range>, |
99 | } | 99 | } |
100 | 100 | ||
101 | pub enum OnEnter {} | 101 | pub enum OnEnter {} |
102 | 102 | ||
103 | impl Request for OnEnter { | 103 | impl Request for OnEnter { |
104 | type Params = lsp_types::TextDocumentPositionParams; | 104 | type Params = lsp_types::TextDocumentPositionParams; |
105 | type Result = Option<SourceChange>; | 105 | type Result = Option<SnippetWorkspaceEdit>; |
106 | const METHOD: &'static str = "rust-analyzer/onEnter"; | 106 | const METHOD: &'static str = "rust-analyzer/onEnter"; |
107 | } | 107 | } |
108 | 108 | ||
@@ -133,14 +133,6 @@ pub struct Runnable { | |||
133 | pub cwd: Option<PathBuf>, | 133 | pub cwd: Option<PathBuf>, |
134 | } | 134 | } |
135 | 135 | ||
136 | #[derive(Deserialize, Serialize, Debug)] | ||
137 | #[serde(rename_all = "camelCase")] | ||
138 | pub struct SourceChange { | ||
139 | pub label: String, | ||
140 | pub workspace_edit: SnippetWorkspaceEdit, | ||
141 | pub cursor_position: Option<lsp_types::TextDocumentPositionParams>, | ||
142 | } | ||
143 | |||
144 | pub enum InlayHints {} | 136 | pub enum InlayHints {} |
145 | 137 | ||
146 | impl Request for InlayHints { | 138 | impl Request for InlayHints { |
@@ -173,8 +165,8 @@ pub enum Ssr {} | |||
173 | 165 | ||
174 | impl Request for Ssr { | 166 | impl Request for Ssr { |
175 | type Params = SsrParams; | 167 | type Params = SsrParams; |
176 | type Result = SourceChange; | 168 | type Result = lsp_types::WorkspaceEdit; |
177 | const METHOD: &'static str = "rust-analyzer/ssr"; | 169 | const METHOD: &'static str = "experimental/ssr"; |
178 | } | 170 | } |
179 | 171 | ||
180 | #[derive(Debug, Deserialize, Serialize)] | 172 | #[derive(Debug, Deserialize, Serialize)] |
@@ -196,6 +188,8 @@ impl Request for CodeActionRequest { | |||
196 | pub struct CodeAction { | 188 | pub struct CodeAction { |
197 | pub title: String, | 189 | pub title: String, |
198 | #[serde(skip_serializing_if = "Option::is_none")] | 190 | #[serde(skip_serializing_if = "Option::is_none")] |
191 | pub group: Option<String>, | ||
192 | #[serde(skip_serializing_if = "Option::is_none")] | ||
199 | pub kind: Option<String>, | 193 | pub kind: Option<String>, |
200 | #[serde(skip_serializing_if = "Option::is_none")] | 194 | #[serde(skip_serializing_if = "Option::is_none")] |
201 | pub command: Option<lsp_types::Command>, | 195 | pub command: Option<lsp_types::Command>, |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 4ff8fa69e..ba6857556 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -15,10 +15,11 @@ use lsp_types::{ | |||
15 | DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, | 15 | DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, |
16 | MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, | 16 | MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, |
17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, | 17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, |
18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, TextEdit, Url, WorkspaceEdit, | 18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, |
19 | }; | 19 | }; |
20 | use ra_ide::{ | 20 | use ra_ide::{ |
21 | Assist, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, | 21 | FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, |
22 | TextEdit, | ||
22 | }; | 23 | }; |
23 | use ra_prof::profile; | 24 | use ra_prof::profile; |
24 | use ra_project_model::TargetKind; | 25 | use ra_project_model::TargetKind; |
@@ -149,22 +150,35 @@ pub fn handle_find_matching_brace( | |||
149 | pub fn handle_join_lines( | 150 | pub fn handle_join_lines( |
150 | world: WorldSnapshot, | 151 | world: WorldSnapshot, |
151 | params: lsp_ext::JoinLinesParams, | 152 | params: lsp_ext::JoinLinesParams, |
152 | ) -> Result<lsp_ext::SourceChange> { | 153 | ) -> Result<Vec<lsp_types::TextEdit>> { |
153 | let _p = profile("handle_join_lines"); | 154 | let _p = profile("handle_join_lines"); |
154 | let frange = from_proto::file_range(&world, params.text_document, params.range)?; | 155 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
155 | let source_change = world.analysis().join_lines(frange)?; | 156 | let line_index = world.analysis().file_line_index(file_id)?; |
156 | to_proto::source_change(&world, source_change) | 157 | let line_endings = world.file_line_endings(file_id); |
158 | let mut res = TextEdit::default(); | ||
159 | for range in params.ranges { | ||
160 | let range = from_proto::text_range(&line_index, range); | ||
161 | let edit = world.analysis().join_lines(FileRange { file_id, range })?; | ||
162 | match res.union(edit) { | ||
163 | Ok(()) => (), | ||
164 | Err(_edit) => { | ||
165 | // just ignore overlapping edits | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | let res = to_proto::text_edit_vec(&line_index, line_endings, res); | ||
170 | Ok(res) | ||
157 | } | 171 | } |
158 | 172 | ||
159 | pub fn handle_on_enter( | 173 | pub fn handle_on_enter( |
160 | world: WorldSnapshot, | 174 | world: WorldSnapshot, |
161 | params: lsp_types::TextDocumentPositionParams, | 175 | params: lsp_types::TextDocumentPositionParams, |
162 | ) -> Result<Option<lsp_ext::SourceChange>> { | 176 | ) -> Result<Option<lsp_ext::SnippetWorkspaceEdit>> { |
163 | let _p = profile("handle_on_enter"); | 177 | let _p = profile("handle_on_enter"); |
164 | let position = from_proto::file_position(&world, params)?; | 178 | let position = from_proto::file_position(&world, params)?; |
165 | match world.analysis().on_enter(position)? { | 179 | match world.analysis().on_enter(position)? { |
166 | None => Ok(None), | 180 | None => Ok(None), |
167 | Some(source_change) => to_proto::source_change(&world, source_change).map(Some), | 181 | Some(source_change) => to_proto::snippet_workspace_edit(&world, source_change).map(Some), |
168 | } | 182 | } |
169 | } | 183 | } |
170 | 184 | ||
@@ -172,7 +186,7 @@ pub fn handle_on_enter( | |||
172 | pub fn handle_on_type_formatting( | 186 | pub fn handle_on_type_formatting( |
173 | world: WorldSnapshot, | 187 | world: WorldSnapshot, |
174 | params: lsp_types::DocumentOnTypeFormattingParams, | 188 | params: lsp_types::DocumentOnTypeFormattingParams, |
175 | ) -> Result<Option<Vec<TextEdit>>> { | 189 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
176 | let _p = profile("handle_on_type_formatting"); | 190 | let _p = profile("handle_on_type_formatting"); |
177 | let mut position = from_proto::file_position(&world, params.text_document_position)?; | 191 | let mut position = from_proto::file_position(&world, params.text_document_position)?; |
178 | let line_index = world.analysis().file_line_index(position.file_id)?; | 192 | let line_index = world.analysis().file_line_index(position.file_id)?; |
@@ -267,7 +281,7 @@ pub fn handle_document_symbol( | |||
267 | kind: symbol.kind, | 281 | kind: symbol.kind, |
268 | deprecated: symbol.deprecated, | 282 | deprecated: symbol.deprecated, |
269 | location: Location::new(url.clone(), symbol.range), | 283 | location: Location::new(url.clone(), symbol.range), |
270 | container_name: container_name, | 284 | container_name, |
271 | }); | 285 | }); |
272 | 286 | ||
273 | for child in symbol.children.iter().flatten() { | 287 | for child in symbol.children.iter().flatten() { |
@@ -618,7 +632,7 @@ pub fn handle_references( | |||
618 | pub fn handle_formatting( | 632 | pub fn handle_formatting( |
619 | world: WorldSnapshot, | 633 | world: WorldSnapshot, |
620 | params: DocumentFormattingParams, | 634 | params: DocumentFormattingParams, |
621 | ) -> Result<Option<Vec<TextEdit>>> { | 635 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
622 | let _p = profile("handle_formatting"); | 636 | let _p = profile("handle_formatting"); |
623 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 637 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
624 | let file = world.analysis().file_text(file_id)?; | 638 | let file = world.analysis().file_text(file_id)?; |
@@ -685,7 +699,7 @@ pub fn handle_formatting( | |||
685 | } | 699 | } |
686 | } | 700 | } |
687 | 701 | ||
688 | Ok(Some(vec![TextEdit { | 702 | Ok(Some(vec![lsp_types::TextEdit { |
689 | range: Range::new(Position::new(0, 0), end_position), | 703 | range: Range::new(Position::new(0, 0), end_position), |
690 | new_text: captured_stdout, | 704 | new_text: captured_stdout, |
691 | }])) | 705 | }])) |
@@ -706,6 +720,7 @@ pub fn handle_code_action( | |||
706 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 720 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
707 | let line_index = world.analysis().file_line_index(file_id)?; | 721 | let line_index = world.analysis().file_line_index(file_id)?; |
708 | let range = from_proto::text_range(&line_index, params.range); | 722 | let range = from_proto::text_range(&line_index, params.range); |
723 | let frange = FileRange { file_id, range }; | ||
709 | 724 | ||
710 | let diagnostics = world.analysis().diagnostics(file_id)?; | 725 | let diagnostics = world.analysis().diagnostics(file_id)?; |
711 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | 726 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); |
@@ -716,10 +731,11 @@ pub fn handle_code_action( | |||
716 | .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) | 731 | .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) |
717 | .map(|(_range, fix)| fix); | 732 | .map(|(_range, fix)| fix); |
718 | 733 | ||
719 | for source_edit in fixes_from_diagnostics { | 734 | for fix in fixes_from_diagnostics { |
720 | let title = source_edit.label.clone(); | 735 | let title = fix.label; |
721 | let edit = to_proto::snippet_workspace_edit(&world, source_edit)?; | 736 | let edit = to_proto::snippet_workspace_edit(&world, fix.source_change)?; |
722 | let action = lsp_ext::CodeAction { title, kind: None, edit: Some(edit), command: None }; | 737 | let action = |
738 | lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None }; | ||
723 | res.push(action); | 739 | res.push(action); |
724 | } | 740 | } |
725 | 741 | ||
@@ -731,53 +747,9 @@ pub fn handle_code_action( | |||
731 | res.push(fix.action.clone()); | 747 | res.push(fix.action.clone()); |
732 | } | 748 | } |
733 | 749 | ||
734 | let mut grouped_assists: FxHashMap<String, (usize, Vec<Assist>)> = FxHashMap::default(); | 750 | for assist in world.analysis().assists(&world.config.assist, frange)?.into_iter() { |
735 | for assist in | 751 | res.push(to_proto::code_action(&world, assist)?.into()); |
736 | world.analysis().assists(&world.config.assist, FileRange { file_id, range })?.into_iter() | ||
737 | { | ||
738 | match &assist.group_label { | ||
739 | Some(label) => grouped_assists | ||
740 | .entry(label.to_owned()) | ||
741 | .or_insert_with(|| { | ||
742 | let idx = res.len(); | ||
743 | let dummy = lsp_ext::CodeAction { | ||
744 | title: String::new(), | ||
745 | kind: None, | ||
746 | command: None, | ||
747 | edit: None, | ||
748 | }; | ||
749 | res.push(dummy); | ||
750 | (idx, Vec::new()) | ||
751 | }) | ||
752 | .1 | ||
753 | .push(assist), | ||
754 | None => { | ||
755 | res.push(to_proto::code_action(&world, assist)?.into()); | ||
756 | } | ||
757 | } | ||
758 | } | ||
759 | |||
760 | for (group_label, (idx, assists)) in grouped_assists { | ||
761 | if assists.len() == 1 { | ||
762 | res[idx] = to_proto::code_action(&world, assists.into_iter().next().unwrap())?.into(); | ||
763 | } else { | ||
764 | let title = group_label; | ||
765 | |||
766 | let mut arguments = Vec::with_capacity(assists.len()); | ||
767 | for assist in assists { | ||
768 | let source_change = to_proto::source_change(&world, assist.source_change)?; | ||
769 | arguments.push(to_value(source_change)?); | ||
770 | } | ||
771 | |||
772 | let command = Some(Command { | ||
773 | title: title.clone(), | ||
774 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), | ||
775 | arguments: Some(vec![serde_json::Value::Array(arguments)]), | ||
776 | }); | ||
777 | res[idx] = lsp_ext::CodeAction { title, kind: None, edit: None, command }; | ||
778 | } | ||
779 | } | 752 | } |
780 | |||
781 | Ok(Some(res)) | 753 | Ok(Some(res)) |
782 | } | 754 | } |
783 | 755 | ||
@@ -802,11 +774,11 @@ pub fn handle_code_lens( | |||
802 | for runnable in world.analysis().runnables(file_id)? { | 774 | for runnable in world.analysis().runnables(file_id)? { |
803 | let (run_title, debugee) = match &runnable.kind { | 775 | let (run_title, debugee) = match &runnable.kind { |
804 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { | 776 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { |
805 | ("▶️\u{fe0e}Run Test", true) | 777 | ("▶\u{fe0e} Run Test", true) |
806 | } | 778 | } |
807 | RunnableKind::DocTest { .. } => { | 779 | RunnableKind::DocTest { .. } => { |
808 | // cargo does not support -no-run for doctests | 780 | // cargo does not support -no-run for doctests |
809 | ("▶️\u{fe0e}Run Doctest", false) | 781 | ("▶\u{fe0e} Run Doctest", false) |
810 | } | 782 | } |
811 | RunnableKind::Bench { .. } => { | 783 | RunnableKind::Bench { .. } => { |
812 | // Nothing wrong with bench debugging | 784 | // Nothing wrong with bench debugging |
@@ -972,11 +944,11 @@ pub fn handle_document_highlight( | |||
972 | pub fn handle_ssr( | 944 | pub fn handle_ssr( |
973 | world: WorldSnapshot, | 945 | world: WorldSnapshot, |
974 | params: lsp_ext::SsrParams, | 946 | params: lsp_ext::SsrParams, |
975 | ) -> Result<lsp_ext::SourceChange> { | 947 | ) -> Result<lsp_types::WorkspaceEdit> { |
976 | let _p = profile("handle_ssr"); | 948 | let _p = profile("handle_ssr"); |
977 | let source_change = | 949 | let source_change = |
978 | world.analysis().structural_search_replace(¶ms.query, params.parse_only)??; | 950 | world.analysis().structural_search_replace(¶ms.query, params.parse_only)??; |
979 | to_proto::source_change(&world, source_change) | 951 | to_proto::workspace_edit(&world, source_change) |
980 | } | 952 | } |
981 | 953 | ||
982 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { | 954 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index af54f81b7..7dd7d9416 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -1,13 +1,12 @@ | |||
1 | //! Conversion of rust-analyzer specific types to lsp_types equivalents. | 1 | //! Conversion of rust-analyzer specific types to lsp_types equivalents. |
2 | use ra_db::{FileId, FileRange}; | 2 | use ra_db::{FileId, FileRange}; |
3 | use ra_ide::{ | 3 | use ra_ide::{ |
4 | translate_offset_with_edit, Assist, CompletionItem, CompletionItemKind, Documentation, | 4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, |
5 | FileSystemEdit, Fold, FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, | 5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, |
6 | HighlightedRange, InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, | 6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, |
7 | ReferenceAccess, Severity, SourceChange, SourceFileEdit, | 7 | SourceChange, SourceFileEdit, TextEdit, |
8 | }; | 8 | }; |
9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
10 | use ra_text_edit::{Indel, TextEdit}; | ||
11 | use ra_vfs::LineEndings; | 10 | use ra_vfs::LineEndings; |
12 | 11 | ||
13 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; | 12 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; |
@@ -133,11 +132,7 @@ pub(crate) fn text_edit_vec( | |||
133 | line_endings: LineEndings, | 132 | line_endings: LineEndings, |
134 | text_edit: TextEdit, | 133 | text_edit: TextEdit, |
135 | ) -> Vec<lsp_types::TextEdit> { | 134 | ) -> Vec<lsp_types::TextEdit> { |
136 | text_edit | 135 | text_edit.into_iter().map(|indel| self::text_edit(line_index, line_endings, indel)).collect() |
137 | .as_indels() | ||
138 | .iter() | ||
139 | .map(|it| self::text_edit(line_index, line_endings, it.clone())) | ||
140 | .collect() | ||
141 | } | 136 | } |
142 | 137 | ||
143 | pub(crate) fn completion_item( | 138 | pub(crate) fn completion_item( |
@@ -150,7 +145,7 @@ pub(crate) fn completion_item( | |||
150 | // LSP does not allow arbitrary edits in completion, so we have to do a | 145 | // LSP does not allow arbitrary edits in completion, so we have to do a |
151 | // non-trivial mapping here. | 146 | // non-trivial mapping here. |
152 | let source_range = completion_item.source_range(); | 147 | let source_range = completion_item.source_range(); |
153 | for indel in completion_item.text_edit().as_indels() { | 148 | for indel in completion_item.text_edit().iter() { |
154 | if indel.delete.contains_range(source_range) { | 149 | if indel.delete.contains_range(source_range) { |
155 | text_edit = Some(if indel.delete == source_range { | 150 | text_edit = Some(if indel.delete == source_range { |
156 | self::text_edit(line_index, line_endings, indel.clone()) | 151 | self::text_edit(line_index, line_endings, indel.clone()) |
@@ -375,14 +370,6 @@ pub(crate) fn url(world: &WorldSnapshot, file_id: FileId) -> Result<lsp_types::U | |||
375 | world.file_id_to_uri(file_id) | 370 | world.file_id_to_uri(file_id) |
376 | } | 371 | } |
377 | 372 | ||
378 | pub(crate) fn text_document_identifier( | ||
379 | world: &WorldSnapshot, | ||
380 | file_id: FileId, | ||
381 | ) -> Result<lsp_types::TextDocumentIdentifier> { | ||
382 | let res = lsp_types::TextDocumentIdentifier { uri: url(world, file_id)? }; | ||
383 | Ok(res) | ||
384 | } | ||
385 | |||
386 | pub(crate) fn versioned_text_document_identifier( | 373 | pub(crate) fn versioned_text_document_identifier( |
387 | world: &WorldSnapshot, | 374 | world: &WorldSnapshot, |
388 | file_id: FileId, | 375 | file_id: FileId, |
@@ -467,9 +454,8 @@ pub(crate) fn snippet_text_document_edit( | |||
467 | let line_endings = world.file_line_endings(source_file_edit.file_id); | 454 | let line_endings = world.file_line_endings(source_file_edit.file_id); |
468 | let edits = source_file_edit | 455 | let edits = source_file_edit |
469 | .edit | 456 | .edit |
470 | .as_indels() | 457 | .into_iter() |
471 | .iter() | 458 | .map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it)) |
472 | .map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it.clone())) | ||
473 | .collect(); | 459 | .collect(); |
474 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 460 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
475 | } | 461 | } |
@@ -492,36 +478,6 @@ pub(crate) fn resource_op( | |||
492 | Ok(res) | 478 | Ok(res) |
493 | } | 479 | } |
494 | 480 | ||
495 | pub(crate) fn source_change( | ||
496 | world: &WorldSnapshot, | ||
497 | source_change: SourceChange, | ||
498 | ) -> Result<lsp_ext::SourceChange> { | ||
499 | let cursor_position = match source_change.cursor_position { | ||
500 | None => None, | ||
501 | Some(pos) => { | ||
502 | let line_index = world.analysis().file_line_index(pos.file_id)?; | ||
503 | let edit = source_change | ||
504 | .source_file_edits | ||
505 | .iter() | ||
506 | .find(|it| it.file_id == pos.file_id) | ||
507 | .map(|it| &it.edit); | ||
508 | let line_col = match edit { | ||
509 | Some(edit) => translate_offset_with_edit(&*line_index, pos.offset, edit), | ||
510 | None => line_index.line_col(pos.offset), | ||
511 | }; | ||
512 | let position = | ||
513 | lsp_types::Position::new(u64::from(line_col.line), u64::from(line_col.col_utf16)); | ||
514 | Some(lsp_types::TextDocumentPositionParams { | ||
515 | text_document: text_document_identifier(world, pos.file_id)?, | ||
516 | position, | ||
517 | }) | ||
518 | } | ||
519 | }; | ||
520 | let label = source_change.label.clone(); | ||
521 | let workspace_edit = self::snippet_workspace_edit(world, source_change)?; | ||
522 | Ok(lsp_ext::SourceChange { label, workspace_edit, cursor_position }) | ||
523 | } | ||
524 | |||
525 | pub(crate) fn snippet_workspace_edit( | 481 | pub(crate) fn snippet_workspace_edit( |
526 | world: &WorldSnapshot, | 482 | world: &WorldSnapshot, |
527 | source_change: SourceChange, | 483 | source_change: SourceChange, |
@@ -639,25 +595,12 @@ fn main() <fold>{ | |||
639 | } | 595 | } |
640 | 596 | ||
641 | pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_ext::CodeAction> { | 597 | pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_ext::CodeAction> { |
642 | let res = if assist.source_change.cursor_position.is_none() { | 598 | let res = lsp_ext::CodeAction { |
643 | lsp_ext::CodeAction { | 599 | title: assist.label, |
644 | title: assist.label, | 600 | group: if world.config.client_caps.code_action_group { assist.group_label } else { None }, |
645 | kind: Some(String::new()), | 601 | kind: Some(String::new()), |
646 | edit: Some(snippet_workspace_edit(world, assist.source_change)?), | 602 | edit: Some(snippet_workspace_edit(world, assist.source_change)?), |
647 | command: None, | 603 | command: None, |
648 | } | ||
649 | } else { | ||
650 | assert!(!assist.source_change.is_snippet); | ||
651 | let source_change = source_change(&world, assist.source_change)?; | ||
652 | let arg = serde_json::to_value(source_change)?; | ||
653 | let title = assist.label; | ||
654 | let command = lsp_types::Command { | ||
655 | title: title.clone(), | ||
656 | command: "rust-analyzer.applySourceChange".to_string(), | ||
657 | arguments: Some(vec![arg]), | ||
658 | }; | ||
659 | |||
660 | lsp_ext::CodeAction { title, kind: Some(String::new()), edit: None, command: Some(command) } | ||
661 | }; | 604 | }; |
662 | Ok(res) | 605 | Ok(res) |
663 | } | 606 | } |
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 74676b3ee..738a9a8e3 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -474,27 +474,21 @@ fn main() {{}} | |||
474 | position: Position { line: 0, character: 5 }, | 474 | position: Position { line: 0, character: 5 }, |
475 | }, | 475 | }, |
476 | json!({ | 476 | json!({ |
477 | "cursorPosition": { | 477 | "documentChanges": [ |
478 | "position": { "character": 4, "line": 1 }, | 478 | { |
479 | "textDocument": { "uri": "file:///[..]src/m0.rs" } | 479 | "edits": [ |
480 | }, | 480 | { |
481 | "label": "On enter", | 481 | "insertTextFormat": 2, |
482 | "workspaceEdit": { | 482 | "newText": "\n/// $0", |
483 | "documentChanges": [ | 483 | "range": { |
484 | { | 484 | "end": { "character": 5, "line": 0 }, |
485 | "edits": [ | 485 | "start": { "character": 5, "line": 0 } |
486 | { | ||
487 | "newText": "\n/// ", | ||
488 | "range": { | ||
489 | "end": { "character": 5, "line": 0 }, | ||
490 | "start": { "character": 5, "line": 0 } | ||
491 | } | ||
492 | } | 486 | } |
493 | ], | 487 | } |
494 | "textDocument": { "uri": "file:///[..]src/m0.rs", "version": null } | 488 | ], |
495 | } | 489 | "textDocument": { "uri": "file:///[..]src/m0.rs", "version": null } |
496 | ] | 490 | } |
497 | } | 491 | ] |
498 | }), | 492 | }), |
499 | ); | 493 | ); |
500 | let elapsed = start.elapsed(); | 494 | let elapsed = start.elapsed(); |
@@ -526,27 +520,21 @@ version = \"0.0.0\" | |||
526 | position: Position { line: 0, character: 8 }, | 520 | position: Position { line: 0, character: 8 }, |
527 | }, | 521 | }, |
528 | json!({ | 522 | json!({ |
529 | "cursorPosition": { | 523 | "documentChanges": [ |
530 | "position": { "line": 1, "character": 4 }, | 524 | { |
531 | "textDocument": { "uri": "file:///[..]src/main.rs" } | 525 | "edits": [ |
532 | }, | 526 | { |
533 | "label": "On enter", | 527 | "insertTextFormat": 2, |
534 | "workspaceEdit": { | 528 | "newText": "\r\n/// $0", |
535 | "documentChanges": [ | 529 | "range": { |
536 | { | 530 | "end": { "line": 0, "character": 8 }, |
537 | "edits": [ | 531 | "start": { "line": 0, "character": 8 } |
538 | { | ||
539 | "newText": "\r\n/// ", | ||
540 | "range": { | ||
541 | "end": { "line": 0, "character": 8 }, | ||
542 | "start": { "line": 0, "character": 8 } | ||
543 | } | ||
544 | } | 532 | } |
545 | ], | 533 | } |
546 | "textDocument": { "uri": "file:///[..]src/main.rs", "version": null } | 534 | ], |
547 | } | 535 | "textDocument": { "uri": "file:///[..]src/main.rs", "version": null } |
548 | ] | 536 | } |
549 | } | 537 | ] |
550 | }), | 538 | }), |
551 | ); | 539 | ); |
552 | } | 540 | } |
@@ -786,5 +774,5 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
786 | }); | 774 | }); |
787 | 775 | ||
788 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); | 776 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); |
789 | assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#) | 777 | assert_eq!(value, r#""foo::Bar\n___\n\n```rust\nfn bar()\n```""#) |
790 | } | 778 | } |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index b1e3c328f..be2cfbaa2 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -7,7 +7,7 @@ | |||
7 | //! * marks (see the eponymous module). | 7 | //! * marks (see the eponymous module). |
8 | 8 | ||
9 | #[macro_use] | 9 | #[macro_use] |
10 | pub mod marks; | 10 | pub mod mark; |
11 | 11 | ||
12 | use std::{ | 12 | use std::{ |
13 | fs, | 13 | fs, |
diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/mark.rs index c3185e860..7c309a894 100644 --- a/crates/test_utils/src/marks.rs +++ b/crates/test_utils/src/mark.rs | |||
@@ -7,18 +7,18 @@ | |||
7 | //! ``` | 7 | //! ``` |
8 | //! #[test] | 8 | //! #[test] |
9 | //! fn test_foo() { | 9 | //! fn test_foo() { |
10 | //! covers!(test_foo); | 10 | //! mark::check!(test_foo); |
11 | //! } | 11 | //! } |
12 | //! ``` | 12 | //! ``` |
13 | //! | 13 | //! |
14 | //! and in the code under test you write | 14 | //! and in the code under test you write |
15 | //! | 15 | //! |
16 | //! ``` | 16 | //! ``` |
17 | //! # use test_utils::tested_by; | 17 | //! # use test_utils::mark; |
18 | //! # fn some_condition() -> bool { true } | 18 | //! # fn some_condition() -> bool { true } |
19 | //! fn foo() { | 19 | //! fn foo() { |
20 | //! if some_condition() { | 20 | //! if some_condition() { |
21 | //! tested_by!(test_foo); | 21 | //! mark::hit!(test_foo); |
22 | //! } | 22 | //! } |
23 | //! } | 23 | //! } |
24 | //! ``` | 24 | //! ``` |
@@ -29,43 +29,31 @@ | |||
29 | use std::sync::atomic::{AtomicUsize, Ordering}; | 29 | use std::sync::atomic::{AtomicUsize, Ordering}; |
30 | 30 | ||
31 | #[macro_export] | 31 | #[macro_export] |
32 | macro_rules! tested_by { | 32 | macro_rules! _hit { |
33 | ($ident:ident; force) => {{ | ||
34 | { | ||
35 | // sic! use call-site crate | ||
36 | crate::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); | ||
37 | } | ||
38 | }}; | ||
39 | ($ident:ident) => {{ | 33 | ($ident:ident) => {{ |
40 | #[cfg(test)] | 34 | #[cfg(test)] |
41 | { | 35 | { |
42 | // sic! use call-site crate | 36 | extern "C" { |
43 | crate::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); | 37 | #[no_mangle] |
38 | static $ident: std::sync::atomic::AtomicUsize; | ||
39 | } | ||
40 | unsafe { | ||
41 | $ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); | ||
42 | } | ||
44 | } | 43 | } |
45 | }}; | 44 | }}; |
46 | } | 45 | } |
46 | pub use _hit as hit; | ||
47 | 47 | ||
48 | #[macro_export] | 48 | #[macro_export] |
49 | macro_rules! covers { | 49 | macro_rules! _check { |
50 | // sic! use call-site crate | ||
51 | ($ident:ident) => { | 50 | ($ident:ident) => { |
52 | $crate::covers!(crate::$ident) | 51 | #[no_mangle] |
53 | }; | 52 | static $ident: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); |
54 | ($krate:ident :: $ident:ident) => { | 53 | let _checker = $crate::mark::MarkChecker::new(&$ident); |
55 | let _checker = $crate::marks::MarkChecker::new(&$krate::marks::$ident); | ||
56 | }; | ||
57 | } | ||
58 | |||
59 | #[macro_export] | ||
60 | macro_rules! marks { | ||
61 | ($($ident:ident)*) => { | ||
62 | $( | ||
63 | #[allow(bad_style)] | ||
64 | pub static $ident: std::sync::atomic::AtomicUsize = | ||
65 | std::sync::atomic::AtomicUsize::new(0); | ||
66 | )* | ||
67 | }; | 54 | }; |
68 | } | 55 | } |
56 | pub use _check as check; | ||
69 | 57 | ||
70 | pub struct MarkChecker { | 58 | pub struct MarkChecker { |
71 | mark: &'static AtomicUsize, | 59 | mark: &'static AtomicUsize, |