diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 45 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 1052 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_implementation.rs | 193 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 985 | ||||
-rw-r--r-- | crates/ra_ide/src/join_lines.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/mock_analysis.rs | 24 | ||||
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 1036 | ||||
-rw-r--r-- | crates/ra_ide/src/ssr.rs | 2 |
9 files changed, 1404 insertions, 1940 deletions
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 560fb19e6..ef22ea54d 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -213,7 +213,7 @@ impl<'a> CompletionContext<'a> { | |||
213 | } | 213 | } |
214 | } | 214 | } |
215 | 215 | ||
216 | pub(crate) fn scope(&self) -> SemanticsScope<'_, RootDatabase> { | 216 | pub(crate) fn scope(&self) -> SemanticsScope<'_> { |
217 | self.sema.scope_at_offset(&self.token.parent(), self.offset) | 217 | self.sema.scope_at_offset(&self.token.parent(), self.offset) |
218 | } | 218 | } |
219 | 219 | ||
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 0b52b01ab..8bf2428ed 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | TextRange, | 11 | TextRange, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{FileRange, FileSymbol}; | 14 | use crate::FileSymbol; |
15 | 15 | ||
16 | use super::short_label::ShortLabel; | 16 | use super::short_label::ShortLabel; |
17 | 17 | ||
@@ -47,6 +47,19 @@ impl NavigationTarget { | |||
47 | pub fn range(&self) -> TextRange { | 47 | pub fn range(&self) -> TextRange { |
48 | self.focus_range.unwrap_or(self.full_range) | 48 | self.focus_range.unwrap_or(self.full_range) |
49 | } | 49 | } |
50 | /// A "most interesting" range withing the `full_range`. | ||
51 | /// | ||
52 | /// Typically, `full_range` is the whole syntax node, | ||
53 | /// including doc comments, and `focus_range` is the range of the identifier. | ||
54 | pub fn focus_range(&self) -> Option<TextRange> { | ||
55 | self.focus_range | ||
56 | } | ||
57 | pub fn full_range(&self) -> TextRange { | ||
58 | self.full_range | ||
59 | } | ||
60 | pub fn file_id(&self) -> FileId { | ||
61 | self.file_id | ||
62 | } | ||
50 | 63 | ||
51 | pub fn name(&self) -> &SmolStr { | 64 | pub fn name(&self) -> &SmolStr { |
52 | &self.name | 65 | &self.name |
@@ -60,18 +73,6 @@ impl NavigationTarget { | |||
60 | self.kind | 73 | self.kind |
61 | } | 74 | } |
62 | 75 | ||
63 | pub fn file_id(&self) -> FileId { | ||
64 | self.file_id | ||
65 | } | ||
66 | |||
67 | pub fn file_range(&self) -> FileRange { | ||
68 | FileRange { file_id: self.file_id, range: self.full_range } | ||
69 | } | ||
70 | |||
71 | pub fn full_range(&self) -> TextRange { | ||
72 | self.full_range | ||
73 | } | ||
74 | |||
75 | pub fn docs(&self) -> Option<&str> { | 76 | pub fn docs(&self) -> Option<&str> { |
76 | self.docs.as_deref() | 77 | self.docs.as_deref() |
77 | } | 78 | } |
@@ -80,14 +81,6 @@ impl NavigationTarget { | |||
80 | self.description.as_deref() | 81 | self.description.as_deref() |
81 | } | 82 | } |
82 | 83 | ||
83 | /// A "most interesting" range withing the `full_range`. | ||
84 | /// | ||
85 | /// Typically, `full_range` is the whole syntax node, | ||
86 | /// including doc comments, and `focus_range` is the range of the identifier. | ||
87 | pub fn focus_range(&self) -> Option<TextRange> { | ||
88 | self.focus_range | ||
89 | } | ||
90 | |||
91 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 84 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
92 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 85 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
93 | if let Some(src) = module.declaration_source(db) { | 86 | if let Some(src) = module.declaration_source(db) { |
@@ -278,16 +271,22 @@ impl ToNav for hir::Module { | |||
278 | impl ToNav for hir::ImplDef { | 271 | impl ToNav for hir::ImplDef { |
279 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 272 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
280 | let src = self.source(db); | 273 | let src = self.source(db); |
281 | let frange = if let Some(item) = self.is_builtin_derive(db) { | 274 | let derive_attr = self.is_builtin_derive(db); |
275 | let frange = if let Some(item) = &derive_attr { | ||
282 | original_range(db, item.syntax()) | 276 | original_range(db, item.syntax()) |
283 | } else { | 277 | } else { |
284 | original_range(db, src.as_ref().map(|it| it.syntax())) | 278 | original_range(db, src.as_ref().map(|it| it.syntax())) |
285 | }; | 279 | }; |
280 | let focus_range = if derive_attr.is_some() { | ||
281 | None | ||
282 | } else { | ||
283 | src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range) | ||
284 | }; | ||
286 | 285 | ||
287 | NavigationTarget::from_syntax( | 286 | NavigationTarget::from_syntax( |
288 | frange.file_id, | 287 | frange.file_id, |
289 | "impl".into(), | 288 | "impl".into(), |
290 | None, | 289 | focus_range, |
291 | frange.range, | 290 | frange.range, |
292 | src.value.syntax().kind(), | 291 | src.value.syntax().kind(), |
293 | ) | 292 | ) |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index bea7fbfa7..4c78fa214 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -103,205 +103,149 @@ pub(crate) fn reference_definition( | |||
103 | 103 | ||
104 | #[cfg(test)] | 104 | #[cfg(test)] |
105 | mod tests { | 105 | mod tests { |
106 | use test_utils::assert_eq_text; | 106 | use ra_db::FileRange; |
107 | 107 | use ra_syntax::{TextRange, TextSize}; | |
108 | use crate::mock_analysis::analysis_and_position; | 108 | |
109 | 109 | use crate::mock_analysis::MockAnalysis; | |
110 | fn check_goto(ra_fixture: &str, expected: &str, expected_range: &str) { | 110 | |
111 | let (analysis, pos) = analysis_and_position(ra_fixture); | 111 | fn check(ra_fixture: &str) { |
112 | let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture); | ||
113 | let (mut expected, data) = mock.annotation(); | ||
114 | let analysis = mock.analysis(); | ||
115 | match data.as_str() { | ||
116 | "" => (), | ||
117 | "file" => { | ||
118 | expected.range = | ||
119 | TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap())) | ||
120 | } | ||
121 | data => panic!("bad data: {}", data), | ||
122 | } | ||
112 | 123 | ||
113 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | 124 | let mut navs = analysis.goto_definition(position).unwrap().unwrap().info; |
114 | if navs.len() == 0 { | 125 | if navs.len() == 0 { |
115 | panic!("unresolved reference") | 126 | panic!("unresolved reference") |
116 | } | 127 | } |
117 | assert_eq!(navs.len(), 1); | 128 | assert_eq!(navs.len(), 1); |
118 | 129 | ||
119 | let nav = navs.pop().unwrap(); | 130 | let nav = navs.pop().unwrap(); |
120 | let file_text = analysis.file_text(nav.file_id()).unwrap(); | 131 | assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() }); |
121 | |||
122 | let mut actual = file_text[nav.full_range()].to_string(); | ||
123 | if let Some(focus) = nav.focus_range() { | ||
124 | actual += "|"; | ||
125 | actual += &file_text[focus]; | ||
126 | } | ||
127 | |||
128 | if !expected_range.contains("...") { | ||
129 | test_utils::assert_eq_text!(&actual, expected_range); | ||
130 | } else { | ||
131 | let mut parts = expected_range.split("..."); | ||
132 | let prefix = parts.next().unwrap(); | ||
133 | let suffix = parts.next().unwrap(); | ||
134 | assert!( | ||
135 | actual.starts_with(prefix) && actual.ends_with(suffix), | ||
136 | "\nExpected: {}\n Actual: {}\n", | ||
137 | expected_range, | ||
138 | actual | ||
139 | ); | ||
140 | } | ||
141 | |||
142 | nav.assert_match(expected); | ||
143 | } | 132 | } |
144 | 133 | ||
145 | #[test] | 134 | #[test] |
146 | fn goto_def_in_items() { | 135 | fn goto_def_in_items() { |
147 | check_goto( | 136 | check( |
148 | " | 137 | r#" |
149 | //- /lib.rs | 138 | struct Foo; |
150 | struct Foo; | 139 | //^^^ |
151 | enum E { X(Foo<|>) } | 140 | enum E { X(Foo<|>) } |
152 | ", | 141 | "#, |
153 | "Foo STRUCT_DEF FileId(1) 0..11 7..10", | ||
154 | "struct Foo;|Foo", | ||
155 | ); | 142 | ); |
156 | } | 143 | } |
157 | 144 | ||
158 | #[test] | 145 | #[test] |
159 | fn goto_def_at_start_of_item() { | 146 | fn goto_def_at_start_of_item() { |
160 | check_goto( | 147 | check( |
161 | " | 148 | r#" |
162 | //- /lib.rs | 149 | struct Foo; |
163 | struct Foo; | 150 | //^^^ |
164 | enum E { X(<|>Foo) } | 151 | enum E { X(<|>Foo) } |
165 | ", | 152 | "#, |
166 | "Foo STRUCT_DEF FileId(1) 0..11 7..10", | ||
167 | "struct Foo;|Foo", | ||
168 | ); | 153 | ); |
169 | } | 154 | } |
170 | 155 | ||
171 | #[test] | 156 | #[test] |
172 | fn goto_definition_resolves_correct_name() { | 157 | fn goto_definition_resolves_correct_name() { |
173 | check_goto( | 158 | check( |
174 | " | 159 | r#" |
175 | //- /lib.rs | 160 | //- /lib.rs |
176 | use a::Foo; | 161 | use a::Foo; |
177 | mod a; | 162 | mod a; |
178 | mod b; | 163 | mod b; |
179 | enum E { X(Foo<|>) } | 164 | enum E { X(Foo<|>) } |
180 | 165 | ||
181 | //- /a.rs | 166 | //- /a.rs |
182 | struct Foo; | 167 | struct Foo; |
183 | 168 | //^^^ | |
184 | //- /b.rs | 169 | //- /b.rs |
185 | struct Foo; | 170 | struct Foo; |
186 | ", | 171 | "#, |
187 | "Foo STRUCT_DEF FileId(2) 0..11 7..10", | ||
188 | "struct Foo;|Foo", | ||
189 | ); | 172 | ); |
190 | } | 173 | } |
191 | 174 | ||
192 | #[test] | 175 | #[test] |
193 | fn goto_def_for_module_declaration() { | 176 | fn goto_def_for_module_declaration() { |
194 | check_goto( | 177 | check( |
195 | r#" | 178 | r#" |
196 | //- /lib.rs | 179 | //- /lib.rs |
197 | mod <|>foo; | 180 | mod <|>foo; |
198 | 181 | ||
199 | //- /foo.rs | 182 | //- /foo.rs |
200 | // empty | 183 | // empty |
184 | //^ file | ||
201 | "#, | 185 | "#, |
202 | "foo SOURCE_FILE FileId(2) 0..9", | ||
203 | "// empty\n", | ||
204 | ); | 186 | ); |
205 | 187 | ||
206 | check_goto( | 188 | check( |
207 | r#" | 189 | r#" |
208 | //- /lib.rs | 190 | //- /lib.rs |
209 | mod <|>foo; | 191 | mod <|>foo; |
210 | 192 | ||
211 | //- /foo/mod.rs | 193 | //- /foo/mod.rs |
212 | // empty | 194 | // empty |
195 | //^ file | ||
213 | "#, | 196 | "#, |
214 | "foo SOURCE_FILE FileId(2) 0..9", | ||
215 | "// empty\n", | ||
216 | ); | 197 | ); |
217 | } | 198 | } |
218 | 199 | ||
219 | #[test] | 200 | #[test] |
220 | fn goto_def_for_macros() { | 201 | fn goto_def_for_macros() { |
221 | check_goto( | 202 | check( |
222 | " | 203 | r#" |
223 | //- /lib.rs | 204 | macro_rules! foo { () => { () } } |
224 | macro_rules! foo { () => { () } } | 205 | //^^^ |
225 | 206 | fn bar() { | |
226 | fn bar() { | 207 | <|>foo!(); |
227 | <|>foo!(); | 208 | } |
228 | } | 209 | "#, |
229 | ", | ||
230 | "foo MACRO_CALL FileId(1) 0..33 13..16", | ||
231 | "macro_rules! foo { () => { () } }|foo", | ||
232 | ); | 210 | ); |
233 | } | 211 | } |
234 | 212 | ||
235 | #[test] | 213 | #[test] |
236 | fn goto_def_for_macros_from_other_crates() { | 214 | fn goto_def_for_macros_from_other_crates() { |
237 | check_goto( | 215 | check( |
238 | " | ||
239 | //- /lib.rs | ||
240 | use foo::foo; | ||
241 | fn bar() { | ||
242 | <|>foo!(); | ||
243 | } | ||
244 | |||
245 | //- /foo/lib.rs | ||
246 | #[macro_export] | ||
247 | macro_rules! foo { () => { () } } | ||
248 | ", | ||
249 | "foo MACRO_CALL FileId(2) 0..49 29..32", | ||
250 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
251 | ); | ||
252 | } | ||
253 | |||
254 | #[test] | ||
255 | fn goto_def_for_use_alias() { | ||
256 | check_goto( | ||
257 | r#" | 216 | r#" |
258 | //- /lib.rs | 217 | //- /lib.rs |
259 | use foo as bar<|>; | 218 | use foo::foo; |
219 | fn bar() { | ||
220 | <|>foo!(); | ||
221 | } | ||
260 | 222 | ||
261 | //- /foo/lib.rs | 223 | //- /foo/lib.rs |
262 | #[macro_export] | 224 | #[macro_export] |
263 | macro_rules! foo { () => { () } } | 225 | macro_rules! foo { () => { () } } |
226 | //^^^ | ||
264 | "#, | 227 | "#, |
265 | "SOURCE_FILE FileId(2) 0..50", | ||
266 | "#[macro_export]\nmacro_rules! foo { () => { () } }\n", | ||
267 | ); | ||
268 | } | ||
269 | |||
270 | #[test] | ||
271 | fn goto_def_for_use_alias_foo_macro() { | ||
272 | check_goto( | ||
273 | " | ||
274 | //- /lib.rs | ||
275 | use foo::foo as bar<|>; | ||
276 | |||
277 | //- /foo/lib.rs | ||
278 | #[macro_export] | ||
279 | macro_rules! foo { () => { () } } | ||
280 | ", | ||
281 | "foo MACRO_CALL FileId(2) 0..49 29..32", | ||
282 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
283 | ); | 228 | ); |
284 | } | 229 | } |
285 | 230 | ||
286 | #[test] | 231 | #[test] |
287 | fn goto_def_for_macros_in_use_tree() { | 232 | fn goto_def_for_macros_in_use_tree() { |
288 | check_goto( | 233 | check( |
289 | " | 234 | r#" |
290 | //- /lib.rs | 235 | //- /lib.rs |
291 | use foo::foo<|>; | 236 | use foo::foo<|>; |
292 | 237 | ||
293 | //- /foo/lib.rs | 238 | //- /foo/lib.rs |
294 | #[macro_export] | 239 | #[macro_export] |
295 | macro_rules! foo { () => { () } } | 240 | macro_rules! foo { () => { () } } |
296 | ", | 241 | //^^^ |
297 | "foo MACRO_CALL FileId(2) 0..49 29..32", | 242 | "#, |
298 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
299 | ); | 243 | ); |
300 | } | 244 | } |
301 | 245 | ||
302 | #[test] | 246 | #[test] |
303 | fn goto_def_for_macro_defined_fn_with_arg() { | 247 | fn goto_def_for_macro_defined_fn_with_arg() { |
304 | check_goto( | 248 | check( |
305 | r#" | 249 | r#" |
306 | //- /lib.rs | 250 | //- /lib.rs |
307 | macro_rules! define_fn { | 251 | macro_rules! define_fn { |
@@ -309,522 +253,478 @@ macro_rules! define_fn { | |||
309 | } | 253 | } |
310 | 254 | ||
311 | define_fn!(foo); | 255 | define_fn!(foo); |
256 | //^^^ | ||
312 | 257 | ||
313 | fn bar() { | 258 | fn bar() { |
314 | <|>foo(); | 259 | <|>foo(); |
315 | } | 260 | } |
316 | "#, | 261 | "#, |
317 | "foo FN_DEF FileId(1) 65..81 76..79", | ||
318 | "define_fn!(foo);|foo", | ||
319 | ); | 262 | ); |
320 | } | 263 | } |
321 | 264 | ||
322 | #[test] | 265 | #[test] |
323 | fn goto_def_for_macro_defined_fn_no_arg() { | 266 | fn goto_def_for_macro_defined_fn_no_arg() { |
324 | check_goto( | 267 | check( |
325 | r#" | 268 | r#" |
326 | //- /lib.rs | 269 | //- /lib.rs |
327 | macro_rules! define_fn { | 270 | macro_rules! define_fn { |
328 | () => (fn foo() {}) | 271 | () => (fn foo() {}) |
329 | } | 272 | } |
330 | 273 | ||
331 | define_fn!(); | 274 | define_fn!(); |
275 | //^^^^^^^^^^^^^ | ||
332 | 276 | ||
333 | fn bar() { | 277 | fn bar() { |
334 | <|>foo(); | 278 | <|>foo(); |
335 | } | 279 | } |
336 | "#, | 280 | "#, |
337 | "foo FN_DEF FileId(1) 52..65 52..65", | ||
338 | "define_fn!();|define_fn!();", | ||
339 | ); | 281 | ); |
340 | } | 282 | } |
341 | 283 | ||
342 | #[test] | 284 | #[test] |
343 | fn goto_definition_works_for_macro_inside_pattern() { | 285 | fn goto_definition_works_for_macro_inside_pattern() { |
344 | check_goto( | 286 | check( |
345 | " | 287 | r#" |
346 | //- /lib.rs | 288 | //- /lib.rs |
347 | macro_rules! foo {() => {0}} | 289 | macro_rules! foo {() => {0}} |
348 | 290 | //^^^ | |
349 | fn bar() { | 291 | |
350 | match (0,1) { | 292 | fn bar() { |
351 | (<|>foo!(), _) => {} | 293 | match (0,1) { |
352 | } | 294 | (<|>foo!(), _) => {} |
353 | } | 295 | } |
354 | ", | 296 | } |
355 | "foo MACRO_CALL FileId(1) 0..28 13..16", | 297 | "#, |
356 | "macro_rules! foo {() => {0}}|foo", | ||
357 | ); | 298 | ); |
358 | } | 299 | } |
359 | 300 | ||
360 | #[test] | 301 | #[test] |
361 | fn goto_definition_works_for_macro_inside_match_arm_lhs() { | 302 | fn goto_definition_works_for_macro_inside_match_arm_lhs() { |
362 | check_goto( | 303 | check( |
363 | " | 304 | r#" |
364 | //- /lib.rs | 305 | //- /lib.rs |
365 | macro_rules! foo {() => {0}} | 306 | macro_rules! foo {() => {0}} |
366 | 307 | //^^^ | |
367 | fn bar() { | 308 | fn bar() { |
368 | match 0 { | 309 | match 0 { |
369 | <|>foo!() => {} | 310 | <|>foo!() => {} |
370 | } | 311 | } |
371 | } | 312 | } |
372 | ", | 313 | "#, |
373 | "foo MACRO_CALL FileId(1) 0..28 13..16", | 314 | ); |
374 | "macro_rules! foo {() => {0}}|foo", | 315 | } |
316 | |||
317 | #[test] | ||
318 | fn goto_def_for_use_alias() { | ||
319 | check( | ||
320 | r#" | ||
321 | //- /lib.rs | ||
322 | use foo as bar<|>; | ||
323 | |||
324 | //- /foo/lib.rs | ||
325 | // empty | ||
326 | //^ file | ||
327 | "#, | ||
328 | ); | ||
329 | } | ||
330 | |||
331 | #[test] | ||
332 | fn goto_def_for_use_alias_foo_macro() { | ||
333 | check( | ||
334 | r#" | ||
335 | //- /lib.rs | ||
336 | use foo::foo as bar<|>; | ||
337 | |||
338 | //- /foo/lib.rs | ||
339 | #[macro_export] | ||
340 | macro_rules! foo { () => { () } } | ||
341 | //^^^ | ||
342 | "#, | ||
375 | ); | 343 | ); |
376 | } | 344 | } |
377 | 345 | ||
378 | #[test] | 346 | #[test] |
379 | fn goto_def_for_methods() { | 347 | fn goto_def_for_methods() { |
380 | check_goto( | 348 | check( |
381 | " | 349 | r#" |
382 | //- /lib.rs | 350 | //- /lib.rs |
383 | struct Foo; | 351 | struct Foo; |
384 | impl Foo { | 352 | impl Foo { |
385 | fn frobnicate(&self) { } | 353 | fn frobnicate(&self) { } |
386 | } | 354 | //^^^^^^^^^^ |
355 | } | ||
387 | 356 | ||
388 | fn bar(foo: &Foo) { | 357 | fn bar(foo: &Foo) { |
389 | foo.frobnicate<|>(); | 358 | foo.frobnicate<|>(); |
390 | } | 359 | } |
391 | ", | 360 | "#, |
392 | "frobnicate FN_DEF FileId(1) 27..51 30..40", | ||
393 | "fn frobnicate(&self) { }|frobnicate", | ||
394 | ); | 361 | ); |
395 | } | 362 | } |
396 | 363 | ||
397 | #[test] | 364 | #[test] |
398 | fn goto_def_for_fields() { | 365 | fn goto_def_for_fields() { |
399 | check_goto( | 366 | check( |
400 | r" | 367 | r#" |
401 | //- /lib.rs | 368 | struct Foo { |
402 | struct Foo { | 369 | spam: u32, |
403 | spam: u32, | 370 | } //^^^^ |
404 | } | ||
405 | 371 | ||
406 | fn bar(foo: &Foo) { | 372 | fn bar(foo: &Foo) { |
407 | foo.spam<|>; | 373 | foo.spam<|>; |
408 | } | 374 | } |
409 | ", | 375 | "#, |
410 | "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21", | ||
411 | "spam: u32|spam", | ||
412 | ); | 376 | ); |
413 | } | 377 | } |
414 | 378 | ||
415 | #[test] | 379 | #[test] |
416 | fn goto_def_for_record_fields() { | 380 | fn goto_def_for_record_fields() { |
417 | check_goto( | 381 | check( |
418 | r" | 382 | r#" |
419 | //- /lib.rs | 383 | //- /lib.rs |
420 | struct Foo { | 384 | struct Foo { |
421 | spam: u32, | 385 | spam: u32, |
422 | } | 386 | } //^^^^ |
423 | 387 | ||
424 | fn bar() -> Foo { | 388 | fn bar() -> Foo { |
425 | Foo { | 389 | Foo { |
426 | spam<|>: 0, | 390 | spam<|>: 0, |
427 | } | 391 | } |
428 | } | 392 | } |
429 | ", | 393 | "#, |
430 | "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21", | ||
431 | "spam: u32|spam", | ||
432 | ); | 394 | ); |
433 | } | 395 | } |
434 | 396 | ||
435 | #[test] | 397 | #[test] |
436 | fn goto_def_for_record_pat_fields() { | 398 | fn goto_def_for_record_pat_fields() { |
437 | check_goto( | 399 | check( |
438 | r" | 400 | r#" |
439 | //- /lib.rs | 401 | //- /lib.rs |
440 | struct Foo { | 402 | struct Foo { |
441 | spam: u32, | 403 | spam: u32, |
442 | } | 404 | } //^^^^ |
443 | 405 | ||
444 | fn bar(foo: Foo) -> Foo { | 406 | fn bar(foo: Foo) -> Foo { |
445 | let Foo { spam<|>: _, } = foo | 407 | let Foo { spam<|>: _, } = foo |
446 | } | 408 | } |
447 | ", | 409 | "#, |
448 | "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21", | ||
449 | "spam: u32|spam", | ||
450 | ); | 410 | ); |
451 | } | 411 | } |
452 | 412 | ||
453 | #[test] | 413 | #[test] |
454 | fn goto_def_for_record_fields_macros() { | 414 | fn goto_def_for_record_fields_macros() { |
455 | check_goto( | 415 | check( |
456 | r" | 416 | r" |
457 | //- /lib.rs | 417 | macro_rules! m { () => { 92 };} |
458 | macro_rules! m { () => { 92 };} | 418 | struct Foo { spam: u32 } |
459 | struct Foo { spam: u32 } | 419 | //^^^^ |
460 | 420 | ||
461 | fn bar() -> Foo { | 421 | fn bar() -> Foo { |
462 | Foo { spam<|>: m!() } | 422 | Foo { spam<|>: m!() } |
463 | } | 423 | } |
464 | ", | 424 | ", |
465 | "spam RECORD_FIELD_DEF FileId(1) 45..54 45..49", | ||
466 | "spam: u32|spam", | ||
467 | ); | 425 | ); |
468 | } | 426 | } |
469 | 427 | ||
470 | #[test] | 428 | #[test] |
471 | fn goto_for_tuple_fields() { | 429 | fn goto_for_tuple_fields() { |
472 | check_goto( | 430 | check( |
473 | " | 431 | r#" |
474 | //- /lib.rs | 432 | struct Foo(u32); |
475 | struct Foo(u32); | 433 | //^^^ |
476 | 434 | ||
477 | fn bar() { | 435 | fn bar() { |
478 | let foo = Foo(0); | 436 | let foo = Foo(0); |
479 | foo.<|>0; | 437 | foo.<|>0; |
480 | } | 438 | } |
481 | ", | 439 | "#, |
482 | "TUPLE_FIELD_DEF FileId(1) 11..14", | ||
483 | "u32", | ||
484 | ); | 440 | ); |
485 | } | 441 | } |
486 | 442 | ||
487 | #[test] | 443 | #[test] |
488 | fn goto_def_for_ufcs_inherent_methods() { | 444 | fn goto_def_for_ufcs_inherent_methods() { |
489 | check_goto( | 445 | check( |
490 | " | 446 | r#" |
491 | //- /lib.rs | 447 | struct Foo; |
492 | struct Foo; | 448 | impl Foo { |
493 | impl Foo { | 449 | fn frobnicate() { } |
494 | fn frobnicate() { } | 450 | } //^^^^^^^^^^ |
495 | } | ||
496 | 451 | ||
497 | fn bar(foo: &Foo) { | 452 | fn bar(foo: &Foo) { |
498 | Foo::frobnicate<|>(); | 453 | Foo::frobnicate<|>(); |
499 | } | 454 | } |
500 | ", | 455 | "#, |
501 | "frobnicate FN_DEF FileId(1) 27..46 30..40", | ||
502 | "fn frobnicate() { }|frobnicate", | ||
503 | ); | 456 | ); |
504 | } | 457 | } |
505 | 458 | ||
506 | #[test] | 459 | #[test] |
507 | fn goto_def_for_ufcs_trait_methods_through_traits() { | 460 | fn goto_def_for_ufcs_trait_methods_through_traits() { |
508 | check_goto( | 461 | check( |
509 | " | 462 | r#" |
510 | //- /lib.rs | 463 | trait Foo { |
511 | trait Foo { | 464 | fn frobnicate(); |
512 | fn frobnicate(); | 465 | } //^^^^^^^^^^ |
513 | } | ||
514 | 466 | ||
515 | fn bar() { | 467 | fn bar() { |
516 | Foo::frobnicate<|>(); | 468 | Foo::frobnicate<|>(); |
517 | } | 469 | } |
518 | ", | 470 | "#, |
519 | "frobnicate FN_DEF FileId(1) 16..32 19..29", | ||
520 | "fn frobnicate();|frobnicate", | ||
521 | ); | 471 | ); |
522 | } | 472 | } |
523 | 473 | ||
524 | #[test] | 474 | #[test] |
525 | fn goto_def_for_ufcs_trait_methods_through_self() { | 475 | fn goto_def_for_ufcs_trait_methods_through_self() { |
526 | check_goto( | 476 | check( |
527 | " | 477 | r#" |
528 | //- /lib.rs | 478 | struct Foo; |
529 | struct Foo; | 479 | trait Trait { |
530 | trait Trait { | 480 | fn frobnicate(); |
531 | fn frobnicate(); | 481 | } //^^^^^^^^^^ |
532 | } | 482 | impl Trait for Foo {} |
533 | impl Trait for Foo {} | ||
534 | 483 | ||
535 | fn bar() { | 484 | fn bar() { |
536 | Foo::frobnicate<|>(); | 485 | Foo::frobnicate<|>(); |
537 | } | 486 | } |
538 | ", | 487 | "#, |
539 | "frobnicate FN_DEF FileId(1) 30..46 33..43", | ||
540 | "fn frobnicate();|frobnicate", | ||
541 | ); | 488 | ); |
542 | } | 489 | } |
543 | 490 | ||
544 | #[test] | 491 | #[test] |
545 | fn goto_definition_on_self() { | 492 | fn goto_definition_on_self() { |
546 | check_goto( | 493 | check( |
547 | " | 494 | r#" |
548 | //- /lib.rs | 495 | struct Foo; |
549 | struct Foo; | 496 | impl Foo { |
550 | impl Foo { | 497 | //^^^ |
551 | pub fn new() -> Self { | 498 | pub fn new() -> Self { |
552 | Self<|> {} | 499 | Self<|> {} |
553 | } | 500 | } |
554 | } | 501 | } |
555 | ", | 502 | "#, |
556 | "impl IMPL_DEF FileId(1) 12..73", | 503 | ); |
557 | "impl Foo {...}", | 504 | check( |
558 | ); | 505 | r#" |
559 | 506 | struct Foo; | |
560 | check_goto( | 507 | impl Foo { |
561 | " | 508 | //^^^ |
562 | //- /lib.rs | 509 | pub fn new() -> Self<|> { |
563 | struct Foo; | 510 | Self {} |
564 | impl Foo { | 511 | } |
565 | pub fn new() -> Self<|> { | 512 | } |
566 | Self {} | 513 | "#, |
567 | } | 514 | ); |
568 | } | 515 | |
569 | ", | 516 | check( |
570 | "impl IMPL_DEF FileId(1) 12..73", | 517 | r#" |
571 | "impl Foo {...}", | 518 | enum Foo { A } |
572 | ); | 519 | impl Foo { |
573 | 520 | //^^^ | |
574 | check_goto( | 521 | pub fn new() -> Self<|> { |
575 | " | 522 | Foo::A |
576 | //- /lib.rs | 523 | } |
577 | enum Foo { A } | 524 | } |
578 | impl Foo { | 525 | "#, |
579 | pub fn new() -> Self<|> { | 526 | ); |
580 | Foo::A | 527 | |
581 | } | 528 | check( |
582 | } | 529 | r#" |
583 | ", | 530 | enum Foo { A } |
584 | "impl IMPL_DEF FileId(1) 15..75", | 531 | impl Foo { |
585 | "impl Foo {...}", | 532 | //^^^ |
586 | ); | 533 | pub fn thing(a: &Self<|>) { |
587 | 534 | } | |
588 | check_goto( | 535 | } |
589 | " | 536 | "#, |
590 | //- /lib.rs | ||
591 | enum Foo { A } | ||
592 | impl Foo { | ||
593 | pub fn thing(a: &Self<|>) { | ||
594 | } | ||
595 | } | ||
596 | ", | ||
597 | "impl IMPL_DEF FileId(1) 15..62", | ||
598 | "impl Foo {...}", | ||
599 | ); | 537 | ); |
600 | } | 538 | } |
601 | 539 | ||
602 | #[test] | 540 | #[test] |
603 | fn goto_definition_on_self_in_trait_impl() { | 541 | fn goto_definition_on_self_in_trait_impl() { |
604 | check_goto( | 542 | check( |
605 | " | 543 | r#" |
606 | //- /lib.rs | 544 | struct Foo; |
607 | struct Foo; | 545 | trait Make { |
608 | trait Make { | 546 | fn new() -> Self; |
609 | fn new() -> Self; | 547 | } |
610 | } | 548 | impl Make for Foo { |
611 | impl Make for Foo { | 549 | //^^^ |
612 | fn new() -> Self { | 550 | fn new() -> Self { |
613 | Self<|> {} | 551 | Self<|> {} |
614 | } | 552 | } |
615 | } | 553 | } |
616 | ", | 554 | "#, |
617 | "impl IMPL_DEF FileId(1) 49..115", | ||
618 | "impl Make for Foo {...}", | ||
619 | ); | 555 | ); |
620 | 556 | ||
621 | check_goto( | 557 | check( |
622 | " | 558 | r#" |
623 | //- /lib.rs | 559 | struct Foo; |
624 | struct Foo; | 560 | trait Make { |
625 | trait Make { | 561 | fn new() -> Self; |
626 | fn new() -> Self; | 562 | } |
627 | } | 563 | impl Make for Foo { |
628 | impl Make for Foo { | 564 | //^^^ |
629 | fn new() -> Self<|> { | 565 | fn new() -> Self<|> { |
630 | Self {} | 566 | Self {} |
631 | } | 567 | } |
632 | } | 568 | } |
633 | ", | 569 | "#, |
634 | "impl IMPL_DEF FileId(1) 49..115", | ||
635 | "impl Make for Foo {...}", | ||
636 | ); | 570 | ); |
637 | } | 571 | } |
638 | 572 | ||
639 | #[test] | 573 | #[test] |
640 | fn goto_def_when_used_on_definition_name_itself() { | 574 | fn goto_def_when_used_on_definition_name_itself() { |
641 | check_goto( | 575 | check( |
642 | " | 576 | r#" |
643 | //- /lib.rs | 577 | struct Foo<|> { value: u32 } |
644 | struct Foo<|> { value: u32 } | 578 | //^^^ |
645 | ", | 579 | "#, |
646 | "Foo STRUCT_DEF FileId(1) 0..25 7..10", | ||
647 | "struct Foo { value: u32 }|Foo", | ||
648 | ); | 580 | ); |
649 | 581 | ||
650 | check_goto( | 582 | check( |
651 | r#" | 583 | r#" |
652 | //- /lib.rs | 584 | struct Foo { |
653 | struct Foo { | 585 | field<|>: string, |
654 | field<|>: string, | 586 | } //^^^^^ |
655 | } | 587 | "#, |
656 | "#, | ||
657 | "field RECORD_FIELD_DEF FileId(1) 17..30 17..22", | ||
658 | "field: string|field", | ||
659 | ); | 588 | ); |
660 | 589 | ||
661 | check_goto( | 590 | check( |
662 | " | 591 | r#" |
663 | //- /lib.rs | 592 | fn foo_test<|>() { } |
664 | fn foo_test<|>() { } | 593 | //^^^^^^^^ |
665 | ", | 594 | "#, |
666 | "foo_test FN_DEF FileId(1) 0..17 3..11", | ||
667 | "fn foo_test() { }|foo_test", | ||
668 | ); | 595 | ); |
669 | 596 | ||
670 | check_goto( | 597 | check( |
671 | " | 598 | r#" |
672 | //- /lib.rs | 599 | enum Foo<|> { Variant } |
673 | enum Foo<|> { | 600 | //^^^ |
674 | Variant, | 601 | "#, |
675 | } | ||
676 | ", | ||
677 | "Foo ENUM_DEF FileId(1) 0..25 5..8", | ||
678 | "enum Foo {...}|Foo", | ||
679 | ); | ||
680 | |||
681 | check_goto( | ||
682 | " | ||
683 | //- /lib.rs | ||
684 | enum Foo { | ||
685 | Variant1, | ||
686 | Variant2<|>, | ||
687 | Variant3, | ||
688 | } | ||
689 | ", | ||
690 | "Variant2 ENUM_VARIANT FileId(1) 29..37 29..37", | ||
691 | "Variant2|Variant2", | ||
692 | ); | 602 | ); |
693 | 603 | ||
694 | check_goto( | 604 | check( |
695 | r#" | 605 | r#" |
696 | //- /lib.rs | 606 | enum Foo { |
697 | static INNER<|>: &str = ""; | 607 | Variant1, |
698 | "#, | 608 | Variant2<|>, |
699 | "INNER STATIC_DEF FileId(1) 0..24 7..12", | 609 | //^^^^^^^^ |
700 | "static INNER: &str = \"\";|INNER", | 610 | Variant3, |
611 | } | ||
612 | "#, | ||
701 | ); | 613 | ); |
702 | 614 | ||
703 | check_goto( | 615 | check( |
704 | r#" | 616 | r#" |
705 | //- /lib.rs | 617 | static INNER<|>: &str = ""; |
706 | const INNER<|>: &str = ""; | 618 | //^^^^^ |
707 | "#, | 619 | "#, |
708 | "INNER CONST_DEF FileId(1) 0..23 6..11", | ||
709 | "const INNER: &str = \"\";|INNER", | ||
710 | ); | 620 | ); |
711 | 621 | ||
712 | check_goto( | 622 | check( |
713 | r#" | 623 | r#" |
714 | //- /lib.rs | 624 | const INNER<|>: &str = ""; |
715 | type Thing<|> = Option<()>; | 625 | //^^^^^ |
716 | "#, | 626 | "#, |
717 | "Thing TYPE_ALIAS_DEF FileId(1) 0..24 5..10", | ||
718 | "type Thing = Option<()>;|Thing", | ||
719 | ); | 627 | ); |
720 | 628 | ||
721 | check_goto( | 629 | check( |
722 | r#" | 630 | r#" |
723 | //- /lib.rs | 631 | type Thing<|> = Option<()>; |
724 | trait Foo<|> { } | 632 | //^^^^^ |
725 | "#, | 633 | "#, |
726 | "Foo TRAIT_DEF FileId(1) 0..13 6..9", | ||
727 | "trait Foo { }|Foo", | ||
728 | ); | 634 | ); |
729 | 635 | ||
730 | check_goto( | 636 | check( |
731 | r#" | 637 | r#" |
732 | //- /lib.rs | 638 | trait Foo<|> { } |
733 | mod bar<|> { } | 639 | //^^^ |
734 | "#, | 640 | "#, |
735 | "bar MODULE FileId(1) 0..11 4..7", | 641 | ); |
736 | "mod bar { }|bar", | 642 | |
643 | check( | ||
644 | r#" | ||
645 | mod bar<|> { } | ||
646 | //^^^ | ||
647 | "#, | ||
737 | ); | 648 | ); |
738 | } | 649 | } |
739 | 650 | ||
740 | #[test] | 651 | #[test] |
741 | fn goto_from_macro() { | 652 | fn goto_from_macro() { |
742 | check_goto( | 653 | check( |
743 | " | 654 | r#" |
744 | //- /lib.rs | 655 | macro_rules! id { |
745 | macro_rules! id { | 656 | ($($tt:tt)*) => { $($tt)* } |
746 | ($($tt:tt)*) => { $($tt)* } | 657 | } |
747 | } | 658 | fn foo() {} |
748 | fn foo() {} | 659 | //^^^ |
749 | id! { | 660 | id! { |
750 | fn bar() { | 661 | fn bar() { |
751 | fo<|>o(); | 662 | fo<|>o(); |
752 | } | 663 | } |
753 | } | 664 | } |
754 | mod confuse_index { fn foo(); } | 665 | mod confuse_index { fn foo(); } |
755 | ", | 666 | "#, |
756 | "foo FN_DEF FileId(1) 52..63 55..58", | ||
757 | "fn foo() {}|foo", | ||
758 | ); | 667 | ); |
759 | } | 668 | } |
760 | 669 | ||
761 | #[test] | 670 | #[test] |
762 | fn goto_through_format() { | 671 | fn goto_through_format() { |
763 | check_goto( | 672 | check( |
764 | " | 673 | r#" |
765 | //- /lib.rs | 674 | #[macro_export] |
766 | #[macro_export] | 675 | macro_rules! format { |
767 | macro_rules! format { | 676 | ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) |
768 | ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) | 677 | } |
769 | } | 678 | #[rustc_builtin_macro] |
770 | #[rustc_builtin_macro] | 679 | #[macro_export] |
771 | #[macro_export] | 680 | macro_rules! format_args { |
772 | macro_rules! format_args { | 681 | ($fmt:expr) => ({ /* compiler built-in */ }); |
773 | ($fmt:expr) => ({ /* compiler built-in */ }); | 682 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) |
774 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) | 683 | } |
775 | } | 684 | pub mod __export { |
776 | pub mod __export { | 685 | pub use crate::format_args; |
777 | pub use crate::format_args; | 686 | fn foo() {} // for index confusion |
778 | fn foo() {} // for index confusion | 687 | } |
779 | } | 688 | fn foo() -> i8 {} |
780 | fn foo() -> i8 {} | 689 | //^^^ |
781 | fn test() { | 690 | fn test() { |
782 | format!(\"{}\", fo<|>o()) | 691 | format!("{}", fo<|>o()) |
783 | } | 692 | } |
784 | ", | 693 | "#, |
785 | "foo FN_DEF FileId(1) 398..415 401..404", | ||
786 | "fn foo() -> i8 {}|foo", | ||
787 | ); | 694 | ); |
788 | } | 695 | } |
789 | 696 | ||
790 | #[test] | 697 | #[test] |
791 | fn goto_for_type_param() { | 698 | fn goto_for_type_param() { |
792 | check_goto( | 699 | check( |
793 | r#" | 700 | r#" |
794 | //- /lib.rs | 701 | struct Foo<T: Clone> { t: <|>T } |
795 | struct Foo<T: Clone> { | 702 | //^ |
796 | t: <|>T, | 703 | "#, |
797 | } | ||
798 | "#, | ||
799 | "T TYPE_PARAM FileId(1) 11..19 11..12", | ||
800 | "T: Clone|T", | ||
801 | ); | 704 | ); |
802 | } | 705 | } |
803 | 706 | ||
804 | #[test] | 707 | #[test] |
805 | fn goto_within_macro() { | 708 | fn goto_within_macro() { |
806 | check_goto( | 709 | check( |
807 | r#" | 710 | r#" |
808 | //- /lib.rs | ||
809 | macro_rules! id { | 711 | macro_rules! id { |
810 | ($($tt:tt)*) => ($($tt)*) | 712 | ($($tt:tt)*) => ($($tt)*) |
811 | } | 713 | } |
812 | 714 | ||
813 | fn foo() { | 715 | fn foo() { |
814 | let x = 1; | 716 | let x = 1; |
717 | //^ | ||
815 | id!({ | 718 | id!({ |
816 | let y = <|>x; | 719 | let y = <|>x; |
817 | let z = y; | 720 | let z = y; |
818 | }); | 721 | }); |
819 | } | 722 | } |
820 | "#, | 723 | "#, |
821 | "x BIND_PAT FileId(1) 70..71", | ||
822 | "x", | ||
823 | ); | 724 | ); |
824 | 725 | ||
825 | check_goto( | 726 | check( |
826 | r#" | 727 | r#" |
827 | //- /lib.rs | ||
828 | macro_rules! id { | 728 | macro_rules! id { |
829 | ($($tt:tt)*) => ($($tt)*) | 729 | ($($tt:tt)*) => ($($tt)*) |
830 | } | 730 | } |
@@ -833,159 +733,125 @@ fn foo() { | |||
833 | let x = 1; | 733 | let x = 1; |
834 | id!({ | 734 | id!({ |
835 | let y = x; | 735 | let y = x; |
736 | //^ | ||
836 | let z = <|>y; | 737 | let z = <|>y; |
837 | }); | 738 | }); |
838 | } | 739 | } |
839 | "#, | 740 | "#, |
840 | "y BIND_PAT FileId(1) 99..100", | ||
841 | "y", | ||
842 | ); | 741 | ); |
843 | } | 742 | } |
844 | 743 | ||
845 | #[test] | 744 | #[test] |
846 | fn goto_def_in_local_fn() { | 745 | fn goto_def_in_local_fn() { |
847 | check_goto( | 746 | check( |
848 | " | 747 | r#" |
849 | //- /lib.rs | 748 | fn main() { |
850 | fn main() { | 749 | fn foo() { |
851 | fn foo() { | 750 | let x = 92; |
852 | let x = 92; | 751 | //^ |
853 | <|>x; | 752 | <|>x; |
854 | } | 753 | } |
855 | } | 754 | } |
856 | ", | 755 | "#, |
857 | "x BIND_PAT FileId(1) 39..40", | ||
858 | "x", | ||
859 | ); | 756 | ); |
860 | } | 757 | } |
861 | 758 | ||
862 | #[test] | 759 | #[test] |
863 | fn goto_def_in_local_macro() { | 760 | fn goto_def_in_local_macro() { |
864 | check_goto( | 761 | check( |
865 | r" | 762 | r#" |
866 | //- /lib.rs | 763 | fn bar() { |
867 | fn bar() { | 764 | macro_rules! foo { () => { () } } |
868 | macro_rules! foo { () => { () } } | 765 | //^^^ |
869 | <|>foo!(); | 766 | <|>foo!(); |
870 | } | 767 | } |
871 | ", | 768 | "#, |
872 | "foo MACRO_CALL FileId(1) 15..48 28..31", | ||
873 | "macro_rules! foo { () => { () } }|foo", | ||
874 | ); | 769 | ); |
875 | } | 770 | } |
876 | 771 | ||
877 | #[test] | 772 | #[test] |
878 | fn goto_def_for_field_init_shorthand() { | 773 | fn goto_def_for_field_init_shorthand() { |
879 | check_goto( | 774 | check( |
880 | " | 775 | r#" |
881 | //- /lib.rs | 776 | struct Foo { x: i32 } |
882 | struct Foo { x: i32 } | 777 | fn main() { |
883 | fn main() { | 778 | let x = 92; |
884 | let x = 92; | 779 | //^ |
885 | Foo { x<|> }; | 780 | Foo { x<|> }; |
886 | } | 781 | } |
887 | ", | 782 | "#, |
888 | "x BIND_PAT FileId(1) 42..43", | ||
889 | "x", | ||
890 | ) | 783 | ) |
891 | } | 784 | } |
892 | 785 | ||
893 | #[test] | 786 | #[test] |
894 | fn goto_def_for_enum_variant_field() { | 787 | fn goto_def_for_enum_variant_field() { |
895 | check_goto( | 788 | check( |
896 | " | 789 | r#" |
897 | //- /lib.rs | 790 | enum Foo { |
898 | enum Foo { | 791 | Bar { x: i32 } |
899 | Bar { x: i32 } | 792 | } //^ |
900 | } | 793 | fn baz(foo: Foo) { |
901 | fn baz(foo: Foo) { | 794 | match foo { |
902 | match foo { | 795 | Foo::Bar { x<|> } => x |
903 | Foo::Bar { x<|> } => x | 796 | }; |
904 | }; | 797 | } |
905 | } | 798 | "#, |
906 | ", | ||
907 | "x RECORD_FIELD_DEF FileId(1) 21..27 21..22", | ||
908 | "x: i32|x", | ||
909 | ); | 799 | ); |
910 | } | 800 | } |
911 | 801 | ||
912 | #[test] | 802 | #[test] |
913 | fn goto_def_for_enum_variant_self_pattern_const() { | 803 | fn goto_def_for_enum_variant_self_pattern_const() { |
914 | check_goto( | 804 | check( |
915 | " | 805 | r#" |
916 | //- /lib.rs | 806 | enum Foo { Bar } |
917 | enum Foo { | 807 | //^^^ |
918 | Bar, | 808 | impl Foo { |
919 | } | 809 | fn baz(self) { |
920 | impl Foo { | 810 | match self { Self::Bar<|> => {} } |
921 | fn baz(self) { | 811 | } |
922 | match self { | 812 | } |
923 | Self::Bar<|> => {} | 813 | "#, |
924 | } | ||
925 | } | ||
926 | } | ||
927 | ", | ||
928 | "Bar ENUM_VARIANT FileId(1) 15..18 15..18", | ||
929 | "Bar|Bar", | ||
930 | ); | 814 | ); |
931 | } | 815 | } |
932 | 816 | ||
933 | #[test] | 817 | #[test] |
934 | fn goto_def_for_enum_variant_self_pattern_record() { | 818 | fn goto_def_for_enum_variant_self_pattern_record() { |
935 | check_goto( | 819 | check( |
936 | " | 820 | r#" |
937 | //- /lib.rs | 821 | enum Foo { Bar { val: i32 } } |
938 | enum Foo { | 822 | //^^^ |
939 | Bar { val: i32 }, | 823 | impl Foo { |
940 | } | 824 | fn baz(self) -> i32 { |
941 | impl Foo { | 825 | match self { Self::Bar<|> { val } => {} } |
942 | fn baz(self) -> i32 { | 826 | } |
943 | match self { | 827 | } |
944 | Self::Bar<|> { val } => {} | 828 | "#, |
945 | } | ||
946 | } | ||
947 | } | ||
948 | ", | ||
949 | "Bar ENUM_VARIANT FileId(1) 15..31 15..18", | ||
950 | "Bar { val: i32 }|Bar", | ||
951 | ); | 829 | ); |
952 | } | 830 | } |
953 | 831 | ||
954 | #[test] | 832 | #[test] |
955 | fn goto_def_for_enum_variant_self_expr_const() { | 833 | fn goto_def_for_enum_variant_self_expr_const() { |
956 | check_goto( | 834 | check( |
957 | " | 835 | r#" |
958 | //- /lib.rs | 836 | enum Foo { Bar } |
959 | enum Foo { | 837 | //^^^ |
960 | Bar, | 838 | impl Foo { |
961 | } | 839 | fn baz(self) { Self::Bar<|>; } |
962 | impl Foo { | 840 | } |
963 | fn baz(self) { | 841 | "#, |
964 | Self::Bar<|>; | ||
965 | } | ||
966 | } | ||
967 | ", | ||
968 | "Bar ENUM_VARIANT FileId(1) 15..18 15..18", | ||
969 | "Bar|Bar", | ||
970 | ); | 842 | ); |
971 | } | 843 | } |
972 | 844 | ||
973 | #[test] | 845 | #[test] |
974 | fn goto_def_for_enum_variant_self_expr_record() { | 846 | fn goto_def_for_enum_variant_self_expr_record() { |
975 | check_goto( | 847 | check( |
976 | " | 848 | r#" |
977 | //- /lib.rs | 849 | enum Foo { Bar { val: i32 } } |
978 | enum Foo { | 850 | //^^^ |
979 | Bar { val: i32 }, | 851 | impl Foo { |
980 | } | 852 | fn baz(self) { Self::Bar<|> {val: 4}; } |
981 | impl Foo { | 853 | } |
982 | fn baz(self) { | 854 | "#, |
983 | Self::Bar<|> {val: 4}; | ||
984 | } | ||
985 | } | ||
986 | ", | ||
987 | "Bar ENUM_VARIANT FileId(1) 15..31 15..18", | ||
988 | "Bar { val: i32 }|Bar", | ||
989 | ); | 855 | ); |
990 | } | 856 | } |
991 | } | 857 | } |
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs index 0cec0657e..99a7022a4 100644 --- a/crates/ra_ide/src/goto_implementation.rs +++ b/crates/ra_ide/src/goto_implementation.rs | |||
@@ -74,135 +74,152 @@ fn impls_for_trait( | |||
74 | 74 | ||
75 | #[cfg(test)] | 75 | #[cfg(test)] |
76 | mod tests { | 76 | mod tests { |
77 | use crate::mock_analysis::analysis_and_position; | 77 | use ra_db::FileRange; |
78 | 78 | ||
79 | fn check_goto(fixture: &str, expected: &[&str]) { | 79 | use crate::mock_analysis::MockAnalysis; |
80 | let (analysis, pos) = analysis_and_position(fixture); | ||
81 | 80 | ||
82 | let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info; | 81 | fn check(ra_fixture: &str) { |
83 | assert_eq!(navs.len(), expected.len()); | 82 | let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture); |
84 | navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start())); | 83 | let annotations = mock.annotations(); |
85 | navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i])); | 84 | let analysis = mock.analysis(); |
85 | |||
86 | let navs = analysis.goto_implementation(position).unwrap().unwrap().info; | ||
87 | |||
88 | let key = |frange: &FileRange| (frange.file_id, frange.range.start()); | ||
89 | |||
90 | let mut expected = annotations | ||
91 | .into_iter() | ||
92 | .map(|(range, data)| { | ||
93 | assert!(data.is_empty()); | ||
94 | range | ||
95 | }) | ||
96 | .collect::<Vec<_>>(); | ||
97 | expected.sort_by_key(key); | ||
98 | |||
99 | let mut actual = navs | ||
100 | .into_iter() | ||
101 | .map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() }) | ||
102 | .collect::<Vec<_>>(); | ||
103 | actual.sort_by_key(key); | ||
104 | |||
105 | assert_eq!(expected, actual); | ||
86 | } | 106 | } |
87 | 107 | ||
88 | #[test] | 108 | #[test] |
89 | fn goto_implementation_works() { | 109 | fn goto_implementation_works() { |
90 | check_goto( | 110 | check( |
91 | " | 111 | r#" |
92 | //- /lib.rs | 112 | struct Foo<|>; |
93 | struct Foo<|>; | 113 | impl Foo {} |
94 | impl Foo {} | 114 | //^^^ |
95 | ", | 115 | "#, |
96 | &["impl IMPL_DEF FileId(1) 12..23"], | ||
97 | ); | 116 | ); |
98 | } | 117 | } |
99 | 118 | ||
100 | #[test] | 119 | #[test] |
101 | fn goto_implementation_works_multiple_blocks() { | 120 | fn goto_implementation_works_multiple_blocks() { |
102 | check_goto( | 121 | check( |
103 | " | 122 | r#" |
104 | //- /lib.rs | 123 | struct Foo<|>; |
105 | struct Foo<|>; | 124 | impl Foo {} |
106 | impl Foo {} | 125 | //^^^ |
107 | impl Foo {} | 126 | impl Foo {} |
108 | ", | 127 | //^^^ |
109 | &["impl IMPL_DEF FileId(1) 12..23", "impl IMPL_DEF FileId(1) 24..35"], | 128 | "#, |
110 | ); | 129 | ); |
111 | } | 130 | } |
112 | 131 | ||
113 | #[test] | 132 | #[test] |
114 | fn goto_implementation_works_multiple_mods() { | 133 | fn goto_implementation_works_multiple_mods() { |
115 | check_goto( | 134 | check( |
116 | " | 135 | r#" |
117 | //- /lib.rs | 136 | struct Foo<|>; |
118 | struct Foo<|>; | 137 | mod a { |
119 | mod a { | 138 | impl super::Foo {} |
120 | impl super::Foo {} | 139 | //^^^^^^^^^^ |
121 | } | 140 | } |
122 | mod b { | 141 | mod b { |
123 | impl super::Foo {} | 142 | impl super::Foo {} |
124 | } | 143 | //^^^^^^^^^^ |
125 | ", | 144 | } |
126 | &["impl IMPL_DEF FileId(1) 24..42", "impl IMPL_DEF FileId(1) 57..75"], | 145 | "#, |
127 | ); | 146 | ); |
128 | } | 147 | } |
129 | 148 | ||
130 | #[test] | 149 | #[test] |
131 | fn goto_implementation_works_multiple_files() { | 150 | fn goto_implementation_works_multiple_files() { |
132 | check_goto( | 151 | check( |
133 | " | 152 | r#" |
134 | //- /lib.rs | 153 | //- /lib.rs |
135 | struct Foo<|>; | 154 | struct Foo<|>; |
136 | mod a; | 155 | mod a; |
137 | mod b; | 156 | mod b; |
138 | //- /a.rs | 157 | //- /a.rs |
139 | impl crate::Foo {} | 158 | impl crate::Foo {} |
140 | //- /b.rs | 159 | //^^^^^^^^^^ |
141 | impl crate::Foo {} | 160 | //- /b.rs |
142 | ", | 161 | impl crate::Foo {} |
143 | &["impl IMPL_DEF FileId(2) 0..18", "impl IMPL_DEF FileId(3) 0..18"], | 162 | //^^^^^^^^^^ |
163 | "#, | ||
144 | ); | 164 | ); |
145 | } | 165 | } |
146 | 166 | ||
147 | #[test] | 167 | #[test] |
148 | fn goto_implementation_for_trait() { | 168 | fn goto_implementation_for_trait() { |
149 | check_goto( | 169 | check( |
150 | " | 170 | r#" |
151 | //- /lib.rs | 171 | trait T<|> {} |
152 | trait T<|> {} | 172 | struct Foo; |
153 | struct Foo; | 173 | impl T for Foo {} |
154 | impl T for Foo {} | 174 | //^^^ |
155 | ", | 175 | "#, |
156 | &["impl IMPL_DEF FileId(1) 23..40"], | ||
157 | ); | 176 | ); |
158 | } | 177 | } |
159 | 178 | ||
160 | #[test] | 179 | #[test] |
161 | fn goto_implementation_for_trait_multiple_files() { | 180 | fn goto_implementation_for_trait_multiple_files() { |
162 | check_goto( | 181 | check( |
163 | " | 182 | r#" |
164 | //- /lib.rs | 183 | //- /lib.rs |
165 | trait T<|> {}; | 184 | trait T<|> {}; |
166 | struct Foo; | 185 | struct Foo; |
167 | mod a; | 186 | mod a; |
168 | mod b; | 187 | mod b; |
169 | //- /a.rs | 188 | //- /a.rs |
170 | impl crate::T for crate::Foo {} | 189 | impl crate::T for crate::Foo {} |
171 | //- /b.rs | 190 | //^^^^^^^^^^ |
172 | impl crate::T for crate::Foo {} | 191 | //- /b.rs |
173 | ", | 192 | impl crate::T for crate::Foo {} |
174 | &["impl IMPL_DEF FileId(2) 0..31", "impl IMPL_DEF FileId(3) 0..31"], | 193 | //^^^^^^^^^^ |
194 | "#, | ||
175 | ); | 195 | ); |
176 | } | 196 | } |
177 | 197 | ||
178 | #[test] | 198 | #[test] |
179 | fn goto_implementation_all_impls() { | 199 | fn goto_implementation_all_impls() { |
180 | check_goto( | 200 | check( |
181 | " | 201 | r#" |
182 | //- /lib.rs | 202 | //- /lib.rs |
183 | trait T {} | 203 | trait T {} |
184 | struct Foo<|>; | 204 | struct Foo<|>; |
185 | impl Foo {} | 205 | impl Foo {} |
186 | impl T for Foo {} | 206 | //^^^ |
187 | impl T for &Foo {} | 207 | impl T for Foo {} |
188 | ", | 208 | //^^^ |
189 | &[ | 209 | impl T for &Foo {} |
190 | "impl IMPL_DEF FileId(1) 23..34", | 210 | //^^^^ |
191 | "impl IMPL_DEF FileId(1) 35..52", | 211 | "#, |
192 | "impl IMPL_DEF FileId(1) 53..71", | ||
193 | ], | ||
194 | ); | 212 | ); |
195 | } | 213 | } |
196 | 214 | ||
197 | #[test] | 215 | #[test] |
198 | fn goto_implementation_to_builtin_derive() { | 216 | fn goto_implementation_to_builtin_derive() { |
199 | check_goto( | 217 | check( |
200 | " | 218 | r#" |
201 | //- /lib.rs | 219 | #[derive(Copy)] |
202 | #[derive(Copy)] | 220 | //^^^^^^^^^^^^^^^ |
203 | struct Foo<|>; | 221 | struct Foo<|>; |
204 | ", | 222 | "#, |
205 | &["impl IMPL_DEF FileId(1) 0..15"], | ||
206 | ); | 223 | ); |
207 | } | 224 | } |
208 | } | 225 | } |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 3fd08b1e8..62d364bfa 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -3,7 +3,7 @@ use ra_ide_db::RootDatabase; | |||
3 | use ra_prof::profile; | 3 | use ra_prof::profile; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, | 5 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, |
6 | match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, | 6 | match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{FileId, FunctionSignature}; | 9 | use crate::{FileId, FunctionSignature}; |
@@ -112,7 +112,7 @@ fn get_chaining_hints( | |||
112 | // Ignoring extra whitespace and comments | 112 | // Ignoring extra whitespace and comments |
113 | let next = tokens.next()?.kind(); | 113 | let next = tokens.next()?.kind(); |
114 | let next_next = tokens.next()?.kind(); | 114 | let next_next = tokens.next()?.kind(); |
115 | if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT { | 115 | if next == SyntaxKind::WHITESPACE && next_next == T![.] { |
116 | let ty = sema.type_of_expr(&expr)?; | 116 | let ty = sema.type_of_expr(&expr)?; |
117 | if ty.is_unknown() { | 117 | if ty.is_unknown() { |
118 | return None; | 118 | return None; |
@@ -258,6 +258,7 @@ fn should_show_param_name_hint( | |||
258 | if param_name.is_empty() | 258 | if param_name.is_empty() |
259 | || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) | 259 | || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) |
260 | || is_argument_similar_to_param_name(sema, argument, param_name) | 260 | || is_argument_similar_to_param_name(sema, argument, param_name) |
261 | || param_name.starts_with("ra_fixture") | ||
261 | { | 262 | { |
262 | return false; | 263 | return false; |
263 | } | 264 | } |
@@ -270,7 +271,7 @@ fn should_show_param_name_hint( | |||
270 | 271 | ||
271 | // avoid displaying hints for common functions like map, filter, etc. | 272 | // avoid displaying hints for common functions like map, filter, etc. |
272 | // or other obvious words used in std | 273 | // or other obvious words used in std |
273 | parameters_len != 1 || !is_obvious_param(param_name) | 274 | !(parameters_len == 1 && is_obvious_param(param_name)) |
274 | } | 275 | } |
275 | 276 | ||
276 | fn is_argument_similar_to_param_name( | 277 | fn is_argument_similar_to_param_name( |
@@ -312,10 +313,8 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> { | |||
312 | } | 313 | } |
313 | 314 | ||
314 | fn is_obvious_param(param_name: &str) -> bool { | 315 | fn is_obvious_param(param_name: &str) -> bool { |
315 | let is_obvious_param_name = match param_name { | 316 | let is_obvious_param_name = |
316 | "predicate" | "value" | "pat" | "rhs" | "other" => true, | 317 | matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other"); |
317 | _ => false, | ||
318 | }; | ||
319 | param_name.len() == 1 || is_obvious_param_name | 318 | param_name.len() == 1 || is_obvious_param_name |
320 | } | 319 | } |
321 | 320 | ||
@@ -346,583 +345,251 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option< | |||
346 | 345 | ||
347 | #[cfg(test)] | 346 | #[cfg(test)] |
348 | mod tests { | 347 | mod tests { |
349 | use crate::inlay_hints::InlayHintsConfig; | 348 | use expect::{expect, Expect}; |
350 | use insta::assert_debug_snapshot; | 349 | use test_utils::extract_annotations; |
350 | |||
351 | use crate::{inlay_hints::InlayHintsConfig, mock_analysis::single_file}; | ||
351 | 352 | ||
352 | use crate::mock_analysis::single_file; | 353 | fn check(ra_fixture: &str) { |
354 | check_with_config(ra_fixture, InlayHintsConfig::default()); | ||
355 | } | ||
356 | |||
357 | fn check_with_config(ra_fixture: &str, config: InlayHintsConfig) { | ||
358 | let (analysis, file_id) = single_file(ra_fixture); | ||
359 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | ||
360 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | ||
361 | let actual = | ||
362 | inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>(); | ||
363 | assert_eq!(expected, actual); | ||
364 | } | ||
365 | |||
366 | fn check_expect(ra_fixture: &str, config: InlayHintsConfig, expect: Expect) { | ||
367 | let (analysis, file_id) = single_file(ra_fixture); | ||
368 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | ||
369 | expect.assert_debug_eq(&inlay_hints) | ||
370 | } | ||
353 | 371 | ||
354 | #[test] | 372 | #[test] |
355 | fn param_hints_only() { | 373 | fn param_hints_only() { |
356 | let (analysis, file_id) = single_file( | 374 | check_with_config( |
357 | r#" | 375 | r#" |
358 | fn foo(a: i32, b: i32) -> i32 { a + b } | 376 | fn foo(a: i32, b: i32) -> i32 { a + b } |
359 | fn main() { | 377 | fn main() { |
360 | let _x = foo(4, 4); | 378 | let _x = foo( |
361 | }"#, | 379 | 4, |
362 | ); | 380 | //^ a |
363 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" | 381 | 4, |
364 | [ | 382 | //^ b |
365 | InlayHint { | 383 | ); |
366 | range: 69..70, | 384 | }"#, |
367 | kind: ParameterHint, | 385 | InlayHintsConfig { |
368 | label: "a", | 386 | parameter_hints: true, |
369 | }, | 387 | type_hints: false, |
370 | InlayHint { | 388 | chaining_hints: false, |
371 | range: 72..73, | 389 | max_length: None, |
372 | kind: ParameterHint, | ||
373 | label: "b", | ||
374 | }, | 390 | }, |
375 | ] | 391 | ); |
376 | "###); | ||
377 | } | 392 | } |
378 | 393 | ||
379 | #[test] | 394 | #[test] |
380 | fn hints_disabled() { | 395 | fn hints_disabled() { |
381 | let (analysis, file_id) = single_file( | 396 | check_with_config( |
382 | r#" | 397 | r#" |
383 | fn foo(a: i32, b: i32) -> i32 { a + b } | 398 | fn foo(a: i32, b: i32) -> i32 { a + b } |
384 | fn main() { | 399 | fn main() { |
385 | let _x = foo(4, 4); | 400 | let _x = foo(4, 4); |
386 | }"#, | 401 | }"#, |
402 | InlayHintsConfig { | ||
403 | type_hints: false, | ||
404 | parameter_hints: false, | ||
405 | chaining_hints: false, | ||
406 | max_length: None, | ||
407 | }, | ||
387 | ); | 408 | ); |
388 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###); | ||
389 | } | 409 | } |
390 | 410 | ||
391 | #[test] | 411 | #[test] |
392 | fn type_hints_only() { | 412 | fn type_hints_only() { |
393 | let (analysis, file_id) = single_file( | 413 | check_with_config( |
394 | r#" | 414 | r#" |
395 | fn foo(a: i32, b: i32) -> i32 { a + b } | 415 | fn foo(a: i32, b: i32) -> i32 { a + b } |
396 | fn main() { | 416 | fn main() { |
397 | let _x = foo(4, 4); | 417 | let _x = foo(4, 4); |
398 | }"#, | 418 | //^^ i32 |
399 | ); | 419 | }"#, |
400 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" | 420 | InlayHintsConfig { |
401 | [ | 421 | type_hints: true, |
402 | InlayHint { | 422 | parameter_hints: false, |
403 | range: 60..62, | 423 | chaining_hints: false, |
404 | kind: TypeHint, | 424 | max_length: None, |
405 | label: "i32", | ||
406 | }, | 425 | }, |
407 | ] | 426 | ); |
408 | "###); | ||
409 | } | 427 | } |
428 | |||
410 | #[test] | 429 | #[test] |
411 | fn default_generic_types_should_not_be_displayed() { | 430 | fn default_generic_types_should_not_be_displayed() { |
412 | let (analysis, file_id) = single_file( | 431 | check( |
413 | r#" | 432 | r#" |
414 | struct Test<K, T = u8> { | 433 | struct Test<K, T = u8> { k: K, t: T } |
415 | k: K, | ||
416 | t: T, | ||
417 | } | ||
418 | 434 | ||
419 | fn main() { | 435 | fn main() { |
420 | let zz = Test { t: 23u8, k: 33 }; | 436 | let zz = Test { t: 23u8, k: 33 }; |
437 | //^^ Test<i32> | ||
421 | let zz_ref = &zz; | 438 | let zz_ref = &zz; |
439 | //^^^^^^ &Test<i32> | ||
422 | }"#, | 440 | }"#, |
423 | ); | 441 | ); |
424 | |||
425 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
426 | [ | ||
427 | InlayHint { | ||
428 | range: 68..70, | ||
429 | kind: TypeHint, | ||
430 | label: "Test<i32>", | ||
431 | }, | ||
432 | InlayHint { | ||
433 | range: 106..112, | ||
434 | kind: TypeHint, | ||
435 | label: "&Test<i32>", | ||
436 | }, | ||
437 | ] | ||
438 | "### | ||
439 | ); | ||
440 | } | 442 | } |
441 | 443 | ||
442 | #[test] | 444 | #[test] |
443 | fn let_statement() { | 445 | fn let_statement() { |
444 | let (analysis, file_id) = single_file( | 446 | check( |
445 | r#" | 447 | r#" |
446 | #[derive(PartialEq)] | 448 | #[derive(PartialEq)] |
447 | enum CustomOption<T> { | 449 | enum Option<T> { None, Some(T) } |
448 | None, | ||
449 | Some(T), | ||
450 | } | ||
451 | 450 | ||
452 | #[derive(PartialEq)] | 451 | #[derive(PartialEq)] |
453 | struct Test { | 452 | struct Test { a: Option<u32>, b: u8 } |
454 | a: CustomOption<u32>, | ||
455 | b: u8, | ||
456 | } | ||
457 | 453 | ||
458 | fn main() { | 454 | fn main() { |
459 | struct InnerStruct {} | 455 | struct InnerStruct {} |
460 | 456 | ||
461 | let test = 54; | 457 | let test = 54; |
458 | //^^^^ i32 | ||
462 | let test: i32 = 33; | 459 | let test: i32 = 33; |
463 | let mut test = 33; | 460 | let mut test = 33; |
461 | //^^^^^^^^ i32 | ||
464 | let _ = 22; | 462 | let _ = 22; |
465 | let test = "test"; | 463 | let test = "test"; |
464 | //^^^^ &str | ||
466 | let test = InnerStruct {}; | 465 | let test = InnerStruct {}; |
467 | 466 | ||
468 | let test = vec![222]; | 467 | let test = unresolved(); |
469 | let test: Vec<_> = (0..3).collect(); | ||
470 | let test = (0..3).collect::<Vec<i128>>(); | ||
471 | let test = (0..3).collect::<Vec<_>>(); | ||
472 | |||
473 | let mut test = Vec::new(); | ||
474 | test.push(333); | ||
475 | 468 | ||
476 | let test = (42, 'a'); | 469 | let test = (42, 'a'); |
477 | let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5)); | 470 | //^^^^ (i32, char) |
471 | let (a, (b, (c,)) = (2, (3, (9.2,)); | ||
472 | //^ i32 ^ i32 ^ f64 | ||
478 | let &x = &92; | 473 | let &x = &92; |
474 | //^ i32 | ||
479 | }"#, | 475 | }"#, |
480 | ); | 476 | ); |
481 | |||
482 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
483 | [ | ||
484 | InlayHint { | ||
485 | range: 192..196, | ||
486 | kind: TypeHint, | ||
487 | label: "i32", | ||
488 | }, | ||
489 | InlayHint { | ||
490 | range: 235..243, | ||
491 | kind: TypeHint, | ||
492 | label: "i32", | ||
493 | }, | ||
494 | InlayHint { | ||
495 | range: 274..278, | ||
496 | kind: TypeHint, | ||
497 | label: "&str", | ||
498 | }, | ||
499 | InlayHint { | ||
500 | range: 538..542, | ||
501 | kind: TypeHint, | ||
502 | label: "(i32, char)", | ||
503 | }, | ||
504 | InlayHint { | ||
505 | range: 565..566, | ||
506 | kind: TypeHint, | ||
507 | label: "i32", | ||
508 | }, | ||
509 | InlayHint { | ||
510 | range: 569..570, | ||
511 | kind: TypeHint, | ||
512 | label: "i32", | ||
513 | }, | ||
514 | InlayHint { | ||
515 | range: 572..573, | ||
516 | kind: TypeHint, | ||
517 | label: "i32", | ||
518 | }, | ||
519 | InlayHint { | ||
520 | range: 576..577, | ||
521 | kind: TypeHint, | ||
522 | label: "f64", | ||
523 | }, | ||
524 | InlayHint { | ||
525 | range: 579..580, | ||
526 | kind: TypeHint, | ||
527 | label: "f64", | ||
528 | }, | ||
529 | InlayHint { | ||
530 | range: 583..584, | ||
531 | kind: TypeHint, | ||
532 | label: "i32", | ||
533 | }, | ||
534 | InlayHint { | ||
535 | range: 626..627, | ||
536 | kind: TypeHint, | ||
537 | label: "i32", | ||
538 | }, | ||
539 | ] | ||
540 | "### | ||
541 | ); | ||
542 | } | 477 | } |
543 | 478 | ||
544 | #[test] | 479 | #[test] |
545 | fn closure_parameters() { | 480 | fn closure_parameters() { |
546 | let (analysis, file_id) = single_file( | 481 | check( |
547 | r#" | 482 | r#" |
548 | fn main() { | 483 | fn main() { |
549 | let mut start = 0; | 484 | let mut start = 0; |
550 | (0..2).for_each(|increment| { | 485 | //^^^^^^^^^ i32 |
551 | start += increment; | 486 | (0..2).for_each(|increment| { start += increment; }); |
552 | }); | 487 | //^^^^^^^^^ i32 |
488 | |||
489 | let multiply = | ||
490 | //^^^^^^^^ |…| -> i32 | ||
491 | | a, b| a * b | ||
492 | //^ i32 ^ i32 | ||
493 | ; | ||
553 | 494 | ||
554 | let multiply = |a, b, c, d| a * b * c * d; | 495 | let _: i32 = multiply(1, 2); |
555 | let _: i32 = multiply(1, 2, 3, 4); | ||
556 | let multiply_ref = &multiply; | 496 | let multiply_ref = &multiply; |
497 | //^^^^^^^^^^^^ &|…| -> i32 | ||
557 | 498 | ||
558 | let return_42 = || 42; | 499 | let return_42 = || 42; |
500 | //^^^^^^^^^ || -> i32 | ||
559 | }"#, | 501 | }"#, |
560 | ); | 502 | ); |
561 | |||
562 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
563 | [ | ||
564 | InlayHint { | ||
565 | range: 20..29, | ||
566 | kind: TypeHint, | ||
567 | label: "i32", | ||
568 | }, | ||
569 | InlayHint { | ||
570 | range: 56..65, | ||
571 | kind: TypeHint, | ||
572 | label: "i32", | ||
573 | }, | ||
574 | InlayHint { | ||
575 | range: 114..122, | ||
576 | kind: TypeHint, | ||
577 | label: "|…| -> i32", | ||
578 | }, | ||
579 | InlayHint { | ||
580 | range: 126..127, | ||
581 | kind: TypeHint, | ||
582 | label: "i32", | ||
583 | }, | ||
584 | InlayHint { | ||
585 | range: 129..130, | ||
586 | kind: TypeHint, | ||
587 | label: "i32", | ||
588 | }, | ||
589 | InlayHint { | ||
590 | range: 132..133, | ||
591 | kind: TypeHint, | ||
592 | label: "i32", | ||
593 | }, | ||
594 | InlayHint { | ||
595 | range: 135..136, | ||
596 | kind: TypeHint, | ||
597 | label: "i32", | ||
598 | }, | ||
599 | InlayHint { | ||
600 | range: 200..212, | ||
601 | kind: TypeHint, | ||
602 | label: "&|…| -> i32", | ||
603 | }, | ||
604 | InlayHint { | ||
605 | range: 235..244, | ||
606 | kind: TypeHint, | ||
607 | label: "|| -> i32", | ||
608 | }, | ||
609 | ] | ||
610 | "### | ||
611 | ); | ||
612 | } | 503 | } |
613 | 504 | ||
614 | #[test] | 505 | #[test] |
615 | fn for_expression() { | 506 | fn for_expression() { |
616 | let (analysis, file_id) = single_file( | 507 | check( |
617 | r#" | 508 | r#" |
618 | fn main() { | 509 | fn main() { |
619 | let mut start = 0; | 510 | let mut start = 0; |
620 | for increment in 0..2 { | 511 | //^^^^^^^^^ i32 |
621 | start += increment; | 512 | for increment in 0..2 { start += increment; } |
622 | } | 513 | //^^^^^^^^^ i32 |
623 | }"#, | 514 | }"#, |
624 | ); | 515 | ); |
625 | |||
626 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
627 | [ | ||
628 | InlayHint { | ||
629 | range: 20..29, | ||
630 | kind: TypeHint, | ||
631 | label: "i32", | ||
632 | }, | ||
633 | InlayHint { | ||
634 | range: 43..52, | ||
635 | kind: TypeHint, | ||
636 | label: "i32", | ||
637 | }, | ||
638 | ] | ||
639 | "### | ||
640 | ); | ||
641 | } | 516 | } |
642 | 517 | ||
643 | #[test] | 518 | #[test] |
644 | fn if_expr() { | 519 | fn if_expr() { |
645 | let (analysis, file_id) = single_file( | 520 | check( |
646 | r#" | 521 | r#" |
647 | #[derive(PartialEq)] | 522 | enum Option<T> { None, Some(T) } |
648 | enum CustomOption<T> { | 523 | use Option::*; |
649 | None, | ||
650 | Some(T), | ||
651 | } | ||
652 | 524 | ||
653 | #[derive(PartialEq)] | 525 | struct Test { a: Option<u32>, b: u8 } |
654 | struct Test { | ||
655 | a: CustomOption<u32>, | ||
656 | b: u8, | ||
657 | } | ||
658 | |||
659 | use CustomOption::*; | ||
660 | 526 | ||
661 | fn main() { | 527 | fn main() { |
662 | let test = Some(Test { a: Some(3), b: 1 }); | 528 | let test = Some(Test { a: Some(3), b: 1 }); |
529 | //^^^^ Option<Test> | ||
663 | if let None = &test {}; | 530 | if let None = &test {}; |
664 | if let test = &test {}; | 531 | if let test = &test {}; |
532 | //^^^^ &Option<Test> | ||
665 | if let Some(test) = &test {}; | 533 | if let Some(test) = &test {}; |
666 | if let Some(Test { a, b }) = &test {}; | 534 | //^^^^ &Test |
667 | if let Some(Test { a: x, b: y }) = &test {}; | 535 | if let Some(Test { a, b }) = &test {}; |
668 | if let Some(Test { a: Some(x), b: y }) = &test {}; | 536 | //^ &Option<u32> ^ &u8 |
669 | if let Some(Test { a: None, b: y }) = &test {}; | 537 | if let Some(Test { a: x, b: y }) = &test {}; |
538 | //^ &Option<u32> ^ &u8 | ||
539 | if let Some(Test { a: Some(x), b: y }) = &test {}; | ||
540 | //^ &u32 ^ &u8 | ||
541 | if let Some(Test { a: None, b: y }) = &test {}; | ||
542 | //^ &u8 | ||
670 | if let Some(Test { b: y, .. }) = &test {}; | 543 | if let Some(Test { b: y, .. }) = &test {}; |
671 | 544 | //^ &u8 | |
672 | if test == None {} | 545 | if test == None {} |
673 | }"#, | 546 | }"#, |
674 | ); | 547 | ); |
675 | |||
676 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
677 | [ | ||
678 | InlayHint { | ||
679 | range: 187..191, | ||
680 | kind: TypeHint, | ||
681 | label: "CustomOption<Test>", | ||
682 | }, | ||
683 | InlayHint { | ||
684 | range: 266..270, | ||
685 | kind: TypeHint, | ||
686 | label: "&CustomOption<Test>", | ||
687 | }, | ||
688 | InlayHint { | ||
689 | range: 299..303, | ||
690 | kind: TypeHint, | ||
691 | label: "&Test", | ||
692 | }, | ||
693 | InlayHint { | ||
694 | range: 340..341, | ||
695 | kind: TypeHint, | ||
696 | label: "&CustomOption<u32>", | ||
697 | }, | ||
698 | InlayHint { | ||
699 | range: 343..344, | ||
700 | kind: TypeHint, | ||
701 | label: "&u8", | ||
702 | }, | ||
703 | InlayHint { | ||
704 | range: 386..387, | ||
705 | kind: TypeHint, | ||
706 | label: "&CustomOption<u32>", | ||
707 | }, | ||
708 | InlayHint { | ||
709 | range: 392..393, | ||
710 | kind: TypeHint, | ||
711 | label: "&u8", | ||
712 | }, | ||
713 | InlayHint { | ||
714 | range: 440..441, | ||
715 | kind: TypeHint, | ||
716 | label: "&u32", | ||
717 | }, | ||
718 | InlayHint { | ||
719 | range: 447..448, | ||
720 | kind: TypeHint, | ||
721 | label: "&u8", | ||
722 | }, | ||
723 | InlayHint { | ||
724 | range: 499..500, | ||
725 | kind: TypeHint, | ||
726 | label: "&u8", | ||
727 | }, | ||
728 | InlayHint { | ||
729 | range: 542..543, | ||
730 | kind: TypeHint, | ||
731 | label: "&u8", | ||
732 | }, | ||
733 | ] | ||
734 | "### | ||
735 | ); | ||
736 | } | 548 | } |
737 | 549 | ||
738 | #[test] | 550 | #[test] |
739 | fn while_expr() { | 551 | fn while_expr() { |
740 | let (analysis, file_id) = single_file( | 552 | check( |
741 | r#" | 553 | r#" |
742 | #[derive(PartialEq)] | 554 | enum Option<T> { None, Some(T) } |
743 | enum CustomOption<T> { | 555 | use Option::*; |
744 | None, | ||
745 | Some(T), | ||
746 | } | ||
747 | 556 | ||
748 | #[derive(PartialEq)] | 557 | struct Test { a: Option<u32>, b: u8 } |
749 | struct Test { | ||
750 | a: CustomOption<u32>, | ||
751 | b: u8, | ||
752 | } | ||
753 | |||
754 | use CustomOption::*; | ||
755 | 558 | ||
756 | fn main() { | 559 | fn main() { |
757 | let test = Some(Test { a: Some(3), b: 1 }); | 560 | let test = Some(Test { a: Some(3), b: 1 }); |
758 | while let None = &test {}; | 561 | //^^^^ Option<Test> |
759 | while let test = &test {}; | 562 | while let Some(Test { a: Some(x), b: y }) = &test {}; |
760 | while let Some(test) = &test {}; | 563 | //^ &u32 ^ &u8 |
761 | while let Some(Test { a, b }) = &test {}; | ||
762 | while let Some(Test { a: x, b: y }) = &test {}; | ||
763 | while let Some(Test { a: Some(x), b: y }) = &test {}; | ||
764 | while let Some(Test { a: None, b: y }) = &test {}; | ||
765 | while let Some(Test { b: y, .. }) = &test {}; | ||
766 | |||
767 | while test == None {} | ||
768 | }"#, | 564 | }"#, |
769 | ); | 565 | ); |
770 | |||
771 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
772 | [ | ||
773 | InlayHint { | ||
774 | range: 187..191, | ||
775 | kind: TypeHint, | ||
776 | label: "CustomOption<Test>", | ||
777 | }, | ||
778 | InlayHint { | ||
779 | range: 272..276, | ||
780 | kind: TypeHint, | ||
781 | label: "&CustomOption<Test>", | ||
782 | }, | ||
783 | InlayHint { | ||
784 | range: 308..312, | ||
785 | kind: TypeHint, | ||
786 | label: "&Test", | ||
787 | }, | ||
788 | InlayHint { | ||
789 | range: 352..353, | ||
790 | kind: TypeHint, | ||
791 | label: "&CustomOption<u32>", | ||
792 | }, | ||
793 | InlayHint { | ||
794 | range: 355..356, | ||
795 | kind: TypeHint, | ||
796 | label: "&u8", | ||
797 | }, | ||
798 | InlayHint { | ||
799 | range: 401..402, | ||
800 | kind: TypeHint, | ||
801 | label: "&CustomOption<u32>", | ||
802 | }, | ||
803 | InlayHint { | ||
804 | range: 407..408, | ||
805 | kind: TypeHint, | ||
806 | label: "&u8", | ||
807 | }, | ||
808 | InlayHint { | ||
809 | range: 458..459, | ||
810 | kind: TypeHint, | ||
811 | label: "&u32", | ||
812 | }, | ||
813 | InlayHint { | ||
814 | range: 465..466, | ||
815 | kind: TypeHint, | ||
816 | label: "&u8", | ||
817 | }, | ||
818 | InlayHint { | ||
819 | range: 520..521, | ||
820 | kind: TypeHint, | ||
821 | label: "&u8", | ||
822 | }, | ||
823 | InlayHint { | ||
824 | range: 566..567, | ||
825 | kind: TypeHint, | ||
826 | label: "&u8", | ||
827 | }, | ||
828 | ] | ||
829 | "### | ||
830 | ); | ||
831 | } | 566 | } |
832 | 567 | ||
833 | #[test] | 568 | #[test] |
834 | fn match_arm_list() { | 569 | fn match_arm_list() { |
835 | let (analysis, file_id) = single_file( | 570 | check( |
836 | r#" | 571 | r#" |
837 | #[derive(PartialEq)] | 572 | enum Option<T> { None, Some(T) } |
838 | enum CustomOption<T> { | 573 | use Option::*; |
839 | None, | ||
840 | Some(T), | ||
841 | } | ||
842 | |||
843 | #[derive(PartialEq)] | ||
844 | struct Test { | ||
845 | a: CustomOption<u32>, | ||
846 | b: u8, | ||
847 | } | ||
848 | 574 | ||
849 | use CustomOption::*; | 575 | struct Test { a: Option<u32>, b: u8 } |
850 | 576 | ||
851 | fn main() { | 577 | fn main() { |
852 | match Some(Test { a: Some(3), b: 1 }) { | 578 | match Some(Test { a: Some(3), b: 1 }) { |
853 | None => (), | 579 | None => (), |
854 | test => (), | 580 | test => (), |
855 | Some(test) => (), | 581 | //^^^^ Option<Test> |
856 | Some(Test { a, b }) => (), | ||
857 | Some(Test { a: x, b: y }) => (), | ||
858 | Some(Test { a: Some(x), b: y }) => (), | 582 | Some(Test { a: Some(x), b: y }) => (), |
859 | Some(Test { a: None, b: y }) => (), | 583 | //^ u32 ^ u8 |
860 | Some(Test { b: y, .. }) => (), | ||
861 | _ => {} | 584 | _ => {} |
862 | } | 585 | } |
863 | }"#, | 586 | }"#, |
864 | ); | 587 | ); |
865 | |||
866 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
867 | [ | ||
868 | InlayHint { | ||
869 | range: 251..255, | ||
870 | kind: TypeHint, | ||
871 | label: "CustomOption<Test>", | ||
872 | }, | ||
873 | InlayHint { | ||
874 | range: 276..280, | ||
875 | kind: TypeHint, | ||
876 | label: "Test", | ||
877 | }, | ||
878 | InlayHint { | ||
879 | range: 309..310, | ||
880 | kind: TypeHint, | ||
881 | label: "CustomOption<u32>", | ||
882 | }, | ||
883 | InlayHint { | ||
884 | range: 312..313, | ||
885 | kind: TypeHint, | ||
886 | label: "u8", | ||
887 | }, | ||
888 | InlayHint { | ||
889 | range: 347..348, | ||
890 | kind: TypeHint, | ||
891 | label: "CustomOption<u32>", | ||
892 | }, | ||
893 | InlayHint { | ||
894 | range: 353..354, | ||
895 | kind: TypeHint, | ||
896 | label: "u8", | ||
897 | }, | ||
898 | InlayHint { | ||
899 | range: 393..394, | ||
900 | kind: TypeHint, | ||
901 | label: "u32", | ||
902 | }, | ||
903 | InlayHint { | ||
904 | range: 400..401, | ||
905 | kind: TypeHint, | ||
906 | label: "u8", | ||
907 | }, | ||
908 | InlayHint { | ||
909 | range: 444..445, | ||
910 | kind: TypeHint, | ||
911 | label: "u8", | ||
912 | }, | ||
913 | InlayHint { | ||
914 | range: 479..480, | ||
915 | kind: TypeHint, | ||
916 | label: "u8", | ||
917 | }, | ||
918 | ] | ||
919 | "### | ||
920 | ); | ||
921 | } | 588 | } |
922 | 589 | ||
923 | #[test] | 590 | #[test] |
924 | fn hint_truncation() { | 591 | fn hint_truncation() { |
925 | let (analysis, file_id) = single_file( | 592 | check_with_config( |
926 | r#" | 593 | r#" |
927 | struct Smol<T>(T); | 594 | struct Smol<T>(T); |
928 | 595 | ||
@@ -930,52 +597,26 @@ struct VeryLongOuterName<T>(T); | |||
930 | 597 | ||
931 | fn main() { | 598 | fn main() { |
932 | let a = Smol(0u32); | 599 | let a = Smol(0u32); |
600 | //^ Smol<u32> | ||
933 | let b = VeryLongOuterName(0usize); | 601 | let b = VeryLongOuterName(0usize); |
602 | //^ VeryLongOuterName<…> | ||
934 | let c = Smol(Smol(0u32)) | 603 | let c = Smol(Smol(0u32)) |
604 | //^ Smol<Smol<…>> | ||
935 | }"#, | 605 | }"#, |
936 | ); | 606 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, |
937 | |||
938 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###" | ||
939 | [ | ||
940 | InlayHint { | ||
941 | range: 73..74, | ||
942 | kind: TypeHint, | ||
943 | label: "Smol<u32>", | ||
944 | }, | ||
945 | InlayHint { | ||
946 | range: 97..98, | ||
947 | kind: TypeHint, | ||
948 | label: "VeryLongOuterName<…>", | ||
949 | }, | ||
950 | InlayHint { | ||
951 | range: 136..137, | ||
952 | kind: TypeHint, | ||
953 | label: "Smol<Smol<…>>", | ||
954 | }, | ||
955 | ] | ||
956 | "### | ||
957 | ); | 607 | ); |
958 | } | 608 | } |
959 | 609 | ||
960 | #[test] | 610 | #[test] |
961 | fn function_call_parameter_hint() { | 611 | fn function_call_parameter_hint() { |
962 | let (analysis, file_id) = single_file( | 612 | check( |
963 | r#" | 613 | r#" |
964 | enum CustomOption<T> { | 614 | enum Option<T> { None, Some(T) } |
965 | None, | 615 | use Option::*; |
966 | Some(T), | ||
967 | } | ||
968 | use CustomOption::*; | ||
969 | 616 | ||
970 | struct FileId {} | 617 | struct FileId {} |
971 | struct SmolStr {} | 618 | struct SmolStr {} |
972 | 619 | ||
973 | impl From<&str> for SmolStr { | ||
974 | fn from(_: &str) -> Self { | ||
975 | unimplemented!() | ||
976 | } | ||
977 | } | ||
978 | |||
979 | struct TextRange {} | 620 | struct TextRange {} |
980 | struct SyntaxKind {} | 621 | struct SyntaxKind {} |
981 | struct NavigationTarget {} | 622 | struct NavigationTarget {} |
@@ -983,18 +624,15 @@ struct NavigationTarget {} | |||
983 | struct Test {} | 624 | struct Test {} |
984 | 625 | ||
985 | impl Test { | 626 | impl Test { |
986 | fn method(&self, mut param: i32) -> i32 { | 627 | fn method(&self, mut param: i32) -> i32 { param * 2 } |
987 | param * 2 | ||
988 | } | ||
989 | 628 | ||
990 | fn from_syntax( | 629 | fn from_syntax( |
991 | file_id: FileId, | 630 | file_id: FileId, |
992 | name: SmolStr, | 631 | name: SmolStr, |
993 | focus_range: CustomOption<TextRange>, | 632 | focus_range: Option<TextRange>, |
994 | full_range: TextRange, | 633 | full_range: TextRange, |
995 | kind: SyntaxKind, | 634 | kind: SyntaxKind, |
996 | docs: CustomOption<String>, | 635 | docs: Option<String>, |
997 | description: CustomOption<String>, | ||
998 | ) -> NavigationTarget { | 636 | ) -> NavigationTarget { |
999 | NavigationTarget {} | 637 | NavigationTarget {} |
1000 | } | 638 | } |
@@ -1006,108 +644,35 @@ fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { | |||
1006 | 644 | ||
1007 | fn main() { | 645 | fn main() { |
1008 | let not_literal = 1; | 646 | let not_literal = 1; |
1009 | let _: i32 = test_func(1, 2, "hello", 3, not_literal); | 647 | //^^^^^^^^^^^ i32 |
648 | let _: i32 = test_func(1, 2, "hello", 3, not_literal); | ||
649 | //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last | ||
1010 | let t: Test = Test {}; | 650 | let t: Test = Test {}; |
1011 | t.method(123); | 651 | t.method(123); |
1012 | Test::method(&t, 3456); | 652 | //^^^ param |
1013 | 653 | Test::method(&t, 3456); | |
654 | //^^ &self ^^^^ param | ||
1014 | Test::from_syntax( | 655 | Test::from_syntax( |
1015 | FileId {}, | 656 | FileId {}, |
657 | //^^^^^^^^^ file_id | ||
1016 | "impl".into(), | 658 | "impl".into(), |
659 | //^^^^^^^^^^^^^ name | ||
1017 | None, | 660 | None, |
661 | //^^^^ focus_range | ||
1018 | TextRange {}, | 662 | TextRange {}, |
663 | //^^^^^^^^^^^^ full_range | ||
1019 | SyntaxKind {}, | 664 | SyntaxKind {}, |
665 | //^^^^^^^^^^^^^ kind | ||
1020 | None, | 666 | None, |
1021 | None, | 667 | //^^^^ docs |
1022 | ); | 668 | ); |
1023 | }"#, | 669 | }"#, |
1024 | ); | 670 | ); |
1025 | |||
1026 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" | ||
1027 | [ | ||
1028 | InlayHint { | ||
1029 | range: 797..808, | ||
1030 | kind: TypeHint, | ||
1031 | label: "i32", | ||
1032 | }, | ||
1033 | InlayHint { | ||
1034 | range: 841..842, | ||
1035 | kind: ParameterHint, | ||
1036 | label: "foo", | ||
1037 | }, | ||
1038 | InlayHint { | ||
1039 | range: 844..845, | ||
1040 | kind: ParameterHint, | ||
1041 | label: "bar", | ||
1042 | }, | ||
1043 | InlayHint { | ||
1044 | range: 847..854, | ||
1045 | kind: ParameterHint, | ||
1046 | label: "msg", | ||
1047 | }, | ||
1048 | InlayHint { | ||
1049 | range: 859..870, | ||
1050 | kind: ParameterHint, | ||
1051 | label: "last", | ||
1052 | }, | ||
1053 | InlayHint { | ||
1054 | range: 913..916, | ||
1055 | kind: ParameterHint, | ||
1056 | label: "param", | ||
1057 | }, | ||
1058 | InlayHint { | ||
1059 | range: 936..938, | ||
1060 | kind: ParameterHint, | ||
1061 | label: "&self", | ||
1062 | }, | ||
1063 | InlayHint { | ||
1064 | range: 940..944, | ||
1065 | kind: ParameterHint, | ||
1066 | label: "param", | ||
1067 | }, | ||
1068 | InlayHint { | ||
1069 | range: 979..988, | ||
1070 | kind: ParameterHint, | ||
1071 | label: "file_id", | ||
1072 | }, | ||
1073 | InlayHint { | ||
1074 | range: 998..1011, | ||
1075 | kind: ParameterHint, | ||
1076 | label: "name", | ||
1077 | }, | ||
1078 | InlayHint { | ||
1079 | range: 1021..1025, | ||
1080 | kind: ParameterHint, | ||
1081 | label: "focus_range", | ||
1082 | }, | ||
1083 | InlayHint { | ||
1084 | range: 1035..1047, | ||
1085 | kind: ParameterHint, | ||
1086 | label: "full_range", | ||
1087 | }, | ||
1088 | InlayHint { | ||
1089 | range: 1057..1070, | ||
1090 | kind: ParameterHint, | ||
1091 | label: "kind", | ||
1092 | }, | ||
1093 | InlayHint { | ||
1094 | range: 1080..1084, | ||
1095 | kind: ParameterHint, | ||
1096 | label: "docs", | ||
1097 | }, | ||
1098 | InlayHint { | ||
1099 | range: 1094..1098, | ||
1100 | kind: ParameterHint, | ||
1101 | label: "description", | ||
1102 | }, | ||
1103 | ] | ||
1104 | "### | ||
1105 | ); | ||
1106 | } | 671 | } |
1107 | 672 | ||
1108 | #[test] | 673 | #[test] |
1109 | fn omitted_parameters_hints_heuristics() { | 674 | fn omitted_parameters_hints_heuristics() { |
1110 | let (analysis, file_id) = single_file( | 675 | check_with_config( |
1111 | r#" | 676 | r#" |
1112 | fn map(f: i32) {} | 677 | fn map(f: i32) {} |
1113 | fn filter(predicate: i32) {} | 678 | fn filter(predicate: i32) {} |
@@ -1188,23 +753,16 @@ fn main() { | |||
1188 | let _: f64 = a.div_euclid(b); | 753 | let _: f64 = a.div_euclid(b); |
1189 | let _: f64 = a.abs_sub(b); | 754 | let _: f64 = a.abs_sub(b); |
1190 | }"#, | 755 | }"#, |
1191 | ); | 756 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, |
1192 | |||
1193 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###" | ||
1194 | [] | ||
1195 | "### | ||
1196 | ); | 757 | ); |
1197 | } | 758 | } |
1198 | 759 | ||
1199 | #[test] | 760 | #[test] |
1200 | fn unit_structs_have_no_type_hints() { | 761 | fn unit_structs_have_no_type_hints() { |
1201 | let (analysis, file_id) = single_file( | 762 | check_with_config( |
1202 | r#" | 763 | r#" |
1203 | enum CustomResult<T, E> { | 764 | enum Result<T, E> { Ok(T), Err(E) } |
1204 | Ok(T), | 765 | use Result::*; |
1205 | Err(E), | ||
1206 | } | ||
1207 | use CustomResult::*; | ||
1208 | 766 | ||
1209 | struct SyntheticSyntax; | 767 | struct SyntheticSyntax; |
1210 | 768 | ||
@@ -1214,136 +772,157 @@ fn main() { | |||
1214 | Err(SyntheticSyntax) => (), | 772 | Err(SyntheticSyntax) => (), |
1215 | } | 773 | } |
1216 | }"#, | 774 | }"#, |
1217 | ); | 775 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, |
1218 | |||
1219 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###" | ||
1220 | [] | ||
1221 | "### | ||
1222 | ); | 776 | ); |
1223 | } | 777 | } |
1224 | 778 | ||
1225 | #[test] | 779 | #[test] |
1226 | fn chaining_hints_ignore_comments() { | 780 | fn chaining_hints_ignore_comments() { |
1227 | let (analysis, file_id) = single_file( | 781 | check_expect( |
1228 | r#" | 782 | r#" |
1229 | struct A(B); | 783 | struct A(B); |
1230 | impl A { fn into_b(self) -> B { self.0 } } | 784 | impl A { fn into_b(self) -> B { self.0 } } |
1231 | struct B(C); | 785 | struct B(C); |
1232 | impl B { fn into_c(self) -> C { self.0 } } | 786 | impl B { fn into_c(self) -> C { self.0 } } |
1233 | struct C; | 787 | struct C; |
1234 | 788 | ||
1235 | fn main() { | 789 | fn main() { |
1236 | let c = A(B(C)) | 790 | let c = A(B(C)) |
1237 | .into_b() // This is a comment | 791 | .into_b() // This is a comment |
1238 | .into_c(); | 792 | .into_c(); |
1239 | }"#, | 793 | } |
794 | "#, | ||
795 | InlayHintsConfig { | ||
796 | parameter_hints: false, | ||
797 | type_hints: false, | ||
798 | chaining_hints: true, | ||
799 | max_length: None, | ||
800 | }, | ||
801 | expect![[r#" | ||
802 | [ | ||
803 | InlayHint { | ||
804 | range: 147..172, | ||
805 | kind: ChainingHint, | ||
806 | label: "B", | ||
807 | }, | ||
808 | InlayHint { | ||
809 | range: 147..154, | ||
810 | kind: ChainingHint, | ||
811 | label: "A", | ||
812 | }, | ||
813 | ] | ||
814 | "#]], | ||
1240 | ); | 815 | ); |
1241 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | ||
1242 | [ | ||
1243 | InlayHint { | ||
1244 | range: 147..172, | ||
1245 | kind: ChainingHint, | ||
1246 | label: "B", | ||
1247 | }, | ||
1248 | InlayHint { | ||
1249 | range: 147..154, | ||
1250 | kind: ChainingHint, | ||
1251 | label: "A", | ||
1252 | }, | ||
1253 | ] | ||
1254 | "###); | ||
1255 | } | 816 | } |
1256 | 817 | ||
1257 | #[test] | 818 | #[test] |
1258 | fn chaining_hints_without_newlines() { | 819 | fn chaining_hints_without_newlines() { |
1259 | let (analysis, file_id) = single_file( | 820 | check_with_config( |
1260 | r#" | 821 | r#" |
1261 | struct A(B); | 822 | struct A(B); |
1262 | impl A { fn into_b(self) -> B { self.0 } } | 823 | impl A { fn into_b(self) -> B { self.0 } } |
1263 | struct B(C); | 824 | struct B(C); |
1264 | impl B { fn into_c(self) -> C { self.0 } } | 825 | impl B { fn into_c(self) -> C { self.0 } } |
1265 | struct C; | 826 | struct C; |
1266 | 827 | ||
1267 | fn main() { | 828 | fn main() { |
1268 | let c = A(B(C)).into_b().into_c(); | 829 | let c = A(B(C)).into_b().into_c(); |
1269 | }"#, | 830 | }"#, |
831 | InlayHintsConfig { | ||
832 | parameter_hints: false, | ||
833 | type_hints: false, | ||
834 | chaining_hints: true, | ||
835 | max_length: None, | ||
836 | }, | ||
1270 | ); | 837 | ); |
1271 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###); | ||
1272 | } | 838 | } |
1273 | 839 | ||
1274 | #[test] | 840 | #[test] |
1275 | fn struct_access_chaining_hints() { | 841 | fn struct_access_chaining_hints() { |
1276 | let (analysis, file_id) = single_file( | 842 | check_expect( |
1277 | r#" | 843 | r#" |
1278 | struct A { pub b: B } | 844 | struct A { pub b: B } |
1279 | struct B { pub c: C } | 845 | struct B { pub c: C } |
1280 | struct C(pub bool); | 846 | struct C(pub bool); |
1281 | struct D; | 847 | struct D; |
1282 | 848 | ||
1283 | impl D { | 849 | impl D { |
1284 | fn foo(&self) -> i32 { 42 } | 850 | fn foo(&self) -> i32 { 42 } |
1285 | } | 851 | } |
1286 | 852 | ||
1287 | fn main() { | 853 | fn main() { |
1288 | let x = A { b: B { c: C(true) } } | 854 | let x = A { b: B { c: C(true) } } |
1289 | .b | 855 | .b |
1290 | .c | 856 | .c |
1291 | .0; | 857 | .0; |
1292 | let x = D | 858 | let x = D |
1293 | .foo(); | 859 | .foo(); |
1294 | }"#, | 860 | }"#, |
861 | InlayHintsConfig { | ||
862 | parameter_hints: false, | ||
863 | type_hints: false, | ||
864 | chaining_hints: true, | ||
865 | max_length: None, | ||
866 | }, | ||
867 | expect![[r#" | ||
868 | [ | ||
869 | InlayHint { | ||
870 | range: 143..190, | ||
871 | kind: ChainingHint, | ||
872 | label: "C", | ||
873 | }, | ||
874 | InlayHint { | ||
875 | range: 143..179, | ||
876 | kind: ChainingHint, | ||
877 | label: "B", | ||
878 | }, | ||
879 | ] | ||
880 | "#]], | ||
1295 | ); | 881 | ); |
1296 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | ||
1297 | [ | ||
1298 | InlayHint { | ||
1299 | range: 143..190, | ||
1300 | kind: ChainingHint, | ||
1301 | label: "C", | ||
1302 | }, | ||
1303 | InlayHint { | ||
1304 | range: 143..179, | ||
1305 | kind: ChainingHint, | ||
1306 | label: "B", | ||
1307 | }, | ||
1308 | ] | ||
1309 | "###); | ||
1310 | } | 882 | } |
1311 | 883 | ||
1312 | #[test] | 884 | #[test] |
1313 | fn generic_chaining_hints() { | 885 | fn generic_chaining_hints() { |
1314 | let (analysis, file_id) = single_file( | 886 | check_expect( |
1315 | r#" | 887 | r#" |
1316 | struct A<T>(T); | 888 | struct A<T>(T); |
1317 | struct B<T>(T); | 889 | struct B<T>(T); |
1318 | struct C<T>(T); | 890 | struct C<T>(T); |
1319 | struct X<T,R>(T, R); | 891 | struct X<T,R>(T, R); |
1320 | 892 | ||
1321 | impl<T> A<T> { | 893 | impl<T> A<T> { |
1322 | fn new(t: T) -> Self { A(t) } | 894 | fn new(t: T) -> Self { A(t) } |
1323 | fn into_b(self) -> B<T> { B(self.0) } | 895 | fn into_b(self) -> B<T> { B(self.0) } |
1324 | } | 896 | } |
1325 | impl<T> B<T> { | 897 | impl<T> B<T> { |
1326 | fn into_c(self) -> C<T> { C(self.0) } | 898 | fn into_c(self) -> C<T> { C(self.0) } |
1327 | } | 899 | } |
1328 | fn main() { | 900 | fn main() { |
1329 | let c = A::new(X(42, true)) | 901 | let c = A::new(X(42, true)) |
1330 | .into_b() | 902 | .into_b() |
1331 | .into_c(); | 903 | .into_c(); |
1332 | }"#, | 904 | } |
905 | "#, | ||
906 | InlayHintsConfig { | ||
907 | parameter_hints: false, | ||
908 | type_hints: false, | ||
909 | chaining_hints: true, | ||
910 | max_length: None, | ||
911 | }, | ||
912 | expect![[r#" | ||
913 | [ | ||
914 | InlayHint { | ||
915 | range: 246..283, | ||
916 | kind: ChainingHint, | ||
917 | label: "B<X<i32, bool>>", | ||
918 | }, | ||
919 | InlayHint { | ||
920 | range: 246..265, | ||
921 | kind: ChainingHint, | ||
922 | label: "A<X<i32, bool>>", | ||
923 | }, | ||
924 | ] | ||
925 | "#]], | ||
1333 | ); | 926 | ); |
1334 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | ||
1335 | [ | ||
1336 | InlayHint { | ||
1337 | range: 246..283, | ||
1338 | kind: ChainingHint, | ||
1339 | label: "B<X<i32, bool>>", | ||
1340 | }, | ||
1341 | InlayHint { | ||
1342 | range: 246..265, | ||
1343 | kind: ChainingHint, | ||
1344 | label: "A<X<i32, bool>>", | ||
1345 | }, | ||
1346 | ] | ||
1347 | "###); | ||
1348 | } | 927 | } |
1349 | } | 928 | } |
diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs index 5036c1fb0..6907c09e8 100644 --- a/crates/ra_ide/src/join_lines.rs +++ b/crates/ra_ide/src/join_lines.rs | |||
@@ -165,10 +165,7 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Opti | |||
165 | } | 165 | } |
166 | 166 | ||
167 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | 167 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { |
168 | match (left, right) { | 168 | matches!((left, right), (T![,], T![')']) | (T![,], T![']'])) |
169 | (T![,], T![')']) | (T![,], T![']']) => true, | ||
170 | _ => false, | ||
171 | } | ||
172 | } | 169 | } |
173 | 170 | ||
174 | #[cfg(test)] | 171 | #[cfg(test)] |
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs index 889b84c59..a393d3dba 100644 --- a/crates/ra_ide/src/mock_analysis.rs +++ b/crates/ra_ide/src/mock_analysis.rs | |||
@@ -3,7 +3,9 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use ra_cfg::CfgOptions; | 4 | use ra_cfg::CfgOptions; |
5 | use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; | 5 | use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; |
6 | use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; | 6 | use test_utils::{ |
7 | extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, | ||
8 | }; | ||
7 | 9 | ||
8 | use crate::{ | 10 | use crate::{ |
9 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, | 11 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, |
@@ -77,6 +79,24 @@ impl MockAnalysis { | |||
77 | .expect("no file in this mock"); | 79 | .expect("no file in this mock"); |
78 | FileId(idx as u32 + 1) | 80 | FileId(idx as u32 + 1) |
79 | } | 81 | } |
82 | pub fn annotations(&self) -> Vec<(FileRange, String)> { | ||
83 | self.files | ||
84 | .iter() | ||
85 | .enumerate() | ||
86 | .flat_map(|(idx, fixture)| { | ||
87 | let file_id = FileId(idx as u32 + 1); | ||
88 | let annotations = extract_annotations(&fixture.text); | ||
89 | annotations | ||
90 | .into_iter() | ||
91 | .map(move |(range, data)| (FileRange { file_id, range }, data)) | ||
92 | }) | ||
93 | .collect() | ||
94 | } | ||
95 | pub fn annotation(&self) -> (FileRange, String) { | ||
96 | let mut all = self.annotations(); | ||
97 | assert_eq!(all.len(), 1); | ||
98 | all.pop().unwrap() | ||
99 | } | ||
80 | pub fn analysis_host(self) -> AnalysisHost { | 100 | pub fn analysis_host(self) -> AnalysisHost { |
81 | let mut host = AnalysisHost::default(); | 101 | let mut host = AnalysisHost::default(); |
82 | let mut change = AnalysisChange::new(); | 102 | let mut change = AnalysisChange::new(); |
@@ -110,7 +130,7 @@ impl MockAnalysis { | |||
110 | let other_crate = crate_graph.add_crate_root( | 130 | let other_crate = crate_graph.add_crate_root( |
111 | file_id, | 131 | file_id, |
112 | edition, | 132 | edition, |
113 | Some(CrateName::new(crate_name).unwrap()), | 133 | Some(crate_name.to_string()), |
114 | cfg, | 134 | cfg, |
115 | env, | 135 | env, |
116 | Default::default(), | 136 | Default::default(), |
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index f569a3f17..ed15d6494 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -251,13 +251,21 @@ fn runnable_mod( | |||
251 | 251 | ||
252 | #[cfg(test)] | 252 | #[cfg(test)] |
253 | mod tests { | 253 | mod tests { |
254 | use insta::assert_debug_snapshot; | 254 | use expect::{expect, Expect}; |
255 | 255 | ||
256 | use crate::mock_analysis::analysis_and_position; | 256 | use crate::mock_analysis::analysis_and_position; |
257 | 257 | ||
258 | use super::{Runnable, RunnableAction, BENCH, BIN, DOCTEST, TEST}; | 258 | use super::{RunnableAction, BENCH, BIN, DOCTEST, TEST}; |
259 | 259 | ||
260 | fn assert_actions(runnables: &[Runnable], actions: &[&RunnableAction]) { | 260 | fn check( |
261 | ra_fixture: &str, | ||
262 | // FIXME: fold this into `expect` as well | ||
263 | actions: &[&RunnableAction], | ||
264 | expect: Expect, | ||
265 | ) { | ||
266 | let (analysis, position) = analysis_and_position(ra_fixture); | ||
267 | let runnables = analysis.runnables(position.file_id).unwrap(); | ||
268 | expect.assert_debug_eq(&runnables); | ||
261 | assert_eq!( | 269 | assert_eq!( |
262 | actions, | 270 | actions, |
263 | runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice() | 271 | runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice() |
@@ -266,579 +274,557 @@ mod tests { | |||
266 | 274 | ||
267 | #[test] | 275 | #[test] |
268 | fn test_runnables() { | 276 | fn test_runnables() { |
269 | let (analysis, pos) = analysis_and_position( | 277 | check( |
270 | r#" | 278 | r#" |
271 | //- /lib.rs | 279 | //- /lib.rs |
272 | <|> //empty | 280 | <|> |
273 | fn main() {} | 281 | fn main() {} |
274 | 282 | ||
275 | #[test] | 283 | #[test] |
276 | fn test_foo() {} | 284 | fn test_foo() {} |
277 | 285 | ||
278 | #[test] | 286 | #[test] |
279 | #[ignore] | 287 | #[ignore] |
280 | fn test_foo() {} | 288 | fn test_foo() {} |
281 | 289 | ||
282 | #[bench] | 290 | #[bench] |
283 | fn bench() {} | 291 | fn bench() {} |
284 | "#, | 292 | "#, |
285 | ); | 293 | &[&BIN, &TEST, &TEST, &BENCH], |
286 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 294 | expect![[r#" |
287 | assert_debug_snapshot!(&runnables, | 295 | [ |
288 | @r###" | 296 | Runnable { |
289 | [ | 297 | nav: NavigationTarget { |
290 | Runnable { | 298 | file_id: FileId( |
291 | nav: NavigationTarget { | 299 | 1, |
292 | file_id: FileId( | 300 | ), |
293 | 1, | 301 | full_range: 1..13, |
294 | ), | 302 | name: "main", |
295 | full_range: 1..21, | 303 | kind: FN_DEF, |
296 | name: "main", | 304 | focus_range: Some( |
297 | kind: FN_DEF, | 305 | 4..8, |
298 | focus_range: Some( | 306 | ), |
299 | 12..16, | 307 | container_name: None, |
300 | ), | 308 | description: None, |
301 | container_name: None, | 309 | docs: None, |
302 | description: None, | 310 | }, |
303 | docs: None, | 311 | kind: Bin, |
304 | }, | 312 | cfg_exprs: [], |
305 | kind: Bin, | ||
306 | cfg_exprs: [], | ||
307 | }, | ||
308 | Runnable { | ||
309 | nav: NavigationTarget { | ||
310 | file_id: FileId( | ||
311 | 1, | ||
312 | ), | ||
313 | full_range: 23..47, | ||
314 | name: "test_foo", | ||
315 | kind: FN_DEF, | ||
316 | focus_range: Some( | ||
317 | 34..42, | ||
318 | ), | ||
319 | container_name: None, | ||
320 | description: None, | ||
321 | docs: None, | ||
322 | }, | ||
323 | kind: Test { | ||
324 | test_id: Path( | ||
325 | "test_foo", | ||
326 | ), | ||
327 | attr: TestAttr { | ||
328 | ignore: false, | ||
329 | }, | 313 | }, |
330 | }, | 314 | Runnable { |
331 | cfg_exprs: [], | 315 | nav: NavigationTarget { |
332 | }, | 316 | file_id: FileId( |
333 | Runnable { | 317 | 1, |
334 | nav: NavigationTarget { | 318 | ), |
335 | file_id: FileId( | 319 | full_range: 15..39, |
336 | 1, | 320 | name: "test_foo", |
337 | ), | 321 | kind: FN_DEF, |
338 | full_range: 49..83, | 322 | focus_range: Some( |
339 | name: "test_foo", | 323 | 26..34, |
340 | kind: FN_DEF, | 324 | ), |
341 | focus_range: Some( | 325 | container_name: None, |
342 | 70..78, | 326 | description: None, |
343 | ), | 327 | docs: None, |
344 | container_name: None, | 328 | }, |
345 | description: None, | 329 | kind: Test { |
346 | docs: None, | 330 | test_id: Path( |
347 | }, | 331 | "test_foo", |
348 | kind: Test { | 332 | ), |
349 | test_id: Path( | 333 | attr: TestAttr { |
350 | "test_foo", | 334 | ignore: false, |
351 | ), | 335 | }, |
352 | attr: TestAttr { | 336 | }, |
353 | ignore: true, | 337 | cfg_exprs: [], |
338 | }, | ||
339 | Runnable { | ||
340 | nav: NavigationTarget { | ||
341 | file_id: FileId( | ||
342 | 1, | ||
343 | ), | ||
344 | full_range: 41..75, | ||
345 | name: "test_foo", | ||
346 | kind: FN_DEF, | ||
347 | focus_range: Some( | ||
348 | 62..70, | ||
349 | ), | ||
350 | container_name: None, | ||
351 | description: None, | ||
352 | docs: None, | ||
353 | }, | ||
354 | kind: Test { | ||
355 | test_id: Path( | ||
356 | "test_foo", | ||
357 | ), | ||
358 | attr: TestAttr { | ||
359 | ignore: true, | ||
360 | }, | ||
361 | }, | ||
362 | cfg_exprs: [], | ||
354 | }, | 363 | }, |
355 | }, | 364 | Runnable { |
356 | cfg_exprs: [], | 365 | nav: NavigationTarget { |
357 | }, | 366 | file_id: FileId( |
358 | Runnable { | 367 | 1, |
359 | nav: NavigationTarget { | 368 | ), |
360 | file_id: FileId( | 369 | full_range: 77..99, |
361 | 1, | 370 | name: "bench", |
362 | ), | 371 | kind: FN_DEF, |
363 | full_range: 85..107, | 372 | focus_range: Some( |
364 | name: "bench", | 373 | 89..94, |
365 | kind: FN_DEF, | 374 | ), |
366 | focus_range: Some( | 375 | container_name: None, |
367 | 97..102, | 376 | description: None, |
368 | ), | 377 | docs: None, |
369 | container_name: None, | 378 | }, |
370 | description: None, | 379 | kind: Bench { |
371 | docs: None, | 380 | test_id: Path( |
372 | }, | 381 | "bench", |
373 | kind: Bench { | 382 | ), |
374 | test_id: Path( | 383 | }, |
375 | "bench", | 384 | cfg_exprs: [], |
376 | ), | 385 | }, |
377 | }, | 386 | ] |
378 | cfg_exprs: [], | 387 | "#]], |
379 | }, | 388 | ); |
380 | ] | ||
381 | "### | ||
382 | ); | ||
383 | assert_actions(&runnables, &[&BIN, &TEST, &TEST, &BENCH]); | ||
384 | } | 389 | } |
385 | 390 | ||
386 | #[test] | 391 | #[test] |
387 | fn test_runnables_doc_test() { | 392 | fn test_runnables_doc_test() { |
388 | let (analysis, pos) = analysis_and_position( | 393 | check( |
389 | r#" | 394 | r#" |
390 | //- /lib.rs | 395 | //- /lib.rs |
391 | <|> //empty | 396 | <|> |
392 | fn main() {} | 397 | fn main() {} |
393 | 398 | ||
394 | /// ``` | 399 | /// ``` |
395 | /// let x = 5; | 400 | /// let x = 5; |
396 | /// ``` | 401 | /// ``` |
397 | fn foo() {} | 402 | fn foo() {} |
398 | "#, | 403 | "#, |
404 | &[&BIN, &DOCTEST], | ||
405 | expect![[r#" | ||
406 | [ | ||
407 | Runnable { | ||
408 | nav: NavigationTarget { | ||
409 | file_id: FileId( | ||
410 | 1, | ||
411 | ), | ||
412 | full_range: 1..13, | ||
413 | name: "main", | ||
414 | kind: FN_DEF, | ||
415 | focus_range: Some( | ||
416 | 4..8, | ||
417 | ), | ||
418 | container_name: None, | ||
419 | description: None, | ||
420 | docs: None, | ||
421 | }, | ||
422 | kind: Bin, | ||
423 | cfg_exprs: [], | ||
424 | }, | ||
425 | Runnable { | ||
426 | nav: NavigationTarget { | ||
427 | file_id: FileId( | ||
428 | 1, | ||
429 | ), | ||
430 | full_range: 15..57, | ||
431 | name: "foo", | ||
432 | kind: FN_DEF, | ||
433 | focus_range: None, | ||
434 | container_name: None, | ||
435 | description: None, | ||
436 | docs: None, | ||
437 | }, | ||
438 | kind: DocTest { | ||
439 | test_id: Path( | ||
440 | "foo", | ||
441 | ), | ||
442 | }, | ||
443 | cfg_exprs: [], | ||
444 | }, | ||
445 | ] | ||
446 | "#]], | ||
399 | ); | 447 | ); |
400 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
401 | assert_debug_snapshot!(&runnables, | ||
402 | @r###" | ||
403 | [ | ||
404 | Runnable { | ||
405 | nav: NavigationTarget { | ||
406 | file_id: FileId( | ||
407 | 1, | ||
408 | ), | ||
409 | full_range: 1..21, | ||
410 | name: "main", | ||
411 | kind: FN_DEF, | ||
412 | focus_range: Some( | ||
413 | 12..16, | ||
414 | ), | ||
415 | container_name: None, | ||
416 | description: None, | ||
417 | docs: None, | ||
418 | }, | ||
419 | kind: Bin, | ||
420 | cfg_exprs: [], | ||
421 | }, | ||
422 | Runnable { | ||
423 | nav: NavigationTarget { | ||
424 | file_id: FileId( | ||
425 | 1, | ||
426 | ), | ||
427 | full_range: 23..65, | ||
428 | name: "foo", | ||
429 | kind: FN_DEF, | ||
430 | focus_range: None, | ||
431 | container_name: None, | ||
432 | description: None, | ||
433 | docs: None, | ||
434 | }, | ||
435 | kind: DocTest { | ||
436 | test_id: Path( | ||
437 | "foo", | ||
438 | ), | ||
439 | }, | ||
440 | cfg_exprs: [], | ||
441 | }, | ||
442 | ] | ||
443 | "### | ||
444 | ); | ||
445 | assert_actions(&runnables, &[&BIN, &DOCTEST]); | ||
446 | } | 448 | } |
447 | 449 | ||
448 | #[test] | 450 | #[test] |
449 | fn test_runnables_doc_test_in_impl() { | 451 | fn test_runnables_doc_test_in_impl() { |
450 | let (analysis, pos) = analysis_and_position( | 452 | check( |
451 | r#" | 453 | r#" |
452 | //- /lib.rs | 454 | //- /lib.rs |
453 | <|> //empty | 455 | <|> |
454 | fn main() {} | 456 | fn main() {} |
455 | 457 | ||
456 | struct Data; | 458 | struct Data; |
457 | impl Data { | 459 | impl Data { |
458 | /// ``` | 460 | /// ``` |
459 | /// let x = 5; | 461 | /// let x = 5; |
460 | /// ``` | 462 | /// ``` |
461 | fn foo() {} | 463 | fn foo() {} |
462 | } | 464 | } |
463 | "#, | 465 | "#, |
466 | &[&BIN, &DOCTEST], | ||
467 | expect![[r#" | ||
468 | [ | ||
469 | Runnable { | ||
470 | nav: NavigationTarget { | ||
471 | file_id: FileId( | ||
472 | 1, | ||
473 | ), | ||
474 | full_range: 1..13, | ||
475 | name: "main", | ||
476 | kind: FN_DEF, | ||
477 | focus_range: Some( | ||
478 | 4..8, | ||
479 | ), | ||
480 | container_name: None, | ||
481 | description: None, | ||
482 | docs: None, | ||
483 | }, | ||
484 | kind: Bin, | ||
485 | cfg_exprs: [], | ||
486 | }, | ||
487 | Runnable { | ||
488 | nav: NavigationTarget { | ||
489 | file_id: FileId( | ||
490 | 1, | ||
491 | ), | ||
492 | full_range: 44..98, | ||
493 | name: "foo", | ||
494 | kind: FN_DEF, | ||
495 | focus_range: None, | ||
496 | container_name: None, | ||
497 | description: None, | ||
498 | docs: None, | ||
499 | }, | ||
500 | kind: DocTest { | ||
501 | test_id: Path( | ||
502 | "Data::foo", | ||
503 | ), | ||
504 | }, | ||
505 | cfg_exprs: [], | ||
506 | }, | ||
507 | ] | ||
508 | "#]], | ||
464 | ); | 509 | ); |
465 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
466 | assert_debug_snapshot!(&runnables, | ||
467 | @r###" | ||
468 | [ | ||
469 | Runnable { | ||
470 | nav: NavigationTarget { | ||
471 | file_id: FileId( | ||
472 | 1, | ||
473 | ), | ||
474 | full_range: 1..21, | ||
475 | name: "main", | ||
476 | kind: FN_DEF, | ||
477 | focus_range: Some( | ||
478 | 12..16, | ||
479 | ), | ||
480 | container_name: None, | ||
481 | description: None, | ||
482 | docs: None, | ||
483 | }, | ||
484 | kind: Bin, | ||
485 | cfg_exprs: [], | ||
486 | }, | ||
487 | Runnable { | ||
488 | nav: NavigationTarget { | ||
489 | file_id: FileId( | ||
490 | 1, | ||
491 | ), | ||
492 | full_range: 52..106, | ||
493 | name: "foo", | ||
494 | kind: FN_DEF, | ||
495 | focus_range: None, | ||
496 | container_name: None, | ||
497 | description: None, | ||
498 | docs: None, | ||
499 | }, | ||
500 | kind: DocTest { | ||
501 | test_id: Path( | ||
502 | "Data::foo", | ||
503 | ), | ||
504 | }, | ||
505 | cfg_exprs: [], | ||
506 | }, | ||
507 | ] | ||
508 | "### | ||
509 | ); | ||
510 | assert_actions(&runnables, &[&BIN, &DOCTEST]); | ||
511 | } | 510 | } |
512 | 511 | ||
513 | #[test] | 512 | #[test] |
514 | fn test_runnables_module() { | 513 | fn test_runnables_module() { |
515 | let (analysis, pos) = analysis_and_position( | 514 | check( |
516 | r#" | 515 | r#" |
517 | //- /lib.rs | 516 | //- /lib.rs |
518 | <|> //empty | 517 | <|> |
519 | mod test_mod { | 518 | mod test_mod { |
520 | #[test] | 519 | #[test] |
521 | fn test_foo1() {} | 520 | fn test_foo1() {} |
522 | } | 521 | } |
523 | "#, | 522 | "#, |
524 | ); | 523 | &[&TEST, &TEST], |
525 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 524 | expect![[r#" |
526 | assert_debug_snapshot!(&runnables, | 525 | [ |
527 | @r###" | 526 | Runnable { |
528 | [ | 527 | nav: NavigationTarget { |
529 | Runnable { | 528 | file_id: FileId( |
530 | nav: NavigationTarget { | 529 | 1, |
531 | file_id: FileId( | 530 | ), |
532 | 1, | 531 | full_range: 1..51, |
533 | ), | 532 | name: "test_mod", |
534 | full_range: 1..59, | 533 | kind: MODULE, |
535 | name: "test_mod", | 534 | focus_range: Some( |
536 | kind: MODULE, | 535 | 5..13, |
537 | focus_range: Some( | 536 | ), |
538 | 13..21, | 537 | container_name: None, |
539 | ), | 538 | description: None, |
540 | container_name: None, | 539 | docs: None, |
541 | description: None, | 540 | }, |
542 | docs: None, | 541 | kind: TestMod { |
543 | }, | 542 | path: "test_mod", |
544 | kind: TestMod { | 543 | }, |
545 | path: "test_mod", | 544 | cfg_exprs: [], |
546 | }, | 545 | }, |
547 | cfg_exprs: [], | 546 | Runnable { |
548 | }, | 547 | nav: NavigationTarget { |
549 | Runnable { | 548 | file_id: FileId( |
550 | nav: NavigationTarget { | 549 | 1, |
551 | file_id: FileId( | 550 | ), |
552 | 1, | 551 | full_range: 20..49, |
553 | ), | 552 | name: "test_foo1", |
554 | full_range: 28..57, | 553 | kind: FN_DEF, |
555 | name: "test_foo1", | 554 | focus_range: Some( |
556 | kind: FN_DEF, | 555 | 35..44, |
557 | focus_range: Some( | 556 | ), |
558 | 43..52, | 557 | container_name: None, |
559 | ), | 558 | description: None, |
560 | container_name: None, | 559 | docs: None, |
561 | description: None, | 560 | }, |
562 | docs: None, | 561 | kind: Test { |
563 | }, | 562 | test_id: Path( |
564 | kind: Test { | 563 | "test_mod::test_foo1", |
565 | test_id: Path( | 564 | ), |
566 | "test_mod::test_foo1", | 565 | attr: TestAttr { |
567 | ), | 566 | ignore: false, |
568 | attr: TestAttr { | 567 | }, |
569 | ignore: false, | 568 | }, |
569 | cfg_exprs: [], | ||
570 | }, | 570 | }, |
571 | }, | 571 | ] |
572 | cfg_exprs: [], | 572 | "#]], |
573 | }, | 573 | ); |
574 | ] | ||
575 | "### | ||
576 | ); | ||
577 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
578 | } | 574 | } |
579 | 575 | ||
580 | #[test] | 576 | #[test] |
581 | fn test_runnables_one_depth_layer_module() { | 577 | fn test_runnables_one_depth_layer_module() { |
582 | let (analysis, pos) = analysis_and_position( | 578 | check( |
583 | r#" | 579 | r#" |
584 | //- /lib.rs | 580 | //- /lib.rs |
585 | <|> //empty | 581 | <|> |
586 | mod foo { | 582 | mod foo { |
587 | mod test_mod { | 583 | mod test_mod { |
588 | #[test] | 584 | #[test] |
589 | fn test_foo1() {} | 585 | fn test_foo1() {} |
590 | } | 586 | } |
591 | } | 587 | } |
592 | "#, | 588 | "#, |
593 | ); | 589 | &[&TEST, &TEST], |
594 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 590 | expect![[r#" |
595 | assert_debug_snapshot!(&runnables, | 591 | [ |
596 | @r###" | 592 | Runnable { |
597 | [ | 593 | nav: NavigationTarget { |
598 | Runnable { | 594 | file_id: FileId( |
599 | nav: NavigationTarget { | 595 | 1, |
600 | file_id: FileId( | 596 | ), |
601 | 1, | 597 | full_range: 15..77, |
602 | ), | 598 | name: "test_mod", |
603 | full_range: 23..85, | 599 | kind: MODULE, |
604 | name: "test_mod", | 600 | focus_range: Some( |
605 | kind: MODULE, | 601 | 19..27, |
606 | focus_range: Some( | 602 | ), |
607 | 27..35, | 603 | container_name: None, |
608 | ), | 604 | description: None, |
609 | container_name: None, | 605 | docs: None, |
610 | description: None, | 606 | }, |
611 | docs: None, | 607 | kind: TestMod { |
612 | }, | 608 | path: "foo::test_mod", |
613 | kind: TestMod { | 609 | }, |
614 | path: "foo::test_mod", | 610 | cfg_exprs: [], |
615 | }, | 611 | }, |
616 | cfg_exprs: [], | 612 | Runnable { |
617 | }, | 613 | nav: NavigationTarget { |
618 | Runnable { | 614 | file_id: FileId( |
619 | nav: NavigationTarget { | 615 | 1, |
620 | file_id: FileId( | 616 | ), |
621 | 1, | 617 | full_range: 38..71, |
622 | ), | 618 | name: "test_foo1", |
623 | full_range: 46..79, | 619 | kind: FN_DEF, |
624 | name: "test_foo1", | 620 | focus_range: Some( |
625 | kind: FN_DEF, | 621 | 57..66, |
626 | focus_range: Some( | 622 | ), |
627 | 65..74, | 623 | container_name: None, |
628 | ), | 624 | description: None, |
629 | container_name: None, | 625 | docs: None, |
630 | description: None, | 626 | }, |
631 | docs: None, | 627 | kind: Test { |
632 | }, | 628 | test_id: Path( |
633 | kind: Test { | 629 | "foo::test_mod::test_foo1", |
634 | test_id: Path( | 630 | ), |
635 | "foo::test_mod::test_foo1", | 631 | attr: TestAttr { |
636 | ), | 632 | ignore: false, |
637 | attr: TestAttr { | 633 | }, |
638 | ignore: false, | 634 | }, |
635 | cfg_exprs: [], | ||
639 | }, | 636 | }, |
640 | }, | 637 | ] |
641 | cfg_exprs: [], | 638 | "#]], |
642 | }, | 639 | ); |
643 | ] | ||
644 | "### | ||
645 | ); | ||
646 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
647 | } | 640 | } |
648 | 641 | ||
649 | #[test] | 642 | #[test] |
650 | fn test_runnables_multiple_depth_module() { | 643 | fn test_runnables_multiple_depth_module() { |
651 | let (analysis, pos) = analysis_and_position( | 644 | check( |
652 | r#" | 645 | r#" |
653 | //- /lib.rs | 646 | //- /lib.rs |
654 | <|> //empty | 647 | <|> |
655 | mod foo { | 648 | mod foo { |
656 | mod bar { | 649 | mod bar { |
657 | mod test_mod { | 650 | mod test_mod { |
658 | #[test] | 651 | #[test] |
659 | fn test_foo1() {} | 652 | fn test_foo1() {} |
660 | } | ||
661 | } | ||
662 | } | 653 | } |
663 | "#, | 654 | } |
664 | ); | 655 | } |
665 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 656 | "#, |
666 | assert_debug_snapshot!(&runnables, | 657 | &[&TEST, &TEST], |
667 | @r###" | 658 | expect![[r#" |
668 | [ | 659 | [ |
669 | Runnable { | 660 | Runnable { |
670 | nav: NavigationTarget { | 661 | nav: NavigationTarget { |
671 | file_id: FileId( | 662 | file_id: FileId( |
672 | 1, | 663 | 1, |
673 | ), | 664 | ), |
674 | full_range: 41..115, | 665 | full_range: 33..107, |
675 | name: "test_mod", | 666 | name: "test_mod", |
676 | kind: MODULE, | 667 | kind: MODULE, |
677 | focus_range: Some( | 668 | focus_range: Some( |
678 | 45..53, | 669 | 37..45, |
679 | ), | 670 | ), |
680 | container_name: None, | 671 | container_name: None, |
681 | description: None, | 672 | description: None, |
682 | docs: None, | 673 | docs: None, |
683 | }, | 674 | }, |
684 | kind: TestMod { | 675 | kind: TestMod { |
685 | path: "foo::bar::test_mod", | 676 | path: "foo::bar::test_mod", |
686 | }, | 677 | }, |
687 | cfg_exprs: [], | 678 | cfg_exprs: [], |
688 | }, | 679 | }, |
689 | Runnable { | 680 | Runnable { |
690 | nav: NavigationTarget { | 681 | nav: NavigationTarget { |
691 | file_id: FileId( | 682 | file_id: FileId( |
692 | 1, | 683 | 1, |
693 | ), | 684 | ), |
694 | full_range: 68..105, | 685 | full_range: 60..97, |
695 | name: "test_foo1", | 686 | name: "test_foo1", |
696 | kind: FN_DEF, | 687 | kind: FN_DEF, |
697 | focus_range: Some( | 688 | focus_range: Some( |
698 | 91..100, | 689 | 83..92, |
699 | ), | 690 | ), |
700 | container_name: None, | 691 | container_name: None, |
701 | description: None, | 692 | description: None, |
702 | docs: None, | 693 | docs: None, |
703 | }, | 694 | }, |
704 | kind: Test { | 695 | kind: Test { |
705 | test_id: Path( | 696 | test_id: Path( |
706 | "foo::bar::test_mod::test_foo1", | 697 | "foo::bar::test_mod::test_foo1", |
707 | ), | 698 | ), |
708 | attr: TestAttr { | 699 | attr: TestAttr { |
709 | ignore: false, | 700 | ignore: false, |
701 | }, | ||
702 | }, | ||
703 | cfg_exprs: [], | ||
710 | }, | 704 | }, |
711 | }, | 705 | ] |
712 | cfg_exprs: [], | 706 | "#]], |
713 | }, | 707 | ); |
714 | ] | ||
715 | "### | ||
716 | ); | ||
717 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
718 | } | 708 | } |
719 | 709 | ||
720 | #[test] | 710 | #[test] |
721 | fn test_runnables_with_feature() { | 711 | fn test_runnables_with_feature() { |
722 | let (analysis, pos) = analysis_and_position( | 712 | check( |
723 | r#" | 713 | r#" |
724 | //- /lib.rs crate:foo cfg:feature=foo | 714 | //- /lib.rs crate:foo cfg:feature=foo |
725 | <|> //empty | 715 | <|> |
726 | #[test] | 716 | #[test] |
727 | #[cfg(feature = "foo")] | 717 | #[cfg(feature = "foo")] |
728 | fn test_foo1() {} | 718 | fn test_foo1() {} |
729 | "#, | 719 | "#, |
730 | ); | 720 | &[&TEST], |
731 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 721 | expect![[r#" |
732 | assert_debug_snapshot!(&runnables, | 722 | [ |
733 | @r###" | 723 | Runnable { |
734 | [ | 724 | nav: NavigationTarget { |
735 | Runnable { | 725 | file_id: FileId( |
736 | nav: NavigationTarget { | 726 | 1, |
737 | file_id: FileId( | 727 | ), |
738 | 1, | 728 | full_range: 1..50, |
739 | ), | 729 | name: "test_foo1", |
740 | full_range: 1..58, | 730 | kind: FN_DEF, |
741 | name: "test_foo1", | 731 | focus_range: Some( |
742 | kind: FN_DEF, | 732 | 36..45, |
743 | focus_range: Some( | 733 | ), |
744 | 44..53, | 734 | container_name: None, |
745 | ), | 735 | description: None, |
746 | container_name: None, | 736 | docs: None, |
747 | description: None, | 737 | }, |
748 | docs: None, | 738 | kind: Test { |
749 | }, | 739 | test_id: Path( |
750 | kind: Test { | 740 | "test_foo1", |
751 | test_id: Path( | 741 | ), |
752 | "test_foo1", | 742 | attr: TestAttr { |
753 | ), | 743 | ignore: false, |
754 | attr: TestAttr { | 744 | }, |
755 | ignore: false, | 745 | }, |
756 | }, | 746 | cfg_exprs: [ |
757 | }, | 747 | KeyValue { |
758 | cfg_exprs: [ | 748 | key: "feature", |
759 | KeyValue { | 749 | value: "foo", |
760 | key: "feature", | 750 | }, |
761 | value: "foo", | 751 | ], |
762 | }, | 752 | }, |
763 | ], | 753 | ] |
764 | }, | 754 | "#]], |
765 | ] | 755 | ); |
766 | "### | ||
767 | ); | ||
768 | assert_actions(&runnables, &[&TEST]); | ||
769 | } | 756 | } |
770 | 757 | ||
771 | #[test] | 758 | #[test] |
772 | fn test_runnables_with_features() { | 759 | fn test_runnables_with_features() { |
773 | let (analysis, pos) = analysis_and_position( | 760 | check( |
774 | r#" | 761 | r#" |
775 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar | 762 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar |
776 | <|> //empty | 763 | <|> |
777 | #[test] | 764 | #[test] |
778 | #[cfg(all(feature = "foo", feature = "bar"))] | 765 | #[cfg(all(feature = "foo", feature = "bar"))] |
779 | fn test_foo1() {} | 766 | fn test_foo1() {} |
780 | "#, | 767 | "#, |
781 | ); | 768 | &[&TEST], |
782 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 769 | expect![[r#" |
783 | assert_debug_snapshot!(&runnables, | 770 | [ |
784 | @r###" | 771 | Runnable { |
785 | [ | 772 | nav: NavigationTarget { |
786 | Runnable { | 773 | file_id: FileId( |
787 | nav: NavigationTarget { | 774 | 1, |
788 | file_id: FileId( | 775 | ), |
789 | 1, | 776 | full_range: 1..72, |
790 | ), | 777 | name: "test_foo1", |
791 | full_range: 1..80, | 778 | kind: FN_DEF, |
792 | name: "test_foo1", | 779 | focus_range: Some( |
793 | kind: FN_DEF, | 780 | 58..67, |
794 | focus_range: Some( | 781 | ), |
795 | 66..75, | 782 | container_name: None, |
796 | ), | 783 | description: None, |
797 | container_name: None, | 784 | docs: None, |
798 | description: None, | 785 | }, |
799 | docs: None, | 786 | kind: Test { |
800 | }, | 787 | test_id: Path( |
801 | kind: Test { | 788 | "test_foo1", |
802 | test_id: Path( | 789 | ), |
803 | "test_foo1", | 790 | attr: TestAttr { |
804 | ), | 791 | ignore: false, |
805 | attr: TestAttr { | ||
806 | ignore: false, | ||
807 | }, | ||
808 | }, | ||
809 | cfg_exprs: [ | ||
810 | All( | ||
811 | [ | ||
812 | KeyValue { | ||
813 | key: "feature", | ||
814 | value: "foo", | ||
815 | }, | ||
816 | KeyValue { | ||
817 | key: "feature", | ||
818 | value: "bar", | ||
819 | }, | 792 | }, |
793 | }, | ||
794 | cfg_exprs: [ | ||
795 | All( | ||
796 | [ | ||
797 | KeyValue { | ||
798 | key: "feature", | ||
799 | value: "foo", | ||
800 | }, | ||
801 | KeyValue { | ||
802 | key: "feature", | ||
803 | value: "bar", | ||
804 | }, | ||
805 | ], | ||
806 | ), | ||
820 | ], | 807 | ], |
821 | ), | 808 | }, |
822 | ], | 809 | ] |
823 | }, | 810 | "#]], |
824 | ] | 811 | ); |
825 | "### | ||
826 | ); | ||
827 | assert_actions(&runnables, &[&TEST]); | ||
828 | } | 812 | } |
829 | 813 | ||
830 | #[test] | 814 | #[test] |
831 | fn test_runnables_no_test_function_in_module() { | 815 | fn test_runnables_no_test_function_in_module() { |
832 | let (analysis, pos) = analysis_and_position( | 816 | check( |
833 | r#" | 817 | r#" |
834 | //- /lib.rs | 818 | //- /lib.rs |
835 | <|> //empty | 819 | <|> |
836 | mod test_mod { | 820 | mod test_mod { |
837 | fn foo1() {} | 821 | fn foo1() {} |
838 | } | 822 | } |
839 | "#, | 823 | "#, |
824 | &[], | ||
825 | expect![[r#" | ||
826 | [] | ||
827 | "#]], | ||
840 | ); | 828 | ); |
841 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
842 | assert!(runnables.is_empty()) | ||
843 | } | 829 | } |
844 | } | 830 | } |
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs index 6cb96608b..9f8e540c0 100644 --- a/crates/ra_ide/src/ssr.rs +++ b/crates/ra_ide/src/ssr.rs | |||
@@ -4,7 +4,7 @@ use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | |||
4 | use crate::SourceFileEdit; | 4 | use crate::SourceFileEdit; |
5 | use ra_ssr::{MatchFinder, SsrError, SsrRule}; | 5 | use ra_ssr::{MatchFinder, SsrError, SsrRule}; |
6 | 6 | ||
7 | // Feature: Structural Seach and Replace | 7 | // Feature: Structural Search and Replace |
8 | // | 8 | // |
9 | // Search and replace with named wildcards that will match any expression, type, path, pattern or item. | 9 | // Search and replace with named wildcards that will match any expression, type, path, pattern or item. |
10 | // The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. | 10 | // The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. |