aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/call_hierarchy.rs73
-rw-r--r--crates/ide/src/diagnostics.rs118
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs15
-rw-r--r--crates/ide/src/diagnostics/fixes.rs36
-rw-r--r--crates/ide/src/display/navigation_target.rs35
-rw-r--r--crates/ide/src/doc_links.rs50
-rw-r--r--crates/ide/src/expand_macro.rs12
-rw-r--r--crates/ide/src/extend_selection.rs114
-rw-r--r--crates/ide/src/fixture.rs12
-rw-r--r--crates/ide/src/fn_references.rs6
-rw-r--r--crates/ide/src/goto_definition.rs267
-rw-r--r--crates/ide/src/goto_implementation.rs16
-rw-r--r--crates/ide/src/goto_type_definition.rs12
-rw-r--r--crates/ide/src/hover.rs313
-rw-r--r--crates/ide/src/inlay_hints.rs62
-rw-r--r--crates/ide/src/join_lines.rs140
-rw-r--r--crates/ide/src/lib.rs27
-rw-r--r--crates/ide/src/matching_brace.rs10
-rw-r--r--crates/ide/src/parent_module.rs8
-rw-r--r--crates/ide/src/references.rs288
-rw-r--r--crates/ide/src/references/rename.rs688
-rw-r--r--crates/ide/src/runnables.rs128
-rw-r--r--crates/ide/src/syntax_highlighting.rs821
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs94
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs509
-rw-r--r--crates/ide/src/syntax_highlighting/highlights.rs92
-rw-r--r--crates/ide/src/syntax_highlighting/html.rs28
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs158
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs192
-rw-r--r--crates/ide/src/syntax_highlighting/injector.rs78
-rw-r--r--crates/ide/src/syntax_highlighting/macro_rules.rs10
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs173
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html28
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html71
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html4
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html20
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_strings.html106
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html88
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html260
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/injection.html48
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html20
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs24
-rw-r--r--crates/ide/src/syntax_tree.rs52
-rw-r--r--crates/ide/src/typing.rs38
-rw-r--r--crates/ide/src/typing/on_enter.rs18
45 files changed, 2810 insertions, 2552 deletions
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 3c2d39f5d..e8999a7f3 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -5,7 +5,7 @@ use indexmap::IndexMap;
5use hir::Semantics; 5use hir::Semantics;
6use ide_db::call_info::FnCallNode; 6use ide_db::call_info::FnCallNode;
7use ide_db::RootDatabase; 7use ide_db::RootDatabase;
8use syntax::{ast, match_ast, AstNode, TextRange}; 8use syntax::{ast, AstNode, TextRange};
9 9
10use crate::{ 10use crate::{
11 display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, 11 display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
@@ -47,28 +47,23 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
47 47
48 let mut calls = CallLocations::default(); 48 let mut calls = CallLocations::default();
49 49
50 for reference in refs.info.references() { 50 for (&file_id, references) in refs.info.references().iter() {
51 let file_id = reference.file_range.file_id;
52 let file = sema.parse(file_id); 51 let file = sema.parse(file_id);
53 let file = file.syntax(); 52 let file = file.syntax();
54 let token = file.token_at_offset(reference.file_range.range.start()).next()?; 53 for reference in references {
55 let token = sema.descend_into_macros(token); 54 let token = file.token_at_offset(reference.range.start()).next()?;
56 let syntax = token.parent(); 55 let token = sema.descend_into_macros(token);
57 56 let syntax = token.parent();
58 // This target is the containing function 57
59 if let Some(nav) = syntax.ancestors().find_map(|node| { 58 // This target is the containing function
60 match_ast! { 59 if let Some(nav) = syntax.ancestors().find_map(|node| {
61 match node { 60 let fn_ = ast::Fn::cast(node)?;
62 ast::Fn(it) => { 61 let def = sema.to_def(&fn_)?;
63 let def = sema.to_def(&it)?; 62 def.try_to_nav(sema.db)
64 def.try_to_nav(sema.db) 63 }) {
65 }, 64 let relative_range = reference.range;
66 _ => None, 65 calls.add(&nav, relative_range);
67 }
68 } 66 }
69 }) {
70 let relative_range = reference.file_range.range;
71 calls.add(&nav, relative_range);
72 } 67 }
73 } 68 }
74 69
@@ -91,17 +86,12 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
91 .filter_map(|node| FnCallNode::with_node_exact(&node)) 86 .filter_map(|node| FnCallNode::with_node_exact(&node))
92 .filter_map(|call_node| { 87 .filter_map(|call_node| {
93 let name_ref = call_node.name_ref()?; 88 let name_ref = call_node.name_ref()?;
94 89 let func_target = match call_node {
95 if let Some(func_target) = match &call_node {
96 FnCallNode::CallExpr(expr) => { 90 FnCallNode::CallExpr(expr) => {
97 //FIXME: Type::as_callable is broken 91 //FIXME: Type::as_callable is broken
98 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?; 92 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
99 match callable.kind() { 93 match callable.kind() {
100 hir::CallableKind::Function(it) => { 94 hir::CallableKind::Function(it) => it.try_to_nav(db),
101 let fn_def: hir::Function = it.into();
102 let nav = fn_def.try_to_nav(db)?;
103 Some(nav)
104 }
105 _ => None, 95 _ => None,
106 } 96 }
107 } 97 }
@@ -109,11 +99,8 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
109 let function = sema.resolve_method_call(&expr)?; 99 let function = sema.resolve_method_call(&expr)?;
110 function.try_to_nav(db) 100 function.try_to_nav(db)
111 } 101 }
112 } { 102 }?;
113 Some((func_target, name_ref.syntax().text_range())) 103 Some((func_target, name_ref.syntax().text_range()))
114 } else {
115 None
116 }
117 }) 104 })
118 .for_each(|(nav, range)| calls.add(&nav, range)); 105 .for_each(|(nav, range)| calls.add(&nav, range));
119 106
@@ -178,7 +165,7 @@ mod tests {
178//- /lib.rs 165//- /lib.rs
179fn callee() {} 166fn callee() {}
180fn caller() { 167fn caller() {
181 call<|>ee(); 168 call$0ee();
182} 169}
183"#, 170"#,
184 "callee Function FileId(0) 0..14 3..9", 171 "callee Function FileId(0) 0..14 3..9",
@@ -192,7 +179,7 @@ fn caller() {
192 check_hierarchy( 179 check_hierarchy(
193 r#" 180 r#"
194//- /lib.rs 181//- /lib.rs
195fn call<|>ee() {} 182fn call$0ee() {}
196fn caller() { 183fn caller() {
197 callee(); 184 callee();
198} 185}
@@ -210,7 +197,7 @@ fn caller() {
210//- /lib.rs 197//- /lib.rs
211fn callee() {} 198fn callee() {}
212fn caller() { 199fn caller() {
213 call<|>ee(); 200 call$0ee();
214 callee(); 201 callee();
215} 202}
216"#, 203"#,
@@ -227,7 +214,7 @@ fn caller() {
227//- /lib.rs 214//- /lib.rs
228fn callee() {} 215fn callee() {}
229fn caller1() { 216fn caller1() {
230 call<|>ee(); 217 call$0ee();
231} 218}
232 219
233fn caller2() { 220fn caller2() {
@@ -250,7 +237,7 @@ fn caller2() {
250//- /lib.rs cfg:test 237//- /lib.rs cfg:test
251fn callee() {} 238fn callee() {}
252fn caller1() { 239fn caller1() {
253 call<|>ee(); 240 call$0ee();
254} 241}
255 242
256#[cfg(test)] 243#[cfg(test)]
@@ -281,7 +268,7 @@ mod foo;
281use foo::callee; 268use foo::callee;
282 269
283fn caller() { 270fn caller() {
284 call<|>ee(); 271 call$0ee();
285} 272}
286 273
287//- /foo/mod.rs 274//- /foo/mod.rs
@@ -299,7 +286,7 @@ pub fn callee() {}
299 r#" 286 r#"
300//- /lib.rs 287//- /lib.rs
301fn callee() {} 288fn callee() {}
302fn call<|>er() { 289fn call$0er() {
303 callee(); 290 callee();
304 callee(); 291 callee();
305} 292}
@@ -318,7 +305,7 @@ fn call<|>er() {
318mod foo; 305mod foo;
319use foo::callee; 306use foo::callee;
320 307
321fn call<|>er() { 308fn call$0er() {
322 callee(); 309 callee();
323} 310}
324 311
@@ -337,7 +324,7 @@ pub fn callee() {}
337 r#" 324 r#"
338//- /lib.rs 325//- /lib.rs
339fn caller1() { 326fn caller1() {
340 call<|>er2(); 327 call$0er2();
341} 328}
342 329
343fn caller2() { 330fn caller2() {
@@ -365,7 +352,7 @@ fn a() {
365fn b() {} 352fn b() {}
366 353
367fn main() { 354fn main() {
368 a<|>() 355 a$0()
369} 356}
370"#, 357"#,
371 "a Function FileId(0) 0..18 3..4", 358 "a Function FileId(0) 0..18 3..4",
@@ -376,7 +363,7 @@ fn main() {
376 check_hierarchy( 363 check_hierarchy(
377 r#" 364 r#"
378fn a() { 365fn a() {
379 b<|>() 366 b$0()
380} 367}
381 368
382fn b() {} 369fn b() {}
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 79d126ff2..b35bc2bae 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -13,17 +13,16 @@ use hir::{
13 diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder}, 13 diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
14 Semantics, 14 Semantics,
15}; 15};
16use ide_db::base_db::SourceDatabase; 16use ide_db::{base_db::SourceDatabase, RootDatabase};
17use ide_db::RootDatabase;
18use itertools::Itertools; 17use itertools::Itertools;
19use rustc_hash::FxHashSet; 18use rustc_hash::FxHashSet;
20use syntax::{ 19use syntax::{
21 ast::{self, AstNode}, 20 ast::{self, AstNode},
22 SyntaxNode, TextRange, T, 21 SyntaxNode, TextRange,
23}; 22};
24use text_edit::TextEdit; 23use text_edit::TextEdit;
25 24
26use crate::{FileId, Label, SourceChange, SourceFileEdit}; 25use crate::{FileId, Label, SourceChange};
27 26
28use self::fixes::DiagnosticWithFix; 27use self::fixes::DiagnosticWithFix;
29 28
@@ -125,7 +124,7 @@ pub(crate) fn diagnostics(
125 .on::<hir::diagnostics::MissingFields, _>(|d| { 124 .on::<hir::diagnostics::MissingFields, _>(|d| {
126 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 125 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
127 }) 126 })
128 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { 127 .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| {
129 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 128 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
130 }) 129 })
131 .on::<hir::diagnostics::NoSuchField, _>(|d| { 130 .on::<hir::diagnostics::NoSuchField, _>(|d| {
@@ -220,7 +219,7 @@ fn check_unnecessary_braces_in_use_statement(
220 Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string()) 219 Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string())
221 .with_fix(Some(Fix::new( 220 .with_fix(Some(Fix::new(
222 "Remove unnecessary braces", 221 "Remove unnecessary braces",
223 SourceFileEdit { file_id, edit }.into(), 222 SourceChange::from_text_edit(file_id, edit),
224 use_range, 223 use_range,
225 ))), 224 ))),
226 ); 225 );
@@ -233,7 +232,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
233 single_use_tree: &ast::UseTree, 232 single_use_tree: &ast::UseTree,
234) -> Option<TextEdit> { 233) -> Option<TextEdit> {
235 let use_tree_list_node = single_use_tree.syntax().parent()?; 234 let use_tree_list_node = single_use_tree.syntax().parent()?;
236 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] { 235 if single_use_tree.path()?.segment()?.self_token().is_some() {
237 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); 236 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
238 let end = use_tree_list_node.text_range().end(); 237 let end = use_tree_list_node.text_range().end();
239 return Some(TextEdit::delete(TextRange::new(start, end))); 238 return Some(TextEdit::delete(TextRange::new(start, end)));
@@ -265,13 +264,11 @@ mod tests {
265 .unwrap(); 264 .unwrap();
266 let fix = diagnostic.fix.unwrap(); 265 let fix = diagnostic.fix.unwrap();
267 let actual = { 266 let actual = {
268 let file_id = fix.source_change.source_file_edits.first().unwrap().file_id; 267 let file_id = *fix.source_change.source_file_edits.keys().next().unwrap();
269 let mut actual = analysis.file_text(file_id).unwrap().to_string(); 268 let mut actual = analysis.file_text(file_id).unwrap().to_string();
270 269
271 // Go from the last one to the first one, so that ranges won't be affected by previous edits. 270 for edit in fix.source_change.source_file_edits.values() {
272 // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/4901#issuecomment-644675309 271 edit.apply(&mut actual);
273 for edit in fix.source_change.source_file_edits.iter().rev() {
274 edit.edit.apply(&mut actual);
275 } 272 }
276 actual 273 actual
277 }; 274 };
@@ -305,6 +302,40 @@ mod tests {
305 } 302 }
306 303
307 #[test] 304 #[test]
305 fn test_wrap_return_type_option() {
306 check_fix(
307 r#"
308//- /main.rs crate:main deps:core
309use core::option::Option::{self, Some, None};
310
311fn div(x: i32, y: i32) -> Option<i32> {
312 if y == 0 {
313 return None;
314 }
315 x / y$0
316}
317//- /core/lib.rs crate:core
318pub mod result {
319 pub enum Result<T, E> { Ok(T), Err(E) }
320}
321pub mod option {
322 pub enum Option<T> { Some(T), None }
323}
324"#,
325 r#"
326use core::option::Option::{self, Some, None};
327
328fn div(x: i32, y: i32) -> Option<i32> {
329 if y == 0 {
330 return None;
331 }
332 Some(x / y)
333}
334"#,
335 );
336 }
337
338 #[test]
308 fn test_wrap_return_type() { 339 fn test_wrap_return_type() {
309 check_fix( 340 check_fix(
310 r#" 341 r#"
@@ -315,12 +346,15 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
315 if y == 0 { 346 if y == 0 {
316 return Err(()); 347 return Err(());
317 } 348 }
318 x / y<|> 349 x / y$0
319} 350}
320//- /core/lib.rs crate:core 351//- /core/lib.rs crate:core
321pub mod result { 352pub mod result {
322 pub enum Result<T, E> { Ok(T), Err(E) } 353 pub enum Result<T, E> { Ok(T), Err(E) }
323} 354}
355pub mod option {
356 pub enum Option<T> { Some(T), None }
357}
324"#, 358"#,
325 r#" 359 r#"
326use core::result::Result::{self, Ok, Err}; 360use core::result::Result::{self, Ok, Err};
@@ -346,12 +380,15 @@ fn div<T>(x: T) -> Result<T, i32> {
346 if x == 0 { 380 if x == 0 {
347 return Err(7); 381 return Err(7);
348 } 382 }
349 <|>x 383 $0x
350} 384}
351//- /core/lib.rs crate:core 385//- /core/lib.rs crate:core
352pub mod result { 386pub mod result {
353 pub enum Result<T, E> { Ok(T), Err(E) } 387 pub enum Result<T, E> { Ok(T), Err(E) }
354} 388}
389pub mod option {
390 pub enum Option<T> { Some(T), None }
391}
355"#, 392"#,
356 r#" 393 r#"
357use core::result::Result::{self, Ok, Err}; 394use core::result::Result::{self, Ok, Err};
@@ -379,12 +416,15 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
379 if y == 0 { 416 if y == 0 {
380 return Err(()); 417 return Err(());
381 } 418 }
382 x <|>/ y 419 x $0/ y
383} 420}
384//- /core/lib.rs crate:core 421//- /core/lib.rs crate:core
385pub mod result { 422pub mod result {
386 pub enum Result<T, E> { Ok(T), Err(E) } 423 pub enum Result<T, E> { Ok(T), Err(E) }
387} 424}
425pub mod option {
426 pub enum Option<T> { Some(T), None }
427}
388"#, 428"#,
389 r#" 429 r#"
390use core::result::Result::{self, Ok, Err}; 430use core::result::Result::{self, Ok, Err};
@@ -414,12 +454,15 @@ fn foo() -> Result<(), i32> { 0 }
414pub mod result { 454pub mod result {
415 pub enum Result<T, E> { Ok(T), Err(E) } 455 pub enum Result<T, E> { Ok(T), Err(E) }
416} 456}
457pub mod option {
458 pub enum Option<T> { Some(T), None }
459}
417"#, 460"#,
418 ); 461 );
419 } 462 }
420 463
421 #[test] 464 #[test]
422 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { 465 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
423 check_no_diagnostics( 466 check_no_diagnostics(
424 r#" 467 r#"
425//- /main.rs crate:main deps:core 468//- /main.rs crate:main deps:core
@@ -433,6 +476,9 @@ fn foo() -> SomeOtherEnum { 0 }
433pub mod result { 476pub mod result {
434 pub enum Result<T, E> { Ok(T), Err(E) } 477 pub enum Result<T, E> { Ok(T), Err(E) }
435} 478}
479pub mod option {
480 pub enum Option<T> { Some(T), None }
481}
436"#, 482"#,
437 ); 483 );
438 } 484 }
@@ -444,7 +490,7 @@ pub mod result {
444struct TestStruct { one: i32, two: i64 } 490struct TestStruct { one: i32, two: i64 }
445 491
446fn test_fn() { 492fn test_fn() {
447 let s = TestStruct {<|>}; 493 let s = TestStruct {$0};
448} 494}
449"#, 495"#,
450 r#" 496 r#"
@@ -464,7 +510,7 @@ fn test_fn() {
464struct TestStruct { one: i32 } 510struct TestStruct { one: i32 }
465 511
466impl TestStruct { 512impl TestStruct {
467 fn test_fn() { let s = Self {<|>}; } 513 fn test_fn() { let s = Self {$0}; }
468} 514}
469"#, 515"#,
470 r#" 516 r#"
@@ -487,7 +533,7 @@ enum Expr {
487 533
488impl Expr { 534impl Expr {
489 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { 535 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
490 Expr::Bin {<|> } 536 Expr::Bin {$0 }
491 } 537 }
492} 538}
493"#, 539"#,
@@ -512,7 +558,7 @@ impl Expr {
512struct TestStruct { one: i32, two: i64 } 558struct TestStruct { one: i32, two: i64 }
513 559
514fn test_fn() { 560fn test_fn() {
515 let s = TestStruct{ two: 2<|> }; 561 let s = TestStruct{ two: 2$0 };
516} 562}
517"#, 563"#,
518 r" 564 r"
@@ -567,7 +613,7 @@ fn test_fn() {
567 Fix { 613 Fix {
568 label: "Create module", 614 label: "Create module",
569 source_change: SourceChange { 615 source_change: SourceChange {
570 source_file_edits: [], 616 source_file_edits: {},
571 file_system_edits: [ 617 file_system_edits: [
572 CreateFile { 618 CreateFile {
573 dst: AnchoredPathBuf { 619 dst: AnchoredPathBuf {
@@ -608,7 +654,7 @@ fn here() {}
608macro_rules! id { ($($tt:tt)*) => { $($tt)*}; } 654macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
609 655
610fn main() { 656fn main() {
611 let _x = id![Foo { a: <|>42 }]; 657 let _x = id![Foo { a: $042 }];
612} 658}
613 659
614pub struct Foo { pub a: i32, pub b: i32 } 660pub struct Foo { pub a: i32, pub b: i32 }
@@ -663,7 +709,7 @@ mod a {
663 check_fix( 709 check_fix(
664 r" 710 r"
665 mod b {} 711 mod b {}
666 use {<|>b}; 712 use {$0b};
667 ", 713 ",
668 r" 714 r"
669 mod b {} 715 mod b {}
@@ -673,7 +719,7 @@ mod a {
673 check_fix( 719 check_fix(
674 r" 720 r"
675 mod b {} 721 mod b {}
676 use {b<|>}; 722 use {b$0};
677 ", 723 ",
678 r" 724 r"
679 mod b {} 725 mod b {}
@@ -683,7 +729,7 @@ mod a {
683 check_fix( 729 check_fix(
684 r" 730 r"
685 mod a { mod c {} } 731 mod a { mod c {} }
686 use a::{c<|>}; 732 use a::{c$0};
687 ", 733 ",
688 r" 734 r"
689 mod a { mod c {} } 735 mod a { mod c {} }
@@ -693,7 +739,7 @@ mod a {
693 check_fix( 739 check_fix(
694 r" 740 r"
695 mod a {} 741 mod a {}
696 use a::{self<|>}; 742 use a::{self$0};
697 ", 743 ",
698 r" 744 r"
699 mod a {} 745 mod a {}
@@ -703,7 +749,7 @@ mod a {
703 check_fix( 749 check_fix(
704 r" 750 r"
705 mod a { mod c {} mod d { mod e {} } } 751 mod a { mod c {} mod d { mod e {} } }
706 use a::{c, d::{e<|>}}; 752 use a::{c, d::{e$0}};
707 ", 753 ",
708 r" 754 r"
709 mod a { mod c {} mod d { mod e {} } } 755 mod a { mod c {} mod d { mod e {} } }
@@ -717,7 +763,7 @@ mod a {
717 check_fix( 763 check_fix(
718 r" 764 r"
719fn main() { 765fn main() {
720 Foo { bar: 3, baz<|>: false}; 766 Foo { bar: 3, baz$0: false};
721} 767}
722struct Foo { 768struct Foo {
723 bar: i32 769 bar: i32
@@ -743,7 +789,7 @@ struct Foo {
743mod foo; 789mod foo;
744 790
745fn main() { 791fn main() {
746 foo::Foo { bar: 3, <|>baz: false}; 792 foo::Foo { bar: 3, $0baz: false};
747} 793}
748//- /foo.rs 794//- /foo.rs
749struct Foo { 795struct Foo {
@@ -777,7 +823,7 @@ struct Foo {
777 fn test_rename_incorrect_case() { 823 fn test_rename_incorrect_case() {
778 check_fix( 824 check_fix(
779 r#" 825 r#"
780pub struct test_struct<|> { one: i32 } 826pub struct test_struct$0 { one: i32 }
781 827
782pub fn some_fn(val: test_struct) -> test_struct { 828pub fn some_fn(val: test_struct) -> test_struct {
783 test_struct { one: val.one + 1 } 829 test_struct { one: val.one + 1 }
@@ -794,7 +840,7 @@ pub fn some_fn(val: TestStruct) -> TestStruct {
794 840
795 check_fix( 841 check_fix(
796 r#" 842 r#"
797pub fn some_fn(NonSnakeCase<|>: u8) -> u8 { 843pub fn some_fn(NonSnakeCase$0: u8) -> u8 {
798 NonSnakeCase 844 NonSnakeCase
799} 845}
800"#, 846"#,
@@ -807,7 +853,7 @@ pub fn some_fn(non_snake_case: u8) -> u8 {
807 853
808 check_fix( 854 check_fix(
809 r#" 855 r#"
810pub fn SomeFn<|>(val: u8) -> u8 { 856pub fn SomeFn$0(val: u8) -> u8 {
811 if val != 0 { SomeFn(val - 1) } else { val } 857 if val != 0 { SomeFn(val - 1) } else { val }
812} 858}
813"#, 859"#,
@@ -821,7 +867,7 @@ pub fn some_fn(val: u8) -> u8 {
821 check_fix( 867 check_fix(
822 r#" 868 r#"
823fn some_fn() { 869fn some_fn() {
824 let whatAWeird_Formatting<|> = 10; 870 let whatAWeird_Formatting$0 = 10;
825 another_func(whatAWeird_Formatting); 871 another_func(whatAWeird_Formatting);
826} 872}
827"#, 873"#,
@@ -839,7 +885,7 @@ fn some_fn() {
839 check_no_diagnostics( 885 check_no_diagnostics(
840 r#" 886 r#"
841fn foo() { 887fn foo() {
842 const ANOTHER_ITEM<|>: &str = "some_item"; 888 const ANOTHER_ITEM$0: &str = "some_item";
843} 889}
844"#, 890"#,
845 ); 891 );
@@ -852,7 +898,7 @@ fn foo() {
852pub struct TestStruct; 898pub struct TestStruct;
853 899
854impl TestStruct { 900impl TestStruct {
855 pub fn SomeFn<|>() -> TestStruct { 901 pub fn SomeFn$0() -> TestStruct {
856 TestStruct 902 TestStruct
857 } 903 }
858} 904}
@@ -871,7 +917,7 @@ impl TestStruct {
871 917
872 #[test] 918 #[test]
873 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { 919 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
874 let input = r#"fn FOO<|>() {}"#; 920 let input = r#"fn FOO$0() {}"#;
875 let expected = r#"fn foo() {}"#; 921 let expected = r#"fn foo() {}"#;
876 922
877 let (analysis, file_position) = fixture::position(input); 923 let (analysis, file_position) = fixture::position(input);
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs
index f41bcd619..5c89e2170 100644
--- a/crates/ide/src/diagnostics/field_shorthand.rs
+++ b/crates/ide/src/diagnostics/field_shorthand.rs
@@ -1,8 +1,7 @@
1//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both 1//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
2//! expressions and patterns. 2//! expressions and patterns.
3 3
4use ide_db::base_db::FileId; 4use ide_db::{base_db::FileId, source_change::SourceChange};
5use ide_db::source_change::SourceFileEdit;
6use syntax::{ast, match_ast, AstNode, SyntaxNode}; 5use syntax::{ast, match_ast, AstNode, SyntaxNode};
7use text_edit::TextEdit; 6use text_edit::TextEdit;
8 7
@@ -50,7 +49,7 @@ fn check_expr_field_shorthand(
50 Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix( 49 Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix(
51 Some(Fix::new( 50 Some(Fix::new(
52 "Use struct shorthand initialization", 51 "Use struct shorthand initialization",
53 SourceFileEdit { file_id, edit }.into(), 52 SourceChange::from_text_edit(file_id, edit),
54 field_range, 53 field_range,
55 )), 54 )),
56 ), 55 ),
@@ -89,7 +88,7 @@ fn check_pat_field_shorthand(
89 acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix( 88 acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix(
90 Some(Fix::new( 89 Some(Fix::new(
91 "Use struct field shorthand", 90 "Use struct field shorthand",
92 SourceFileEdit { file_id, edit }.into(), 91 SourceChange::from_text_edit(file_id, edit),
93 field_range, 92 field_range,
94 )), 93 )),
95 )); 94 ));
@@ -120,7 +119,7 @@ fn main() { A { 0: 0 } }
120struct A { a: &'static str } 119struct A { a: &'static str }
121fn main() { 120fn main() {
122 let a = "haha"; 121 let a = "haha";
123 A { a<|>: a } 122 A { a$0: a }
124} 123}
125"#, 124"#,
126 r#" 125 r#"
@@ -138,7 +137,7 @@ struct A { a: &'static str, b: &'static str }
138fn main() { 137fn main() {
139 let a = "haha"; 138 let a = "haha";
140 let b = "bb"; 139 let b = "bb";
141 A { a<|>: a, b } 140 A { a$0: a, b }
142} 141}
143"#, 142"#,
144 r#" 143 r#"
@@ -171,7 +170,7 @@ fn f(a: A) { let A { 0: 0 } = a; }
171 r#" 170 r#"
172struct A { a: &'static str } 171struct A { a: &'static str }
173fn f(a: A) { 172fn f(a: A) {
174 let A { a<|>: a } = a; 173 let A { a$0: a } = a;
175} 174}
176"#, 175"#,
177 r#" 176 r#"
@@ -186,7 +185,7 @@ fn f(a: A) {
186 r#" 185 r#"
187struct A { a: &'static str, b: &'static str } 186struct A { a: &'static str, b: &'static str }
188fn f(a: A) { 187fn f(a: A) {
189 let A { a<|>: a, b } = a; 188 let A { a$0: a, b } = a;
190} 189}
191"#, 190"#,
192 r#" 191 r#"
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 71ec4df92..e4335119b 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -3,14 +3,14 @@
3use hir::{ 3use hir::{
4 db::AstDatabase, 4 db::AstDatabase,
5 diagnostics::{ 5 diagnostics::{
6 Diagnostic, IncorrectCase, MissingFields, MissingOkInTailExpr, NoSuchField, 6 Diagnostic, IncorrectCase, MissingFields, MissingOkOrSomeInTailExpr, NoSuchField,
7 RemoveThisSemicolon, UnresolvedModule, 7 RemoveThisSemicolon, UnresolvedModule,
8 }, 8 },
9 HasSource, HirDisplay, InFile, Semantics, VariantDef, 9 HasSource, HirDisplay, InFile, Semantics, VariantDef,
10}; 10};
11use ide_db::base_db::{AnchoredPathBuf, FileId};
12use ide_db::{ 11use ide_db::{
13 source_change::{FileSystemEdit, SourceFileEdit}, 12 base_db::{AnchoredPathBuf, FileId},
13 source_change::{FileSystemEdit, SourceChange},
14 RootDatabase, 14 RootDatabase,
15}; 15};
16use syntax::{ 16use syntax::{
@@ -88,21 +88,22 @@ impl DiagnosticWithFix for MissingFields {
88 }; 88 };
89 Some(Fix::new( 89 Some(Fix::new(
90 "Fill struct fields", 90 "Fill struct fields",
91 SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(), 91 SourceChange::from_text_edit(self.file.original_file(sema.db), edit),
92 sema.original_range(&field_list_parent.syntax()).range, 92 sema.original_range(&field_list_parent.syntax()).range,
93 )) 93 ))
94 } 94 }
95} 95}
96 96
97impl DiagnosticWithFix for MissingOkInTailExpr { 97impl DiagnosticWithFix for MissingOkOrSomeInTailExpr {
98 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 98 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
99 let root = sema.db.parse_or_expand(self.file)?; 99 let root = sema.db.parse_or_expand(self.file)?;
100 let tail_expr = self.expr.to_node(&root); 100 let tail_expr = self.expr.to_node(&root);
101 let tail_expr_range = tail_expr.syntax().text_range(); 101 let tail_expr_range = tail_expr.syntax().text_range();
102 let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); 102 let replacement = format!("{}({})", self.required, tail_expr.syntax());
103 let source_change = 103 let edit = TextEdit::replace(tail_expr_range, replacement);
104 SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); 104 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
105 Some(Fix::new("Wrap with ok", source_change, tail_expr_range)) 105 let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
106 Some(Fix::new(name, source_change, tail_expr_range))
106 } 107 }
107} 108}
108 109
@@ -120,8 +121,7 @@ impl DiagnosticWithFix for RemoveThisSemicolon {
120 .text_range(); 121 .text_range();
121 122
122 let edit = TextEdit::delete(semicolon); 123 let edit = TextEdit::delete(semicolon);
123 let source_change = 124 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
124 SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
125 125
126 Some(Fix::new("Remove this semicolon", source_change, semicolon)) 126 Some(Fix::new("Remove this semicolon", source_change, semicolon))
127 } 127 }
@@ -202,15 +202,11 @@ fn missing_record_expr_field_fix(
202 new_field = format!(",{}", new_field); 202 new_field = format!(",{}", new_field);
203 } 203 }
204 204
205 let source_change = SourceFileEdit { 205 let source_change = SourceChange::from_text_edit(
206 file_id: def_file_id, 206 def_file_id,
207 edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field), 207 TextEdit::insert(last_field_syntax.text_range().end(), new_field),
208 }; 208 );
209 return Some(Fix::new( 209 return Some(Fix::new("Create field", source_change, record_expr_field.syntax().text_range()));
210 "Create field",
211 source_change.into(),
212 record_expr_field.syntax().text_range(),
213 ));
214 210
215 fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { 211 fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
216 match field_def_list { 212 match field_def_list {
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index e24c78301..00e601244 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -215,10 +215,8 @@ impl TryToNav for Definition {
215 Definition::ModuleDef(it) => it.try_to_nav(db), 215 Definition::ModuleDef(it) => it.try_to_nav(db),
216 Definition::SelfType(it) => it.try_to_nav(db), 216 Definition::SelfType(it) => it.try_to_nav(db),
217 Definition::Local(it) => Some(it.to_nav(db)), 217 Definition::Local(it) => Some(it.to_nav(db)),
218 Definition::TypeParam(it) => it.try_to_nav(db), 218 Definition::GenericParam(it) => it.try_to_nav(db),
219 Definition::LifetimeParam(it) => it.try_to_nav(db),
220 Definition::Label(it) => Some(it.to_nav(db)), 219 Definition::Label(it) => Some(it.to_nav(db)),
221 Definition::ConstParam(it) => it.try_to_nav(db),
222 } 220 }
223 } 221 }
224} 222}
@@ -389,27 +387,44 @@ impl TryToNav for hir::AssocItem {
389 } 387 }
390} 388}
391 389
390impl TryToNav for hir::GenericParam {
391 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
392 match self {
393 hir::GenericParam::TypeParam(it) => it.try_to_nav(db),
394 hir::GenericParam::ConstParam(it) => it.try_to_nav(db),
395 hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db),
396 }
397 }
398}
399
392impl ToNav for hir::Local { 400impl ToNav for hir::Local {
393 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 401 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
394 let src = self.source(db); 402 let src = self.source(db);
395 let node = match &src.value { 403 let (node, name) = match &src.value {
396 Either::Left(bind_pat) => { 404 Either::Left(bind_pat) => (bind_pat.syntax().clone(), bind_pat.name()),
397 bind_pat.name().map_or_else(|| bind_pat.syntax().clone(), |it| it.syntax().clone()) 405 Either::Right(it) => (it.syntax().clone(), it.name()),
398 }
399 Either::Right(it) => it.syntax().clone(),
400 }; 406 };
407 let focus_range =
408 name.map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range);
409
401 let full_range = src.with_value(&node).original_file_range(db); 410 let full_range = src.with_value(&node).original_file_range(db);
402 let name = match self.name(db) { 411 let name = match self.name(db) {
403 Some(it) => it.to_string().into(), 412 Some(it) => it.to_string().into(),
404 None => "".into(), 413 None => "".into(),
405 }; 414 };
406 let kind = if self.is_param(db) { SymbolKind::ValueParam } else { SymbolKind::Local }; 415 let kind = if self.is_self(db) {
416 SymbolKind::SelfParam
417 } else if self.is_param(db) {
418 SymbolKind::ValueParam
419 } else {
420 SymbolKind::Local
421 };
407 NavigationTarget { 422 NavigationTarget {
408 file_id: full_range.file_id, 423 file_id: full_range.file_id,
409 name, 424 name,
410 kind: Some(kind), 425 kind: Some(kind),
411 full_range: full_range.range, 426 full_range: full_range.range,
412 focus_range: None, 427 focus_range,
413 container_name: None, 428 container_name: None,
414 description: None, 429 description: None,
415 docs: None, 430 docs: None,
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 367fac05e..de10406bc 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -1,6 +1,6 @@
1//! Resolves and rewrites links in markdown documentation. 1//! Resolves and rewrites links in markdown documentation.
2 2
3use std::{convert::TryFrom, iter::once}; 3use std::{convert::TryFrom, iter::once, ops::Range};
4 4
5use itertools::Itertools; 5use itertools::Itertools;
6use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; 6use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
@@ -39,7 +39,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi
39 if target.contains("://") { 39 if target.contains("://") {
40 (target.to_string(), title.to_string()) 40 (target.to_string(), title.to_string())
41 } else { 41 } else {
42 // Two posibilities: 42 // Two possibilities:
43 // * path-based links: `../../module/struct.MyStruct.html` 43 // * path-based links: `../../module/struct.MyStruct.html`
44 // * module-based links (AKA intra-doc links): `super::super::module::MyStruct` 44 // * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
45 if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) { 45 if let Some(rewritten) = rewrite_intra_doc_link(db, *definition, target, title) {
@@ -61,6 +61,30 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi
61 out 61 out
62} 62}
63 63
64pub(crate) fn extract_definitions_from_markdown(
65 markdown: &str,
66) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> {
67 let mut res = vec![];
68 let mut cb = |link: BrokenLink| {
69 Some((
70 /*url*/ link.reference.to_owned().into(),
71 /*title*/ link.reference.to_owned().into(),
72 ))
73 };
74 let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb));
75 for (event, range) in doc.into_offset_iter() {
76 match event {
77 Event::Start(Tag::Link(_link_type, ref target, ref title)) => {
78 let link = if target.is_empty() { title } else { target };
79 let (link, ns) = parse_link(link);
80 res.push((link.to_string(), ns, range));
81 }
82 _ => {}
83 }
84 }
85 res
86}
87
64/// Remove all links in markdown documentation. 88/// Remove all links in markdown documentation.
65pub(crate) fn remove_links(markdown: &str) -> String { 89pub(crate) fn remove_links(markdown: &str) -> String {
66 let mut drop_link = false; 90 let mut drop_link = false;
@@ -192,9 +216,7 @@ fn rewrite_intra_doc_link(
192 Definition::Field(it) => it.resolve_doc_path(db, link, ns), 216 Definition::Field(it) => it.resolve_doc_path(db, link, ns),
193 Definition::SelfType(_) 217 Definition::SelfType(_)
194 | Definition::Local(_) 218 | Definition::Local(_)
195 | Definition::TypeParam(_) 219 | Definition::GenericParam(_)
196 | Definition::ConstParam(_)
197 | Definition::LifetimeParam(_)
198 | Definition::Label(_) => return None, 220 | Definition::Label(_) => return None,
199 }?; 221 }?;
200 let krate = resolved.module(db)?.krate(); 222 let krate = resolved.module(db)?.krate();
@@ -420,7 +442,7 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem)
420 function.as_assoc_item(db).map(|assoc| assoc.container(db)), 442 function.as_assoc_item(db).map(|assoc| assoc.container(db)),
421 Some(AssocItemContainer::Trait(..)) 443 Some(AssocItemContainer::Trait(..))
422 ); 444 );
423 // This distinction may get more complicated when specialisation is available. 445 // This distinction may get more complicated when specialization is available.
424 // Rustdoc makes this decision based on whether a method 'has defaultness'. 446 // Rustdoc makes this decision based on whether a method 'has defaultness'.
425 // Currently this is only the case for provided trait methods. 447 // Currently this is only the case for provided trait methods.
426 if is_trait_method && !function.has_body(db) { 448 if is_trait_method && !function.has_body(db) {
@@ -464,7 +486,7 @@ mod tests {
464 fn test_doc_url_struct() { 486 fn test_doc_url_struct() {
465 check( 487 check(
466 r#" 488 r#"
467pub struct Fo<|>o; 489pub struct Fo$0o;
468"#, 490"#,
469 expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]], 491 expect![[r#"https://docs.rs/test/*/test/struct.Foo.html"#]],
470 ); 492 );
@@ -474,7 +496,7 @@ pub struct Fo<|>o;
474 fn test_doc_url_fn() { 496 fn test_doc_url_fn() {
475 check( 497 check(
476 r#" 498 r#"
477pub fn fo<|>o() {} 499pub fn fo$0o() {}
478"#, 500"#,
479 expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]], 501 expect![[r##"https://docs.rs/test/*/test/fn.foo.html#method.foo"##]],
480 ); 502 );
@@ -487,7 +509,7 @@ pub fn fo<|>o() {}
487pub struct Foo; 509pub struct Foo;
488 510
489impl Foo { 511impl Foo {
490 pub fn met<|>hod() {} 512 pub fn met$0hod() {}
491} 513}
492 514
493"#, 515"#,
@@ -500,7 +522,7 @@ impl Foo {
500 check( 522 check(
501 r#" 523 r#"
502pub trait Bar { 524pub trait Bar {
503 fn met<|>hod() {} 525 fn met$0hod() {}
504} 526}
505 527
506"#, 528"#,
@@ -513,7 +535,7 @@ pub trait Bar {
513 check( 535 check(
514 r#" 536 r#"
515pub trait Foo { 537pub trait Foo {
516 fn met<|>hod(); 538 fn met$0hod();
517} 539}
518 540
519"#, 541"#,
@@ -526,7 +548,7 @@ pub trait Foo {
526 check( 548 check(
527 r#" 549 r#"
528pub struct Foo { 550pub struct Foo {
529 pub fie<|>ld: () 551 pub fie$0ld: ()
530} 552}
531 553
532"#, 554"#,
@@ -539,7 +561,7 @@ pub struct Foo {
539 check( 561 check(
540 r#" 562 r#"
541pub mod foo { 563pub mod foo {
542 pub mod ba<|>r {} 564 pub mod ba$0r {}
543} 565}
544 "#, 566 "#,
545 expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]], 567 expect![[r#"https://docs.rs/test/*/test/foo/bar/index.html"#]],
@@ -564,7 +586,7 @@ pub mod wrapper {
564} 586}
565 587
566fn foo() { 588fn foo() {
567 let bar: wrapper::It<|>em; 589 let bar: wrapper::It$0em;
568} 590}
569 "#, 591 "#,
570 expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], 592 expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]],
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 8d75e0f05..ffb3a6f7d 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -144,7 +144,7 @@ macro_rules! foo {
144macro_rules! baz { 144macro_rules! baz {
145 () => { foo!(); } 145 () => { foo!(); }
146} 146}
147f<|>oo!(); 147f$0oo!();
148"#, 148"#,
149 expect![[r#" 149 expect![[r#"
150 foo 150 foo
@@ -165,7 +165,7 @@ macro_rules! foo {
165 } 165 }
166 } 166 }
167} 167}
168f<|>oo!(); 168f$0oo!();
169 "#, 169 "#,
170 expect![[r#" 170 expect![[r#"
171 foo 171 foo
@@ -192,7 +192,7 @@ macro_rules! match_ast {
192} 192}
193 193
194fn main() { 194fn main() {
195 mat<|>ch_ast! { 195 mat$0ch_ast! {
196 match container { 196 match container {
197 ast::TraitDef(it) => {}, 197 ast::TraitDef(it) => {},
198 ast::ImplDef(it) => {}, 198 ast::ImplDef(it) => {},
@@ -226,7 +226,7 @@ macro_rules! match_ast {
226 226
227fn main() { 227fn main() {
228 let p = f(|it| { 228 let p = f(|it| {
229 let res = mat<|>ch_ast! { match c {}}; 229 let res = mat$0ch_ast! { match c {}};
230 Some(res) 230 Some(res)
231 })?; 231 })?;
232} 232}
@@ -250,7 +250,7 @@ macro_rules! foo {
250} 250}
251 251
252fn main() { 252fn main() {
253 let res = fo<|>o!(); 253 let res = fo$0o!();
254} 254}
255"#, 255"#,
256 expect![[r#" 256 expect![[r#"
@@ -272,7 +272,7 @@ macro_rules! foo {
272} 272}
273 273
274fn main() { 274fn main() {
275 let res = fo<|>o!(); 275 let res = fo$0o!();
276} 276}
277"#, 277"#,
278 expect![[r#" 278 expect![[r#"
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs
index 6f3022dfd..17a540972 100644
--- a/crates/ide/src/extend_selection.rs
+++ b/crates/ide/src/extend_selection.rs
@@ -3,7 +3,7 @@ use std::iter::successors;
3use hir::Semantics; 3use hir::Semantics;
4use ide_db::RootDatabase; 4use ide_db::RootDatabase;
5use syntax::{ 5use syntax::{
6 algo::{self, find_covering_element, skip_trivia_token}, 6 algo::{self, skip_trivia_token},
7 ast::{self, AstNode, AstToken}, 7 ast::{self, AstNode, AstToken},
8 Direction, NodeOrToken, 8 Direction, NodeOrToken,
9 SyntaxKind::{self, *}, 9 SyntaxKind::{self, *},
@@ -76,7 +76,7 @@ fn try_extend_selection(
76 }; 76 };
77 return Some(leaf_range); 77 return Some(leaf_range);
78 }; 78 };
79 let node = match find_covering_element(root, range) { 79 let node = match root.covering_element(range) {
80 NodeOrToken::Token(token) => { 80 NodeOrToken::Token(token) => {
81 if token.text_range() != range { 81 if token.text_range() != range {
82 return Some(token.text_range()); 82 return Some(token.text_range());
@@ -120,7 +120,7 @@ fn extend_tokens_from_range(
120 macro_call: ast::MacroCall, 120 macro_call: ast::MacroCall,
121 original_range: TextRange, 121 original_range: TextRange,
122) -> Option<TextRange> { 122) -> Option<TextRange> {
123 let src = find_covering_element(&macro_call.syntax(), original_range); 123 let src = macro_call.syntax().covering_element(original_range);
124 let (first_token, last_token) = match src { 124 let (first_token, last_token) = match src {
125 NodeOrToken::Node(it) => (it.first_token()?, it.last_token()?), 125 NodeOrToken::Node(it) => (it.first_token()?, it.last_token()?),
126 NodeOrToken::Token(it) => (it.clone(), it), 126 NodeOrToken::Token(it) => (it.clone(), it),
@@ -334,29 +334,29 @@ mod tests {
334 334
335 #[test] 335 #[test]
336 fn test_extend_selection_arith() { 336 fn test_extend_selection_arith() {
337 do_check(r#"fn foo() { <|>1 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); 337 do_check(r#"fn foo() { $01 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]);
338 } 338 }
339 339
340 #[test] 340 #[test]
341 fn test_extend_selection_list() { 341 fn test_extend_selection_list() {
342 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]); 342 do_check(r#"fn foo($0x: i32) {}"#, &["x", "x: i32"]);
343 do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); 343 do_check(r#"fn foo($0x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]);
344 do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]); 344 do_check(r#"fn foo($0x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]);
345 do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]); 345 do_check(r#"fn foo(x: i32, $0y: i32) {}"#, &["y", "y: i32", ", y: i32"]);
346 do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]); 346 do_check(r#"fn foo(x: i32, $0y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]);
347 do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]); 347 do_check(r#"fn foo(x: i32,$0y: i32) {}"#, &["y", "y: i32", ",y: i32"]);
348 348
349 do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]); 349 do_check(r#"const FOO: [usize; 2] = [ 22$0 , 33];"#, &["22", "22 , "]);
350 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); 350 do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0];"#, &["33", ", 33"]);
351 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]); 351 do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0 ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]);
352 352
353 do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]); 353 do_check(r#"fn main() { (1, 2$0) }"#, &["2", ", 2", "(1, 2)"]);
354 354
355 do_check( 355 do_check(
356 r#" 356 r#"
357const FOO: [usize; 2] = [ 357const FOO: [usize; 2] = [
358 22, 358 22,
359 <|>33, 359 $033,
360]"#, 360]"#,
361 &["33", "33,"], 361 &["33", "33,"],
362 ); 362 );
@@ -365,7 +365,7 @@ const FOO: [usize; 2] = [
365 r#" 365 r#"
366const FOO: [usize; 2] = [ 366const FOO: [usize; 2] = [
367 22 367 22
368 , 33<|>, 368 , 33$0,
369]"#, 369]"#,
370 &["33", "33,"], 370 &["33", "33,"],
371 ); 371 );
@@ -376,7 +376,7 @@ const FOO: [usize; 2] = [
376 do_check( 376 do_check(
377 r#" 377 r#"
378impl S { 378impl S {
379<|> fn foo() { 379$0 fn foo() {
380 380
381 } 381 }
382}"#, 382}"#,
@@ -393,7 +393,7 @@ struct A;
393/// bla 393/// bla
394/// bla 394/// bla
395struct B { 395struct B {
396 <|> 396 $0
397} 397}
398 "#, 398 "#,
399 &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"], 399 &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"],
@@ -407,7 +407,7 @@ struct B {
407fn bar(){} 407fn bar(){}
408 408
409// fn foo() { 409// fn foo() {
410// 1 + <|>1 410// 1 + $01
411// } 411// }
412 412
413// fn foo(){} 413// fn foo(){}
@@ -419,7 +419,7 @@ fn bar(){}
419 r#" 419 r#"
420// #[derive(Debug, Clone, Copy, PartialEq, Eq)] 420// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
421// pub enum Direction { 421// pub enum Direction {
422// <|> Next, 422// $0 Next,
423// Prev 423// Prev
424// } 424// }
425"#, 425"#,
@@ -433,27 +433,27 @@ fn bar(){}
433 r#" 433 r#"
434/* 434/*
435foo 435foo
436_bar1<|>*/ 436_bar1$0*/
437"#, 437"#,
438 &["_bar1", "/*\nfoo\n_bar1*/"], 438 &["_bar1", "/*\nfoo\n_bar1*/"],
439 ); 439 );
440 440
441 do_check(r#"//!<|>foo_2 bar"#, &["foo_2", "//!foo_2 bar"]); 441 do_check(r#"//!$0foo_2 bar"#, &["foo_2", "//!foo_2 bar"]);
442 442
443 do_check(r#"/<|>/foo bar"#, &["//foo bar"]); 443 do_check(r#"/$0/foo bar"#, &["//foo bar"]);
444 } 444 }
445 445
446 #[test] 446 #[test]
447 fn test_extend_selection_prefer_idents() { 447 fn test_extend_selection_prefer_idents() {
448 do_check( 448 do_check(
449 r#" 449 r#"
450fn main() { foo<|>+bar;} 450fn main() { foo$0+bar;}
451"#, 451"#,
452 &["foo", "foo+bar"], 452 &["foo", "foo+bar"],
453 ); 453 );
454 do_check( 454 do_check(
455 r#" 455 r#"
456fn main() { foo+<|>bar;} 456fn main() { foo+$0bar;}
457"#, 457"#,
458 &["bar", "foo+bar"], 458 &["bar", "foo+bar"],
459 ); 459 );
@@ -461,18 +461,18 @@ fn main() { foo+<|>bar;}
461 461
462 #[test] 462 #[test]
463 fn test_extend_selection_prefer_lifetimes() { 463 fn test_extend_selection_prefer_lifetimes() {
464 do_check(r#"fn foo<<|>'a>() {}"#, &["'a", "<'a>"]); 464 do_check(r#"fn foo<$0'a>() {}"#, &["'a", "<'a>"]);
465 do_check(r#"fn foo<'a<|>>() {}"#, &["'a", "<'a>"]); 465 do_check(r#"fn foo<'a$0>() {}"#, &["'a", "<'a>"]);
466 } 466 }
467 467
468 #[test] 468 #[test]
469 fn test_extend_selection_select_first_word() { 469 fn test_extend_selection_select_first_word() {
470 do_check(r#"// foo bar b<|>az quxx"#, &["baz", "// foo bar baz quxx"]); 470 do_check(r#"// foo bar b$0az quxx"#, &["baz", "// foo bar baz quxx"]);
471 do_check( 471 do_check(
472 r#" 472 r#"
473impl S { 473impl S {
474fn foo() { 474fn foo() {
475// hel<|>lo world 475// hel$0lo world
476} 476}
477} 477}
478"#, 478"#,
@@ -486,7 +486,7 @@ fn foo() {
486 r#" 486 r#"
487fn bar(){} 487fn bar(){}
488 488
489" fn f<|>oo() {" 489" fn f$0oo() {"
490"#, 490"#,
491 &["foo", "\" fn foo() {\""], 491 &["foo", "\" fn foo() {\""],
492 ); 492 );
@@ -499,7 +499,7 @@ fn bar(){}
499fn foo<R>() 499fn foo<R>()
500 where 500 where
501 R: req::Request + 'static, 501 R: req::Request + 'static,
502 R::Params: DeserializeOwned<|> + panic::UnwindSafe + 'static, 502 R::Params: DeserializeOwned$0 + panic::UnwindSafe + 'static,
503 R::Result: Serialize + 'static, 503 R::Result: Serialize + 'static,
504"#, 504"#,
505 &[ 505 &[
@@ -510,26 +510,26 @@ fn foo<R>()
510 "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,", 510 "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,",
511 ], 511 ],
512 ); 512 );
513 do_check(r#"fn foo<T>() where T: <|>Copy"#, &["Copy"]); 513 do_check(r#"fn foo<T>() where T: $0Copy"#, &["Copy"]);
514 do_check(r#"fn foo<T>() where T: <|>Copy + Display"#, &["Copy", "Copy + "]); 514 do_check(r#"fn foo<T>() where T: $0Copy + Display"#, &["Copy", "Copy + "]);
515 do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]); 515 do_check(r#"fn foo<T>() where T: $0Copy +Display"#, &["Copy", "Copy +"]);
516 do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]); 516 do_check(r#"fn foo<T>() where T: $0Copy+Display"#, &["Copy", "Copy+"]);
517 do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]); 517 do_check(r#"fn foo<T>() where T: Copy + $0Display"#, &["Display", "+ Display"]);
518 do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "Display + "]); 518 do_check(r#"fn foo<T>() where T: Copy + $0Display + Sync"#, &["Display", "Display + "]);
519 do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]); 519 do_check(r#"fn foo<T>() where T: Copy +$0Display"#, &["Display", "+Display"]);
520 } 520 }
521 521
522 #[test] 522 #[test]
523 fn test_extend_trait_bounds_list_inline() { 523 fn test_extend_trait_bounds_list_inline() {
524 do_check(r#"fn foo<T: <|>Copy>() {}"#, &["Copy"]); 524 do_check(r#"fn foo<T: $0Copy>() {}"#, &["Copy"]);
525 do_check(r#"fn foo<T: <|>Copy + Display>() {}"#, &["Copy", "Copy + "]); 525 do_check(r#"fn foo<T: $0Copy + Display>() {}"#, &["Copy", "Copy + "]);
526 do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]); 526 do_check(r#"fn foo<T: $0Copy +Display>() {}"#, &["Copy", "Copy +"]);
527 do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]); 527 do_check(r#"fn foo<T: $0Copy+Display>() {}"#, &["Copy", "Copy+"]);
528 do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]); 528 do_check(r#"fn foo<T: Copy + $0Display>() {}"#, &["Display", "+ Display"]);
529 do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "Display + "]); 529 do_check(r#"fn foo<T: Copy + $0Display + Sync>() {}"#, &["Display", "Display + "]);
530 do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]); 530 do_check(r#"fn foo<T: Copy +$0Display>() {}"#, &["Display", "+Display"]);
531 do_check( 531 do_check(
532 r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#, 532 r#"fn foo<T: Copy$0 + Display, U: Copy>() {}"#,
533 &[ 533 &[
534 "Copy", 534 "Copy",
535 "Copy + ", 535 "Copy + ",
@@ -544,19 +544,19 @@ fn foo<R>()
544 #[test] 544 #[test]
545 fn test_extend_selection_on_tuple_in_type() { 545 fn test_extend_selection_on_tuple_in_type() {
546 do_check( 546 do_check(
547 r#"fn main() { let _: (krate, <|>_crate_def_map, module_id) = (); }"#, 547 r#"fn main() { let _: (krate, $0_crate_def_map, module_id) = (); }"#,
548 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], 548 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"],
549 ); 549 );
550 // white space variations 550 // white space variations
551 do_check( 551 do_check(
552 r#"fn main() { let _: (krate,<|>_crate_def_map,module_id) = (); }"#, 552 r#"fn main() { let _: (krate,$0_crate_def_map,module_id) = (); }"#,
553 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], 553 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"],
554 ); 554 );
555 do_check( 555 do_check(
556 r#" 556 r#"
557fn main() { let _: ( 557fn main() { let _: (
558 krate, 558 krate,
559 _crate<|>_def_map, 559 _crate$0_def_map,
560 module_id 560 module_id
561) = (); }"#, 561) = (); }"#,
562 &[ 562 &[
@@ -570,19 +570,19 @@ fn main() { let _: (
570 #[test] 570 #[test]
571 fn test_extend_selection_on_tuple_in_rvalue() { 571 fn test_extend_selection_on_tuple_in_rvalue() {
572 do_check( 572 do_check(
573 r#"fn main() { let var = (krate, _crate_def_map<|>, module_id); }"#, 573 r#"fn main() { let var = (krate, _crate_def_map$0, module_id); }"#,
574 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], 574 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"],
575 ); 575 );
576 // white space variations 576 // white space variations
577 do_check( 577 do_check(
578 r#"fn main() { let var = (krate,_crate<|>_def_map,module_id); }"#, 578 r#"fn main() { let var = (krate,_crate$0_def_map,module_id); }"#,
579 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], 579 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"],
580 ); 580 );
581 do_check( 581 do_check(
582 r#" 582 r#"
583fn main() { let var = ( 583fn main() { let var = (
584 krate, 584 krate,
585 _crate_def_map<|>, 585 _crate_def_map$0,
586 module_id 586 module_id
587); }"#, 587); }"#,
588 &[ 588 &[
@@ -596,19 +596,19 @@ fn main() { let var = (
596 #[test] 596 #[test]
597 fn test_extend_selection_on_tuple_pat() { 597 fn test_extend_selection_on_tuple_pat() {
598 do_check( 598 do_check(
599 r#"fn main() { let (krate, _crate_def_map<|>, module_id) = var; }"#, 599 r#"fn main() { let (krate, _crate_def_map$0, module_id) = var; }"#,
600 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"], 600 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"],
601 ); 601 );
602 // white space variations 602 // white space variations
603 do_check( 603 do_check(
604 r#"fn main() { let (krate,_crate<|>_def_map,module_id) = var; }"#, 604 r#"fn main() { let (krate,_crate$0_def_map,module_id) = var; }"#,
605 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"], 605 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"],
606 ); 606 );
607 do_check( 607 do_check(
608 r#" 608 r#"
609fn main() { let ( 609fn main() { let (
610 krate, 610 krate,
611 _crate_def_map<|>, 611 _crate_def_map$0,
612 module_id 612 module_id
613) = var; }"#, 613) = var; }"#,
614 &[ 614 &[
@@ -623,7 +623,7 @@ fn main() { let (
623 fn extend_selection_inside_macros() { 623 fn extend_selection_inside_macros() {
624 do_check( 624 do_check(
625 r#"macro_rules! foo { ($item:item) => {$item} } 625 r#"macro_rules! foo { ($item:item) => {$item} }
626 foo!{fn hello(na<|>me:usize){}}"#, 626 foo!{fn hello(na$0me:usize){}}"#,
627 &[ 627 &[
628 "name", 628 "name",
629 "name:usize", 629 "name:usize",
@@ -640,7 +640,7 @@ fn main() { let (
640 do_check( 640 do_check(
641 r#" macro_rules! foo2 { ($item:item) => {$item} } 641 r#" macro_rules! foo2 { ($item:item) => {$item} }
642 macro_rules! foo { ($item:item) => {foo2!($item);} } 642 macro_rules! foo { ($item:item) => {foo2!($item);} }
643 foo!{fn hello(na<|>me:usize){}}"#, 643 foo!{fn hello(na$0me:usize){}}"#,
644 &[ 644 &[
645 "name", 645 "name",
646 "name:usize", 646 "name:usize",
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs
index eb57f9224..cc8218885 100644
--- a/crates/ide/src/fixture.rs
+++ b/crates/ide/src/fixture.rs
@@ -20,12 +20,12 @@ pub(crate) fn files(ra_fixture: &str) -> (Analysis, Vec<FileId>) {
20 (host.analysis(), change_fixture.files) 20 (host.analysis(), change_fixture.files)
21} 21}
22 22
23/// Creates analysis from a multi-file fixture, returns positions marked with <|>. 23/// Creates analysis from a multi-file fixture, returns positions marked with $0.
24pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { 24pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
25 let mut host = AnalysisHost::default(); 25 let mut host = AnalysisHost::default();
26 let change_fixture = ChangeFixture::parse(ra_fixture); 26 let change_fixture = ChangeFixture::parse(ra_fixture);
27 host.db.apply_change(change_fixture.change); 27 host.db.apply_change(change_fixture.change);
28 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); 28 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
29 let offset = match range_or_offset { 29 let offset = match range_or_offset {
30 RangeOrOffset::Range(_) => panic!(), 30 RangeOrOffset::Range(_) => panic!(),
31 RangeOrOffset::Offset(it) => it, 31 RangeOrOffset::Offset(it) => it,
@@ -33,12 +33,12 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
33 (host.analysis(), FilePosition { file_id, offset }) 33 (host.analysis(), FilePosition { file_id, offset })
34} 34}
35 35
36/// Creates analysis for a single file, returns range marked with a pair of <|>. 36/// Creates analysis for a single file, returns range marked with a pair of $0.
37pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { 37pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) {
38 let mut host = AnalysisHost::default(); 38 let mut host = AnalysisHost::default();
39 let change_fixture = ChangeFixture::parse(ra_fixture); 39 let change_fixture = ChangeFixture::parse(ra_fixture);
40 host.db.apply_change(change_fixture.change); 40 host.db.apply_change(change_fixture.change);
41 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); 41 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
42 let range = match range_or_offset { 42 let range = match range_or_offset {
43 RangeOrOffset::Range(it) => it, 43 RangeOrOffset::Range(it) => it,
44 RangeOrOffset::Offset(_) => panic!(), 44 RangeOrOffset::Offset(_) => panic!(),
@@ -46,12 +46,12 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) {
46 (host.analysis(), FileRange { file_id, range }) 46 (host.analysis(), FileRange { file_id, range })
47} 47}
48 48
49/// Creates analysis from a multi-file fixture, returns positions marked with <|>. 49/// Creates analysis from a multi-file fixture, returns positions marked with $0.
50pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { 50pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) {
51 let mut host = AnalysisHost::default(); 51 let mut host = AnalysisHost::default();
52 let change_fixture = ChangeFixture::parse(ra_fixture); 52 let change_fixture = ChangeFixture::parse(ra_fixture);
53 host.db.apply_change(change_fixture.change); 53 host.db.apply_change(change_fixture.change);
54 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); 54 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
55 let offset = match range_or_offset { 55 let offset = match range_or_offset {
56 RangeOrOffset::Range(_) => panic!(), 56 RangeOrOffset::Range(_) => panic!(),
57 RangeOrOffset::Offset(it) => it, 57 RangeOrOffset::Offset(it) => it,
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs
index 5cbbe306e..f6e5a522b 100644
--- a/crates/ide/src/fn_references.rs
+++ b/crates/ide/src/fn_references.rs
@@ -34,7 +34,7 @@ mod tests {
34 fn test_find_all_methods() { 34 fn test_find_all_methods() {
35 let (analysis, pos) = fixture::position( 35 let (analysis, pos) = fixture::position(
36 r#" 36 r#"
37 fn private_fn() {<|>} 37 fn private_fn() {$0}
38 38
39 pub fn pub_fn() {} 39 pub fn pub_fn() {}
40 40
@@ -51,7 +51,7 @@ mod tests {
51 let (analysis, pos) = fixture::position( 51 let (analysis, pos) = fixture::position(
52 r#" 52 r#"
53 trait Foo { 53 trait Foo {
54 fn bar() {<|>} 54 fn bar() {$0}
55 fn baz() {} 55 fn baz() {}
56 } 56 }
57 "#, 57 "#,
@@ -67,7 +67,7 @@ mod tests {
67 r#" 67 r#"
68 //- /lib.rs 68 //- /lib.rs
69 #[test] 69 #[test]
70 fn foo() {<|>} 70 fn foo() {$0}
71 71
72 pub fn pub_fn() {} 72 pub fn pub_fn() {}
73 73
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 912144f8b..a1d2bce1d 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,15 +1,18 @@
1use either::Either; 1use either::Either;
2use hir::Semantics; 2use hir::{HasAttrs, ModuleDef, Semantics};
3use ide_db::{ 3use ide_db::{
4 base_db::FileId, 4 defs::{Definition, NameClass, NameRefClass},
5 defs::{NameClass, NameRefClass},
6 symbol_index, RootDatabase, 5 symbol_index, RootDatabase,
7}; 6};
8use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 7use syntax::{
8 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T,
9};
9 10
10use crate::{ 11use crate::{
11 display::{ToNav, TryToNav}, 12 display::{ToNav, TryToNav},
12 FilePosition, NavigationTarget, RangeInfo, SymbolKind, 13 doc_links::extract_definitions_from_markdown,
14 runnables::doc_owner_to_def,
15 FilePosition, NavigationTarget, RangeInfo,
13}; 16};
14 17
15// Feature: Go to Definition 18// Feature: Go to Definition
@@ -30,6 +33,10 @@ pub(crate) fn goto_definition(
30 let original_token = pick_best(file.token_at_offset(position.offset))?; 33 let original_token = pick_best(file.token_at_offset(position.offset))?;
31 let token = sema.descend_into_macros(original_token.clone()); 34 let token = sema.descend_into_macros(original_token.clone());
32 let parent = token.parent(); 35 let parent = token.parent();
36 if let Some(comment) = ast::Comment::cast(token.clone()) {
37 let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?;
38 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
39 }
33 40
34 let nav_targets = match_ast! { 41 let nav_targets = match_ast! {
35 match parent { 42 match parent {
@@ -41,19 +48,6 @@ pub(crate) fn goto_definition(
41 let nav = def.try_to_nav(sema.db)?; 48 let nav = def.try_to_nav(sema.db)?;
42 vec![nav] 49 vec![nav]
43 }, 50 },
44 ast::SelfParam(self_param) => {
45 vec![self_to_nav_target(self_param, position.file_id)?]
46 },
47 ast::PathSegment(segment) => {
48 segment.self_token()?;
49 let path = segment.parent_path();
50 if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) {
51 return None;
52 }
53 let func = segment.syntax().ancestors().find_map(ast::Fn::cast)?;
54 let self_param = func.param_list()?.self_param()?;
55 vec![self_to_nav_target(self_param, position.file_id)?]
56 },
57 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) { 51 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
58 let def = name_class.referenced_or_defined(sema.db); 52 let def = name_class.referenced_or_defined(sema.db);
59 let nav = def.try_to_nav(sema.db)?; 53 let nav = def.try_to_nav(sema.db)?;
@@ -68,31 +62,64 @@ pub(crate) fn goto_definition(
68 Some(RangeInfo::new(original_token.text_range(), nav_targets)) 62 Some(RangeInfo::new(original_token.text_range(), nav_targets))
69} 63}
70 64
65fn def_for_doc_comment(
66 sema: &Semantics<RootDatabase>,
67 position: FilePosition,
68 doc_comment: &ast::Comment,
69) -> Option<hir::ModuleDef> {
70 let parent = doc_comment.syntax().parent();
71 let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?;
72
73 let def = doc_owner_to_def(sema, parent)?;
74 match def {
75 Definition::ModuleDef(def) => match def {
76 ModuleDef::Module(it) => it.resolve_doc_path(sema.db, &link, ns),
77 ModuleDef::Function(it) => it.resolve_doc_path(sema.db, &link, ns),
78 ModuleDef::Adt(it) => it.resolve_doc_path(sema.db, &link, ns),
79 ModuleDef::Variant(it) => it.resolve_doc_path(sema.db, &link, ns),
80 ModuleDef::Const(it) => it.resolve_doc_path(sema.db, &link, ns),
81 ModuleDef::Static(it) => it.resolve_doc_path(sema.db, &link, ns),
82 ModuleDef::Trait(it) => it.resolve_doc_path(sema.db, &link, ns),
83 ModuleDef::TypeAlias(it) => it.resolve_doc_path(sema.db, &link, ns),
84 ModuleDef::BuiltinType(_) => return None,
85 },
86 Definition::Macro(it) => it.resolve_doc_path(sema.db, &link, ns),
87 Definition::Field(it) => it.resolve_doc_path(sema.db, &link, ns),
88 Definition::SelfType(_)
89 | Definition::Local(_)
90 | Definition::GenericParam(_)
91 | Definition::Label(_) => return None,
92 }
93}
94
95fn extract_positioned_link_from_comment(
96 position: FilePosition,
97 comment: &ast::Comment,
98) -> Option<(String, Option<hir::Namespace>)> {
99 let comment_range = comment.syntax().text_range();
100 let doc_comment = comment.doc_comment()?;
101 let def_links = extract_definitions_from_markdown(doc_comment);
102 let (def_link, ns, _) = def_links.iter().min_by_key(|(_, _, def_link_range)| {
103 let matched_position = comment_range.start() + TextSize::from(def_link_range.start as u32);
104 match position.offset.checked_sub(matched_position) {
105 Some(distance) => distance,
106 None => comment_range.end(),
107 }
108 })?;
109 Some((def_link.to_string(), ns.clone()))
110}
111
71fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 112fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
72 return tokens.max_by_key(priority); 113 return tokens.max_by_key(priority);
73 fn priority(n: &SyntaxToken) -> usize { 114 fn priority(n: &SyntaxToken) -> usize {
74 match n.kind() { 115 match n.kind() {
75 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 2, 116 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | COMMENT => 2,
76 kind if kind.is_trivia() => 0, 117 kind if kind.is_trivia() => 0,
77 _ => 1, 118 _ => 1,
78 } 119 }
79 } 120 }
80} 121}
81 122
82fn self_to_nav_target(self_param: ast::SelfParam, file_id: FileId) -> Option<NavigationTarget> {
83 let self_token = self_param.self_token()?;
84 Some(NavigationTarget {
85 file_id,
86 full_range: self_param.syntax().text_range(),
87 focus_range: Some(self_token.text_range()),
88 name: self_token.text().clone(),
89 kind: Some(SymbolKind::SelfParam),
90 container_name: None,
91 description: None,
92 docs: None,
93 })
94}
95
96#[derive(Debug)] 123#[derive(Debug)]
97pub(crate) enum ReferenceResult { 124pub(crate) enum ReferenceResult {
98 Exact(NavigationTarget), 125 Exact(NavigationTarget),
@@ -166,7 +193,7 @@ mod tests {
166 check( 193 check(
167 r#" 194 r#"
168 //- /main.rs crate:main deps:std 195 //- /main.rs crate:main deps:std
169 extern crate std<|>; 196 extern crate std$0;
170 //- /std/lib.rs crate:std 197 //- /std/lib.rs crate:std
171 // empty 198 // empty
172 //^ file 199 //^ file
@@ -179,7 +206,7 @@ mod tests {
179 check( 206 check(
180 r#" 207 r#"
181 //- /main.rs crate:main deps:std 208 //- /main.rs crate:main deps:std
182 extern crate std as abc<|>; 209 extern crate std as abc$0;
183 //- /std/lib.rs crate:std 210 //- /std/lib.rs crate:std
184 // empty 211 // empty
185 //^ file 212 //^ file
@@ -193,7 +220,7 @@ mod tests {
193 r#" 220 r#"
194struct Foo; 221struct Foo;
195 //^^^ 222 //^^^
196enum E { X(Foo<|>) } 223enum E { X(Foo$0) }
197"#, 224"#,
198 ); 225 );
199 } 226 }
@@ -204,7 +231,7 @@ enum E { X(Foo<|>) }
204 r#" 231 r#"
205struct Foo; 232struct Foo;
206 //^^^ 233 //^^^
207enum E { X(<|>Foo) } 234enum E { X($0Foo) }
208"#, 235"#,
209 ); 236 );
210 } 237 }
@@ -217,7 +244,7 @@ enum E { X(<|>Foo) }
217use a::Foo; 244use a::Foo;
218mod a; 245mod a;
219mod b; 246mod b;
220enum E { X(Foo<|>) } 247enum E { X(Foo$0) }
221 248
222//- /a.rs 249//- /a.rs
223struct Foo; 250struct Foo;
@@ -233,7 +260,7 @@ struct Foo;
233 check( 260 check(
234 r#" 261 r#"
235//- /lib.rs 262//- /lib.rs
236mod <|>foo; 263mod $0foo;
237 264
238//- /foo.rs 265//- /foo.rs
239// empty 266// empty
@@ -244,7 +271,7 @@ mod <|>foo;
244 check( 271 check(
245 r#" 272 r#"
246//- /lib.rs 273//- /lib.rs
247mod <|>foo; 274mod $0foo;
248 275
249//- /foo/mod.rs 276//- /foo/mod.rs
250// empty 277// empty
@@ -260,7 +287,7 @@ mod <|>foo;
260macro_rules! foo { () => { () } } 287macro_rules! foo { () => { () } }
261 //^^^ 288 //^^^
262fn bar() { 289fn bar() {
263 <|>foo!(); 290 $0foo!();
264} 291}
265"#, 292"#,
266 ); 293 );
@@ -273,7 +300,7 @@ fn bar() {
273//- /lib.rs 300//- /lib.rs
274use foo::foo; 301use foo::foo;
275fn bar() { 302fn bar() {
276 <|>foo!(); 303 $0foo!();
277} 304}
278 305
279//- /foo/lib.rs 306//- /foo/lib.rs
@@ -289,7 +316,7 @@ macro_rules! foo { () => { () } }
289 check( 316 check(
290 r#" 317 r#"
291//- /lib.rs 318//- /lib.rs
292use foo::foo<|>; 319use foo::foo$0;
293 320
294//- /foo/lib.rs 321//- /foo/lib.rs
295#[macro_export] 322#[macro_export]
@@ -312,7 +339,7 @@ define_fn!(foo);
312 //^^^ 339 //^^^
313 340
314fn bar() { 341fn bar() {
315 <|>foo(); 342 $0foo();
316} 343}
317"#, 344"#,
318 ); 345 );
@@ -331,7 +358,7 @@ macro_rules! define_fn {
331//^^^^^^^^^^^^^ 358//^^^^^^^^^^^^^
332 359
333fn bar() { 360fn bar() {
334 <|>foo(); 361 $0foo();
335} 362}
336"#, 363"#,
337 ); 364 );
@@ -347,7 +374,7 @@ macro_rules! foo {() => {0}}
347 374
348fn bar() { 375fn bar() {
349 match (0,1) { 376 match (0,1) {
350 (<|>foo!(), _) => {} 377 ($0foo!(), _) => {}
351 } 378 }
352} 379}
353"#, 380"#,
@@ -363,7 +390,7 @@ macro_rules! foo {() => {0}}
363 //^^^ 390 //^^^
364fn bar() { 391fn bar() {
365 match 0 { 392 match 0 {
366 <|>foo!() => {} 393 $0foo!() => {}
367 } 394 }
368} 395}
369"#, 396"#,
@@ -375,7 +402,7 @@ fn bar() {
375 check( 402 check(
376 r#" 403 r#"
377//- /lib.rs crate:main deps:foo 404//- /lib.rs crate:main deps:foo
378use foo as bar<|>; 405use foo as bar$0;
379 406
380//- /foo/lib.rs crate:foo 407//- /foo/lib.rs crate:foo
381// empty 408// empty
@@ -389,7 +416,7 @@ use foo as bar<|>;
389 check( 416 check(
390 r#" 417 r#"
391//- /lib.rs crate:main deps:foo 418//- /lib.rs crate:main deps:foo
392use foo::foo as bar<|>; 419use foo::foo as bar$0;
393 420
394//- /foo/lib.rs crate:foo 421//- /foo/lib.rs crate:foo
395#[macro_export] 422#[macro_export]
@@ -410,7 +437,7 @@ impl Foo {
410} 437}
411 438
412fn bar(foo: &Foo) { 439fn bar(foo: &Foo) {
413 foo.frobnicate<|>(); 440 foo.frobnicate$0();
414} 441}
415"#, 442"#,
416 ); 443 );
@@ -425,7 +452,7 @@ struct Foo {
425} //^^^^ 452} //^^^^
426 453
427fn bar(foo: &Foo) { 454fn bar(foo: &Foo) {
428 foo.spam<|>; 455 foo.spam$0;
429} 456}
430"#, 457"#,
431 ); 458 );
@@ -442,7 +469,7 @@ struct Foo {
442 469
443fn bar() -> Foo { 470fn bar() -> Foo {
444 Foo { 471 Foo {
445 spam<|>: 0, 472 spam$0: 0,
446 } 473 }
447} 474}
448"#, 475"#,
@@ -459,7 +486,7 @@ struct Foo {
459} //^^^^ 486} //^^^^
460 487
461fn bar(foo: Foo) -> Foo { 488fn bar(foo: Foo) -> Foo {
462 let Foo { spam<|>: _, } = foo 489 let Foo { spam$0: _, } = foo
463} 490}
464"#, 491"#,
465 ); 492 );
@@ -474,7 +501,7 @@ struct Foo { spam: u32 }
474 //^^^^ 501 //^^^^
475 502
476fn bar() -> Foo { 503fn bar() -> Foo {
477 Foo { spam<|>: m!() } 504 Foo { spam$0: m!() }
478} 505}
479", 506",
480 ); 507 );
@@ -489,7 +516,7 @@ struct Foo(u32);
489 516
490fn bar() { 517fn bar() {
491 let foo = Foo(0); 518 let foo = Foo(0);
492 foo.<|>0; 519 foo.$00;
493} 520}
494"#, 521"#,
495 ); 522 );
@@ -505,7 +532,7 @@ impl Foo {
505} //^^^^^^^^^^ 532} //^^^^^^^^^^
506 533
507fn bar(foo: &Foo) { 534fn bar(foo: &Foo) {
508 Foo::frobnicate<|>(); 535 Foo::frobnicate$0();
509} 536}
510"#, 537"#,
511 ); 538 );
@@ -520,7 +547,7 @@ trait Foo {
520} //^^^^^^^^^^ 547} //^^^^^^^^^^
521 548
522fn bar() { 549fn bar() {
523 Foo::frobnicate<|>(); 550 Foo::frobnicate$0();
524} 551}
525"#, 552"#,
526 ); 553 );
@@ -537,7 +564,7 @@ trait Trait {
537impl Trait for Foo {} 564impl Trait for Foo {}
538 565
539fn bar() { 566fn bar() {
540 Foo::frobnicate<|>(); 567 Foo::frobnicate$0();
541} 568}
542"#, 569"#,
543 ); 570 );
@@ -551,7 +578,7 @@ struct Foo;
551impl Foo { 578impl Foo {
552 //^^^ 579 //^^^
553 pub fn new() -> Self { 580 pub fn new() -> Self {
554 Self<|> {} 581 Self$0 {}
555 } 582 }
556} 583}
557"#, 584"#,
@@ -561,7 +588,7 @@ impl Foo {
561struct Foo; 588struct Foo;
562impl Foo { 589impl Foo {
563 //^^^ 590 //^^^
564 pub fn new() -> Self<|> { 591 pub fn new() -> Self$0 {
565 Self {} 592 Self {}
566 } 593 }
567} 594}
@@ -573,7 +600,7 @@ impl Foo {
573enum Foo { A } 600enum Foo { A }
574impl Foo { 601impl Foo {
575 //^^^ 602 //^^^
576 pub fn new() -> Self<|> { 603 pub fn new() -> Self$0 {
577 Foo::A 604 Foo::A
578 } 605 }
579} 606}
@@ -585,7 +612,7 @@ impl Foo {
585enum Foo { A } 612enum Foo { A }
586impl Foo { 613impl Foo {
587 //^^^ 614 //^^^
588 pub fn thing(a: &Self<|>) { 615 pub fn thing(a: &Self$0) {
589 } 616 }
590} 617}
591"#, 618"#,
@@ -603,7 +630,7 @@ trait Make {
603impl Make for Foo { 630impl Make for Foo {
604 //^^^ 631 //^^^
605 fn new() -> Self { 632 fn new() -> Self {
606 Self<|> {} 633 Self$0 {}
607 } 634 }
608} 635}
609"#, 636"#,
@@ -617,7 +644,7 @@ trait Make {
617} 644}
618impl Make for Foo { 645impl Make for Foo {
619 //^^^ 646 //^^^
620 fn new() -> Self<|> { 647 fn new() -> Self$0 {
621 Self {} 648 Self {}
622 } 649 }
623} 650}
@@ -629,7 +656,7 @@ impl Make for Foo {
629 fn goto_def_when_used_on_definition_name_itself() { 656 fn goto_def_when_used_on_definition_name_itself() {
630 check( 657 check(
631 r#" 658 r#"
632struct Foo<|> { value: u32 } 659struct Foo$0 { value: u32 }
633 //^^^ 660 //^^^
634 "#, 661 "#,
635 ); 662 );
@@ -637,21 +664,21 @@ struct Foo<|> { value: u32 }
637 check( 664 check(
638 r#" 665 r#"
639struct Foo { 666struct Foo {
640 field<|>: string, 667 field$0: string,
641} //^^^^^ 668} //^^^^^
642"#, 669"#,
643 ); 670 );
644 671
645 check( 672 check(
646 r#" 673 r#"
647fn foo_test<|>() { } 674fn foo_test$0() { }
648 //^^^^^^^^ 675 //^^^^^^^^
649"#, 676"#,
650 ); 677 );
651 678
652 check( 679 check(
653 r#" 680 r#"
654enum Foo<|> { Variant } 681enum Foo$0 { Variant }
655 //^^^ 682 //^^^
656"#, 683"#,
657 ); 684 );
@@ -660,7 +687,7 @@ enum Foo<|> { Variant }
660 r#" 687 r#"
661enum Foo { 688enum Foo {
662 Variant1, 689 Variant1,
663 Variant2<|>, 690 Variant2$0,
664 //^^^^^^^^ 691 //^^^^^^^^
665 Variant3, 692 Variant3,
666} 693}
@@ -669,35 +696,35 @@ enum Foo {
669 696
670 check( 697 check(
671 r#" 698 r#"
672static INNER<|>: &str = ""; 699static INNER$0: &str = "";
673 //^^^^^ 700 //^^^^^
674"#, 701"#,
675 ); 702 );
676 703
677 check( 704 check(
678 r#" 705 r#"
679const INNER<|>: &str = ""; 706const INNER$0: &str = "";
680 //^^^^^ 707 //^^^^^
681"#, 708"#,
682 ); 709 );
683 710
684 check( 711 check(
685 r#" 712 r#"
686type Thing<|> = Option<()>; 713type Thing$0 = Option<()>;
687 //^^^^^ 714 //^^^^^
688"#, 715"#,
689 ); 716 );
690 717
691 check( 718 check(
692 r#" 719 r#"
693trait Foo<|> { } 720trait Foo$0 { }
694 //^^^ 721 //^^^
695"#, 722"#,
696 ); 723 );
697 724
698 check( 725 check(
699 r#" 726 r#"
700mod bar<|> { } 727mod bar$0 { }
701 //^^^ 728 //^^^
702"#, 729"#,
703 ); 730 );
@@ -714,7 +741,7 @@ fn foo() {}
714 //^^^ 741 //^^^
715id! { 742id! {
716 fn bar() { 743 fn bar() {
717 fo<|>o(); 744 fo$0o();
718 } 745 }
719} 746}
720mod confuse_index { fn foo(); } 747mod confuse_index { fn foo(); }
@@ -743,7 +770,7 @@ pub mod __export {
743fn foo() -> i8 {} 770fn foo() -> i8 {}
744 //^^^ 771 //^^^
745fn test() { 772fn test() {
746 format!("{}", fo<|>o()) 773 format!("{}", fo$0o())
747} 774}
748"#, 775"#,
749 ); 776 );
@@ -761,7 +788,7 @@ macro_rules! include {}
761//^^^^^^^^^^^^^^^^^^^ 788//^^^^^^^^^^^^^^^^^^^
762 789
763fn f() { 790fn f() {
764 foo<|>(); 791 foo$0();
765} 792}
766 793
767mod confuse_index { 794mod confuse_index {
@@ -778,7 +805,7 @@ fn foo() {}
778 fn goto_for_type_param() { 805 fn goto_for_type_param() {
779 check( 806 check(
780 r#" 807 r#"
781struct Foo<T: Clone> { t: <|>T } 808struct Foo<T: Clone> { t: $0T }
782 //^ 809 //^
783"#, 810"#,
784 ); 811 );
@@ -796,7 +823,7 @@ fn foo() {
796 let x = 1; 823 let x = 1;
797 //^ 824 //^
798 id!({ 825 id!({
799 let y = <|>x; 826 let y = $0x;
800 let z = y; 827 let z = y;
801 }); 828 });
802} 829}
@@ -814,7 +841,7 @@ fn foo() {
814 id!({ 841 id!({
815 let y = x; 842 let y = x;
816 //^ 843 //^
817 let z = <|>y; 844 let z = $0y;
818 }); 845 });
819} 846}
820"#, 847"#,
@@ -829,7 +856,7 @@ fn main() {
829 fn foo() { 856 fn foo() {
830 let x = 92; 857 let x = 92;
831 //^ 858 //^
832 <|>x; 859 $0x;
833 } 860 }
834} 861}
835"#, 862"#,
@@ -843,7 +870,7 @@ fn main() {
843fn bar() { 870fn bar() {
844 macro_rules! foo { () => { () } } 871 macro_rules! foo { () => { () } }
845 //^^^ 872 //^^^
846 <|>foo!(); 873 $0foo!();
847} 874}
848"#, 875"#,
849 ); 876 );
@@ -857,7 +884,7 @@ struct Foo { x: i32 }
857fn main() { 884fn main() {
858 let x = 92; 885 let x = 92;
859 //^ 886 //^
860 Foo { x<|> }; 887 Foo { x$0 };
861} 888}
862"#, 889"#,
863 ) 890 )
@@ -872,7 +899,7 @@ enum Foo {
872} //^ 899} //^
873fn baz(foo: Foo) { 900fn baz(foo: Foo) {
874 match foo { 901 match foo {
875 Foo::Bar { x<|> } => x 902 Foo::Bar { x$0 } => x
876 }; 903 };
877} 904}
878"#, 905"#,
@@ -887,7 +914,7 @@ enum Foo { Bar }
887 //^^^ 914 //^^^
888impl Foo { 915impl Foo {
889 fn baz(self) { 916 fn baz(self) {
890 match self { Self::Bar<|> => {} } 917 match self { Self::Bar$0 => {} }
891 } 918 }
892} 919}
893"#, 920"#,
@@ -902,7 +929,7 @@ enum Foo { Bar { val: i32 } }
902 //^^^ 929 //^^^
903impl Foo { 930impl Foo {
904 fn baz(self) -> i32 { 931 fn baz(self) -> i32 {
905 match self { Self::Bar<|> { val } => {} } 932 match self { Self::Bar$0 { val } => {} }
906 } 933 }
907} 934}
908"#, 935"#,
@@ -916,7 +943,7 @@ impl Foo {
916enum Foo { Bar } 943enum Foo { Bar }
917 //^^^ 944 //^^^
918impl Foo { 945impl Foo {
919 fn baz(self) { Self::Bar<|>; } 946 fn baz(self) { Self::Bar$0; }
920} 947}
921"#, 948"#,
922 ); 949 );
@@ -929,7 +956,7 @@ impl Foo {
929enum Foo { Bar { val: i32 } } 956enum Foo { Bar { val: i32 } }
930 //^^^ 957 //^^^
931impl Foo { 958impl Foo {
932 fn baz(self) { Self::Bar<|> {val: 4}; } 959 fn baz(self) { Self::Bar$0 {val: 4}; }
933} 960}
934"#, 961"#,
935 ); 962 );
@@ -939,7 +966,7 @@ impl Foo {
939 fn goto_def_for_type_alias_generic_parameter() { 966 fn goto_def_for_type_alias_generic_parameter() {
940 check( 967 check(
941 r#" 968 r#"
942type Alias<T> = T<|>; 969type Alias<T> = T$0;
943 //^ 970 //^
944"#, 971"#,
945 ) 972 )
@@ -950,7 +977,7 @@ type Alias<T> = T<|>;
950 check( 977 check(
951 r#" 978 r#"
952//- /lib.rs 979//- /lib.rs
953foo::module<|>::mac!(); 980foo::module$0::mac!();
954 981
955//- /foo/lib.rs 982//- /foo/lib.rs
956pub mod module { 983pub mod module {
@@ -972,7 +999,7 @@ trait Iterator {
972 //^^^^ 999 //^^^^
973} 1000}
974 1001
975fn f() -> impl Iterator<Item<|> = u8> {} 1002fn f() -> impl Iterator<Item$0 = u8> {}
976"#, 1003"#,
977 ); 1004 );
978 } 1005 }
@@ -987,7 +1014,7 @@ trait Iterator {
987 type B; 1014 type B;
988} 1015}
989 1016
990fn f() -> impl Iterator<A<|> = u8, B = ()> {} 1017fn f() -> impl Iterator<A$0 = u8, B = ()> {}
991"#, 1018"#,
992 ); 1019 );
993 check( 1020 check(
@@ -998,7 +1025,7 @@ trait Iterator {
998 //^ 1025 //^
999} 1026}
1000 1027
1001fn f() -> impl Iterator<A = u8, B<|> = ()> {} 1028fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1002"#, 1029"#,
1003 ); 1030 );
1004 } 1031 }
@@ -1012,7 +1039,7 @@ trait Iterator {
1012 //^^^^ 1039 //^^^^
1013} 1040}
1014 1041
1015fn g() -> <() as Iterator<Item<|> = ()>>::Item {} 1042fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1016"#, 1043"#,
1017 ); 1044 );
1018 } 1045 }
@@ -1027,7 +1054,7 @@ trait Iterator {
1027 type B; 1054 type B;
1028} 1055}
1029 1056
1030fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {} 1057fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1031"#, 1058"#,
1032 ); 1059 );
1033 check( 1060 check(
@@ -1038,7 +1065,7 @@ trait Iterator {
1038 //^ 1065 //^
1039} 1066}
1040 1067
1041fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {} 1068fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1042"#, 1069"#,
1043 ); 1070 );
1044 } 1071 }
@@ -1052,7 +1079,7 @@ struct Foo {}
1052impl Foo { 1079impl Foo {
1053 fn bar(self: &Foo) { 1080 fn bar(self: &Foo) {
1054 //^^^^ 1081 //^^^^
1055 let foo = sel<|>f; 1082 let foo = sel$0f;
1056 } 1083 }
1057}"#, 1084}"#,
1058 ) 1085 )
@@ -1065,7 +1092,7 @@ impl Foo {
1065struct Foo {} 1092struct Foo {}
1066 1093
1067impl Foo { 1094impl Foo {
1068 fn bar(&self<|>) { 1095 fn bar(&self$0) {
1069 //^^^^ 1096 //^^^^
1070 } 1097 }
1071}"#, 1098}"#,
@@ -1076,7 +1103,7 @@ impl Foo {
1076 fn goto_lifetime_param_on_decl() { 1103 fn goto_lifetime_param_on_decl() {
1077 check( 1104 check(
1078 r#" 1105 r#"
1079fn foo<'foobar<|>>(_: &'foobar ()) { 1106fn foo<'foobar$0>(_: &'foobar ()) {
1080 //^^^^^^^ 1107 //^^^^^^^
1081}"#, 1108}"#,
1082 ) 1109 )
@@ -1086,7 +1113,7 @@ fn foo<'foobar<|>>(_: &'foobar ()) {
1086 fn goto_lifetime_param_decl() { 1113 fn goto_lifetime_param_decl() {
1087 check( 1114 check(
1088 r#" 1115 r#"
1089fn foo<'foobar>(_: &'foobar<|> ()) { 1116fn foo<'foobar>(_: &'foobar$0 ()) {
1090 //^^^^^^^ 1117 //^^^^^^^
1091}"#, 1118}"#,
1092 ) 1119 )
@@ -1097,7 +1124,7 @@ fn foo<'foobar>(_: &'foobar<|> ()) {
1097 check( 1124 check(
1098 r#" 1125 r#"
1099fn foo<'foobar>(_: &'foobar ()) { 1126fn foo<'foobar>(_: &'foobar ()) {
1100 fn foo<'foobar>(_: &'foobar<|> ()) {} 1127 fn foo<'foobar>(_: &'foobar$0 ()) {}
1101 //^^^^^^^ 1128 //^^^^^^^
1102}"#, 1129}"#,
1103 ) 1130 )
@@ -1108,13 +1135,13 @@ fn foo<'foobar>(_: &'foobar ()) {
1108 fn goto_lifetime_hrtb() { 1135 fn goto_lifetime_hrtb() {
1109 check( 1136 check(
1110 r#"trait Foo<T> {} 1137 r#"trait Foo<T> {}
1111fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {} 1138fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1112 //^^ 1139 //^^
1113"#, 1140"#,
1114 ); 1141 );
1115 check( 1142 check(
1116 r#"trait Foo<T> {} 1143 r#"trait Foo<T> {}
1117fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} 1144fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1118 //^^ 1145 //^^
1119"#, 1146"#,
1120 ); 1147 );
@@ -1125,7 +1152,7 @@ fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {}
1125 fn goto_lifetime_hrtb_for_type() { 1152 fn goto_lifetime_hrtb_for_type() {
1126 check( 1153 check(
1127 r#"trait Foo<T> {} 1154 r#"trait Foo<T> {}
1128fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {} 1155fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1129 //^^ 1156 //^^
1130"#, 1157"#,
1131 ); 1158 );
@@ -1139,10 +1166,40 @@ fn foo<'foo>(_: &'foo ()) {
1139 'foo: { 1166 'foo: {
1140 //^^^^ 1167 //^^^^
1141 'bar: loop { 1168 'bar: loop {
1142 break 'foo<|>; 1169 break 'foo$0;
1143 } 1170 }
1144 } 1171 }
1145}"#, 1172}"#,
1146 ) 1173 )
1147 } 1174 }
1175
1176 #[test]
1177 fn goto_def_for_intra_doc_link_same_file() {
1178 check(
1179 r#"
1180/// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar)
1181pub fn bar() { }
1182
1183/// You might want to see [`std::fs::read()`] too.
1184pub fn foo() { }
1185 //^^^
1186
1187}"#,
1188 )
1189 }
1190
1191 #[test]
1192 fn goto_def_for_intra_doc_link_inner() {
1193 check(
1194 r#"
1195//- /main.rs
1196mod m;
1197struct S;
1198 //^
1199
1200//- /m.rs
1201//! [`super::S$0`]
1202"#,
1203 )
1204 }
1148} 1205}
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index da9378a97..761a98b2c 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -107,7 +107,7 @@ mod tests {
107 fn goto_implementation_works() { 107 fn goto_implementation_works() {
108 check( 108 check(
109 r#" 109 r#"
110struct Foo<|>; 110struct Foo$0;
111impl Foo {} 111impl Foo {}
112 //^^^ 112 //^^^
113"#, 113"#,
@@ -118,7 +118,7 @@ impl Foo {}
118 fn goto_implementation_works_multiple_blocks() { 118 fn goto_implementation_works_multiple_blocks() {
119 check( 119 check(
120 r#" 120 r#"
121struct Foo<|>; 121struct Foo$0;
122impl Foo {} 122impl Foo {}
123 //^^^ 123 //^^^
124impl Foo {} 124impl Foo {}
@@ -131,7 +131,7 @@ impl Foo {}
131 fn goto_implementation_works_multiple_mods() { 131 fn goto_implementation_works_multiple_mods() {
132 check( 132 check(
133 r#" 133 r#"
134struct Foo<|>; 134struct Foo$0;
135mod a { 135mod a {
136 impl super::Foo {} 136 impl super::Foo {}
137 //^^^^^^^^^^ 137 //^^^^^^^^^^
@@ -149,7 +149,7 @@ mod b {
149 check( 149 check(
150 r#" 150 r#"
151//- /lib.rs 151//- /lib.rs
152struct Foo<|>; 152struct Foo$0;
153mod a; 153mod a;
154mod b; 154mod b;
155//- /a.rs 155//- /a.rs
@@ -166,7 +166,7 @@ impl crate::Foo {}
166 fn goto_implementation_for_trait() { 166 fn goto_implementation_for_trait() {
167 check( 167 check(
168 r#" 168 r#"
169trait T<|> {} 169trait T$0 {}
170struct Foo; 170struct Foo;
171impl T for Foo {} 171impl T for Foo {}
172 //^^^ 172 //^^^
@@ -179,7 +179,7 @@ impl T for Foo {}
179 check( 179 check(
180 r#" 180 r#"
181//- /lib.rs 181//- /lib.rs
182trait T<|> {}; 182trait T$0 {};
183struct Foo; 183struct Foo;
184mod a; 184mod a;
185mod b; 185mod b;
@@ -199,7 +199,7 @@ impl crate::T for crate::Foo {}
199 r#" 199 r#"
200//- /lib.rs 200//- /lib.rs
201trait T {} 201trait T {}
202struct Foo<|>; 202struct Foo$0;
203impl Foo {} 203impl Foo {}
204 //^^^ 204 //^^^
205impl T for Foo {} 205impl T for Foo {}
@@ -216,7 +216,7 @@ impl T for &Foo {}
216 r#" 216 r#"
217 #[derive(Copy)] 217 #[derive(Copy)]
218//^^^^^^^^^^^^^^^ 218//^^^^^^^^^^^^^^^
219struct Foo<|>; 219struct Foo$0;
220 220
221mod marker { 221mod marker {
222 trait Copy {} 222 trait Copy {}
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index 7e84e06be..369a59820 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -76,7 +76,7 @@ mod tests {
76struct Foo; 76struct Foo;
77 //^^^ 77 //^^^
78fn foo() { 78fn foo() {
79 let f: Foo; f<|> 79 let f: Foo; f$0
80} 80}
81"#, 81"#,
82 ); 82 );
@@ -89,7 +89,7 @@ fn foo() {
89struct Foo; 89struct Foo;
90 //^^^ 90 //^^^
91fn foo() { 91fn foo() {
92 let f: &Foo; f<|> 92 let f: &Foo; f$0
93} 93}
94"#, 94"#,
95 ); 95 );
@@ -103,7 +103,7 @@ macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
103struct Foo {} 103struct Foo {}
104 //^^^ 104 //^^^
105id! { 105id! {
106 fn bar() { let f<|> = Foo {}; } 106 fn bar() { let f$0 = Foo {}; }
107} 107}
108"#, 108"#,
109 ); 109 );
@@ -115,7 +115,7 @@ id! {
115 r#" 115 r#"
116struct Foo; 116struct Foo;
117 //^^^ 117 //^^^
118fn foo(<|>f: Foo) {} 118fn foo($0f: Foo) {}
119"#, 119"#,
120 ); 120 );
121 } 121 }
@@ -129,7 +129,7 @@ struct Foo;
129struct Bar(Foo); 129struct Bar(Foo);
130fn foo() { 130fn foo() {
131 let bar = Bar(Foo); 131 let bar = Bar(Foo);
132 bar.<|>0; 132 bar.$00;
133} 133}
134"#, 134"#,
135 ); 135 );
@@ -142,7 +142,7 @@ fn foo() {
142struct Foo; 142struct Foo;
143 //^^^ 143 //^^^
144impl Foo { 144impl Foo {
145 fn f(&self<|>) {} 145 fn f(&self$0) {}
146} 146}
147"#, 147"#,
148 ) 148 )
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index a12a2475e..2024acd94 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,6 +1,6 @@
1use hir::{ 1use hir::{
2 Adt, AsAssocItem, AssocItemContainer, FieldSource, HasAttrs, HasSource, HirDisplay, Module, 2 Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource,
3 ModuleDef, ModuleSource, Semantics, 3 HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
4}; 4};
5use ide_db::base_db::SourceDatabase; 5use ide_db::base_db::SourceDatabase;
6use ide_db::{ 6use ide_db::{
@@ -17,7 +17,7 @@ use crate::{
17 doc_links::{remove_links, rewrite_links}, 17 doc_links::{remove_links, rewrite_links},
18 markdown_remove::remove_markdown, 18 markdown_remove::remove_markdown,
19 markup::Markup, 19 markup::Markup,
20 runnables::{runnable, runnable_fn}, 20 runnables::{runnable_fn, runnable_mod},
21 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, 21 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
22}; 22};
23 23
@@ -134,17 +134,14 @@ pub(crate) fn hover(
134 return None; 134 return None;
135 } 135 }
136 136
137 let node = token.ancestors().find(|n| { 137 let node = token
138 ast::Expr::can_cast(n.kind()) 138 .ancestors()
139 || ast::Pat::can_cast(n.kind()) 139 .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
140 || ast::SelfParam::can_cast(n.kind())
141 })?;
142 140
143 let ty = match_ast! { 141 let ty = match_ast! {
144 match node { 142 match node {
145 ast::Expr(it) => sema.type_of_expr(&it)?, 143 ast::Expr(it) => sema.type_of_expr(&it)?,
146 ast::Pat(it) => sema.type_of_pat(&it)?, 144 ast::Pat(it) => sema.type_of_pat(&it)?,
147 ast::SelfParam(self_param) => sema.type_of_self(&self_param)?,
148 // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. 145 // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve.
149 // (e.g expanding a builtin macro). So we give up here. 146 // (e.g expanding a builtin macro). So we give up here.
150 ast::MacroCall(_it) => return None, 147 ast::MacroCall(_it) => return None,
@@ -175,12 +172,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
175 Definition::SelfType(it) => it.target_ty(db).as_adt(), 172 Definition::SelfType(it) => it.target_ty(db).as_adt(),
176 _ => None, 173 _ => None,
177 }?; 174 }?;
178 match adt { 175 adt.try_to_nav(db).map(to_action)
179 Adt::Struct(it) => it.try_to_nav(db),
180 Adt::Union(it) => it.try_to_nav(db),
181 Adt::Enum(it) => it.try_to_nav(db),
182 }
183 .map(to_action)
184} 176}
185 177
186fn runnable_action( 178fn runnable_action(
@@ -192,7 +184,7 @@ fn runnable_action(
192 Definition::ModuleDef(it) => match it { 184 Definition::ModuleDef(it) => match it {
193 ModuleDef::Module(it) => match it.definition_source(sema.db).value { 185 ModuleDef::Module(it) => match it.definition_source(sema.db).value {
194 ModuleSource::Module(it) => { 186 ModuleSource::Module(it) => {
195 runnable(&sema, it.syntax().clone()).map(|it| HoverAction::Runnable(it)) 187 runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it))
196 } 188 }
197 _ => None, 189 _ => None,
198 }, 190 },
@@ -220,12 +212,12 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
220 } 212 }
221 }; 213 };
222 214
223 if let Definition::TypeParam(it) = def { 215 if let Definition::GenericParam(GenericParam::TypeParam(it)) = def {
224 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); 216 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
225 } else { 217 } else {
226 let ty = match def { 218 let ty = match def {
227 Definition::Local(it) => it.ty(db), 219 Definition::Local(it) => it.ty(db),
228 Definition::ConstParam(it) => it.ty(db), 220 Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db),
229 _ => return None, 221 _ => return None,
230 }; 222 };
231 223
@@ -357,9 +349,11 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
357 }) 349 })
358 } 350 }
359 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 351 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
360 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), 352 Definition::GenericParam(it) => match it {
361 Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))), 353 GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))),
362 Definition::ConstParam(it) => from_def_source(db, it, None), 354 GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
355 GenericParam::ConstParam(it) => from_def_source(db, it, None),
356 },
363 }; 357 };
364 358
365 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> 359 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
@@ -389,7 +383,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
389 return tokens.max_by_key(priority); 383 return tokens.max_by_key(priority);
390 fn priority(n: &SyntaxToken) -> usize { 384 fn priority(n: &SyntaxToken) -> usize {
391 match n.kind() { 385 match n.kind() {
392 IDENT | INT_NUMBER | LIFETIME_IDENT => 3, 386 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 3,
393 T!['('] | T![')'] => 2, 387 T!['('] | T![')'] => 2,
394 kind if kind.is_trivia() => 0, 388 kind if kind.is_trivia() => 0,
395 _ => 1, 389 _ => 1,
@@ -457,7 +451,7 @@ mod tests {
457pub fn foo() -> u32 { 1 } 451pub fn foo() -> u32 { 1 }
458 452
459fn main() { 453fn main() {
460 let foo_test = foo()<|>; 454 let foo_test = foo()$0;
461} 455}
462"#, 456"#,
463 expect![[r#" 457 expect![[r#"
@@ -476,7 +470,7 @@ fn main() {
476pub fn foo() -> u32 { 1 } 470pub fn foo() -> u32 { 1 }
477 471
478fn main() { 472fn main() {
479 let foo_test = foo()<|>; 473 let foo_test = foo()$0;
480} 474}
481"#, 475"#,
482 expect![[r#" 476 expect![[r#"
@@ -506,7 +500,7 @@ fn main() {
506 Option::Some(*memo + value) 500 Option::Some(*memo + value)
507 }; 501 };
508 let number = 5u32; 502 let number = 5u32;
509 let mut iter<|> = scan(OtherStruct { i: num }, closure, number); 503 let mut iter$0 = scan(OtherStruct { i: num }, closure, number);
510} 504}
511"#, 505"#,
512 expect![[r#" 506 expect![[r#"
@@ -526,7 +520,7 @@ fn main() {
526 r#" 520 r#"
527pub fn foo() -> u32 { 1 } 521pub fn foo() -> u32 { 1 }
528 522
529fn main() { let foo_test = fo<|>o(); } 523fn main() { let foo_test = fo$0o(); }
530"#, 524"#,
531 expect![[r#" 525 expect![[r#"
532 *foo* 526 *foo*
@@ -558,7 +552,7 @@ mod a;
558mod b; 552mod b;
559mod c; 553mod c;
560 554
561fn main() { let foo_test = fo<|>o(); } 555fn main() { let foo_test = fo$0o(); }
562 "#, 556 "#,
563 expect![[r#" 557 expect![[r#"
564 *foo* 558 *foo*
@@ -575,7 +569,7 @@ fn main() { let foo_test = fo<|>o(); }
575 r#" 569 r#"
576pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { } 570pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
577 571
578fn main() { let foo_test = fo<|>o(); } 572fn main() { let foo_test = fo$0o(); }
579 "#, 573 "#,
580 expect![[r#" 574 expect![[r#"
581 *foo* 575 *foo*
@@ -595,7 +589,7 @@ fn main() { let foo_test = fo<|>o(); }
595 fn hover_shows_fn_signature_on_fn_name() { 589 fn hover_shows_fn_signature_on_fn_name() {
596 check( 590 check(
597 r#" 591 r#"
598pub fn foo<|>(a: u32, b: u32) -> u32 {} 592pub fn foo$0(a: u32, b: u32) -> u32 {}
599 593
600fn main() { } 594fn main() { }
601"#, 595"#,
@@ -623,7 +617,7 @@ fn main() { }
623/// # 617/// #
624/// foo(Path::new("hello, world!")) 618/// foo(Path::new("hello, world!"))
625/// ``` 619/// ```
626pub fn foo<|>(_: &Path) {} 620pub fn foo$0(_: &Path) {}
627 621
628fn main() { } 622fn main() { }
629"#, 623"#,
@@ -656,7 +650,7 @@ fn main() { }
656 check( 650 check(
657 r##" 651 r##"
658#[doc = r#"Raw string doc attr"#] 652#[doc = r#"Raw string doc attr"#]
659pub fn foo<|>(_: &Path) {} 653pub fn foo$0(_: &Path) {}
660 654
661fn main() { } 655fn main() { }
662"##, 656"##,
@@ -686,7 +680,7 @@ fn main() { }
686struct Foo { field_a: u32 } 680struct Foo { field_a: u32 }
687 681
688fn main() { 682fn main() {
689 let foo = Foo { field_a<|>: 0, }; 683 let foo = Foo { field_a$0: 0, };
690} 684}
691"#, 685"#,
692 expect![[r#" 686 expect![[r#"
@@ -705,7 +699,7 @@ fn main() {
705 // Hovering over the field in the definition 699 // Hovering over the field in the definition
706 check( 700 check(
707 r#" 701 r#"
708struct Foo { field_a<|>: u32 } 702struct Foo { field_a$0: u32 }
709 703
710fn main() { 704fn main() {
711 let foo = Foo { field_a: 0 }; 705 let foo = Foo { field_a: 0 };
@@ -728,7 +722,7 @@ fn main() {
728 #[test] 722 #[test]
729 fn hover_const_static() { 723 fn hover_const_static() {
730 check( 724 check(
731 r#"const foo<|>: u32 = 123;"#, 725 r#"const foo$0: u32 = 123;"#,
732 expect![[r#" 726 expect![[r#"
733 *foo* 727 *foo*
734 728
@@ -742,7 +736,7 @@ fn main() {
742 "#]], 736 "#]],
743 ); 737 );
744 check( 738 check(
745 r#"static foo<|>: u32 = 456;"#, 739 r#"static foo$0: u32 = 456;"#,
746 expect![[r#" 740 expect![[r#"
747 *foo* 741 *foo*
748 742
@@ -764,7 +758,7 @@ fn main() {
764struct Test<K, T = u8> { k: K, t: T } 758struct Test<K, T = u8> { k: K, t: T }
765 759
766fn main() { 760fn main() {
767 let zz<|> = Test { t: 23u8, k: 33 }; 761 let zz$0 = Test { t: 23u8, k: 33 };
768}"#, 762}"#,
769 expect![[r#" 763 expect![[r#"
770 *zz* 764 *zz*
@@ -783,7 +777,7 @@ fn main() {
783enum Option<T> { Some(T) } 777enum Option<T> { Some(T) }
784use Option::Some; 778use Option::Some;
785 779
786fn main() { So<|>me(12); } 780fn main() { So$0me(12); }
787"#, 781"#,
788 expect![[r#" 782 expect![[r#"
789 *Some* 783 *Some*
@@ -803,7 +797,7 @@ fn main() { So<|>me(12); }
803enum Option<T> { Some(T) } 797enum Option<T> { Some(T) }
804use Option::Some; 798use Option::Some;
805 799
806fn main() { let b<|>ar = Some(12); } 800fn main() { let b$0ar = Some(12); }
807"#, 801"#,
808 expect![[r#" 802 expect![[r#"
809 *bar* 803 *bar*
@@ -821,7 +815,7 @@ fn main() { let b<|>ar = Some(12); }
821 r#" 815 r#"
822enum Option<T> { 816enum Option<T> {
823 /// The None variant 817 /// The None variant
824 Non<|>e 818 Non$0e
825} 819}
826"#, 820"#,
827 expect![[r#" 821 expect![[r#"
@@ -848,7 +842,7 @@ enum Option<T> {
848 Some(T) 842 Some(T)
849} 843}
850fn main() { 844fn main() {
851 let s = Option::Som<|>e(12); 845 let s = Option::Som$0e(12);
852} 846}
853"#, 847"#,
854 expect![[r#" 848 expect![[r#"
@@ -872,7 +866,7 @@ fn main() {
872 #[test] 866 #[test]
873 fn hover_for_local_variable() { 867 fn hover_for_local_variable() {
874 check( 868 check(
875 r#"fn func(foo: i32) { fo<|>o; }"#, 869 r#"fn func(foo: i32) { fo$0o; }"#,
876 expect![[r#" 870 expect![[r#"
877 *foo* 871 *foo*
878 872
@@ -886,7 +880,7 @@ fn main() {
886 #[test] 880 #[test]
887 fn hover_for_local_variable_pat() { 881 fn hover_for_local_variable_pat() {
888 check( 882 check(
889 r#"fn func(fo<|>o: i32) {}"#, 883 r#"fn func(fo$0o: i32) {}"#,
890 expect![[r#" 884 expect![[r#"
891 *foo* 885 *foo*
892 886
@@ -900,7 +894,7 @@ fn main() {
900 #[test] 894 #[test]
901 fn hover_local_var_edge() { 895 fn hover_local_var_edge() {
902 check( 896 check(
903 r#"fn func(foo: i32) { if true { <|>foo; }; }"#, 897 r#"fn func(foo: i32) { if true { $0foo; }; }"#,
904 expect![[r#" 898 expect![[r#"
905 *foo* 899 *foo*
906 900
@@ -914,7 +908,7 @@ fn main() {
914 #[test] 908 #[test]
915 fn hover_for_param_edge() { 909 fn hover_for_param_edge() {
916 check( 910 check(
917 r#"fn func(<|>foo: i32) {}"#, 911 r#"fn func($0foo: i32) {}"#,
918 expect![[r#" 912 expect![[r#"
919 *foo* 913 *foo*
920 914
@@ -934,7 +928,7 @@ fn main() {
934 trait DerefMut { 928 trait DerefMut {
935 type Target: ?Sized; 929 type Target: ?Sized;
936 } 930 }
937 fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#, 931 fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
938 expect![[r#" 932 expect![[r#"
939 *_x* 933 *_x*
940 934
@@ -955,7 +949,7 @@ impl Thing {
955 fn new() -> Thing { Thing { x: 0 } } 949 fn new() -> Thing { Thing { x: 0 } }
956} 950}
957 951
958fn main() { let foo_<|>test = Thing::new(); } 952fn main() { let foo_$0test = Thing::new(); }
959 "#, 953 "#,
960 expect![[r#" 954 expect![[r#"
961 *foo_test* 955 *foo_test*
@@ -979,7 +973,7 @@ mod wrapper {
979 } 973 }
980} 974}
981 975
982fn main() { let foo_test = wrapper::Thing::new<|>(); } 976fn main() { let foo_test = wrapper::Thing::new$0(); }
983"#, 977"#,
984 expect![[r#" 978 expect![[r#"
985 *new* 979 *new*
@@ -1006,7 +1000,7 @@ impl X {
1006 1000
1007fn main() { 1001fn main() {
1008 match 1 { 1002 match 1 {
1009 X::C<|> => {}, 1003 X::C$0 => {},
1010 2 => {}, 1004 2 => {},
1011 _ => {} 1005 _ => {}
1012 }; 1006 };
@@ -1032,7 +1026,7 @@ fn main() {
1032 r#" 1026 r#"
1033struct Thing { x: u32 } 1027struct Thing { x: u32 }
1034impl Thing { 1028impl Thing {
1035 fn new() -> Self { Self<|> { x: 0 } } 1029 fn new() -> Self { Self$0 { x: 0 } }
1036} 1030}
1037"#, 1031"#,
1038 expect![[r#" 1032 expect![[r#"
@@ -1051,7 +1045,7 @@ impl Thing {
1051 r#" 1045 r#"
1052struct Thing { x: u32 } 1046struct Thing { x: u32 }
1053impl Thing { 1047impl Thing {
1054 fn new() -> Self<|> { Self { x: 0 } } 1048 fn new() -> Self$0 { Self { x: 0 } }
1055} 1049}
1056"#, 1050"#,
1057 expect![[r#" 1051 expect![[r#"
@@ -1070,7 +1064,7 @@ impl Thing {
1070 r#" 1064 r#"
1071enum Thing { A } 1065enum Thing { A }
1072impl Thing { 1066impl Thing {
1073 pub fn new() -> Self<|> { Thing::A } 1067 pub fn new() -> Self$0 { Thing::A }
1074} 1068}
1075"#, 1069"#,
1076 expect![[r#" 1070 expect![[r#"
@@ -1089,7 +1083,7 @@ impl Thing {
1089 r#" 1083 r#"
1090 enum Thing { A } 1084 enum Thing { A }
1091 impl Thing { 1085 impl Thing {
1092 pub fn thing(a: Self<|>) {} 1086 pub fn thing(a: Self$0) {}
1093 } 1087 }
1094 "#, 1088 "#,
1095 expect![[r#" 1089 expect![[r#"
@@ -1114,7 +1108,7 @@ fn x() {}
1114 1108
1115fn y() { 1109fn y() {
1116 let x = 0i32; 1110 let x = 0i32;
1117 x<|>; 1111 x$0;
1118} 1112}
1119"#, 1113"#,
1120 expect![[r#" 1114 expect![[r#"
@@ -1133,7 +1127,7 @@ fn y() {
1133 r#" 1127 r#"
1134macro_rules! foo { () => {} } 1128macro_rules! foo { () => {} }
1135 1129
1136fn f() { fo<|>o!(); } 1130fn f() { fo$0o!(); }
1137"#, 1131"#,
1138 expect![[r#" 1132 expect![[r#"
1139 *foo* 1133 *foo*
@@ -1152,7 +1146,7 @@ fn f() { fo<|>o!(); }
1152 #[test] 1146 #[test]
1153 fn test_hover_tuple_field() { 1147 fn test_hover_tuple_field() {
1154 check( 1148 check(
1155 r#"struct TS(String, i32<|>);"#, 1149 r#"struct TS(String, i32$0);"#,
1156 expect![[r#" 1150 expect![[r#"
1157 *i32* 1151 *i32*
1158 1152
@@ -1170,7 +1164,7 @@ fn f() { fo<|>o!(); }
1170macro_rules! id { ($($tt:tt)*) => { $($tt)* } } 1164macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1171fn foo() {} 1165fn foo() {}
1172id! { 1166id! {
1173 fn bar() { fo<|>o(); } 1167 fn bar() { fo$0o(); }
1174} 1168}
1175"#, 1169"#,
1176 expect![[r#" 1170 expect![[r#"
@@ -1192,7 +1186,7 @@ id! {
1192 check( 1186 check(
1193 r#" 1187 r#"
1194macro_rules! id { ($($tt:tt)*) => { $($tt)* } } 1188macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1195fn foo(bar:u32) { let a = id!(ba<|>r); } 1189fn foo(bar:u32) { let a = id!(ba$0r); }
1196"#, 1190"#,
1197 expect![[r#" 1191 expect![[r#"
1198 *bar* 1192 *bar*
@@ -1210,7 +1204,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); }
1210 r#" 1204 r#"
1211macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } 1205macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1212macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } 1206macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1213fn foo(bar:u32) { let a = id!(ba<|>r); } 1207fn foo(bar:u32) { let a = id!(ba$0r); }
1214"#, 1208"#,
1215 expect![[r#" 1209 expect![[r#"
1216 *bar* 1210 *bar*
@@ -1229,7 +1223,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); }
1229macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } 1223macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1230macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } 1224macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1231fn bar() -> u32 { 0 } 1225fn bar() -> u32 { 0 }
1232fn foo() { let a = id!([0u32, bar(<|>)] ); } 1226fn foo() { let a = id!([0u32, bar($0)] ); }
1233"#, 1227"#,
1234 expect![[r#" 1228 expect![[r#"
1235 *bar()* 1229 *bar()*
@@ -1247,7 +1241,7 @@ fn foo() { let a = id!([0u32, bar(<|>)] ); }
1247macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } } 1241macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
1248fn foo() { 1242fn foo() {
1249 let mastered_for_itunes = ""; 1243 let mastered_for_itunes = "";
1250 let _ = arr!("Tr<|>acks", &mastered_for_itunes); 1244 let _ = arr!("Tr$0acks", &mastered_for_itunes);
1251} 1245}
1252"#, 1246"#,
1253 expect![[r#" 1247 expect![[r#"
@@ -1268,7 +1262,7 @@ macro_rules! assert {}
1268 1262
1269fn bar() -> bool { true } 1263fn bar() -> bool { true }
1270fn foo() { 1264fn foo() {
1271 assert!(ba<|>r()); 1265 assert!(ba$0r());
1272} 1266}
1273"#, 1267"#,
1274 expect![[r#" 1268 expect![[r#"
@@ -1293,7 +1287,7 @@ fn foo() {
1293 macro_rules! format {} 1287 macro_rules! format {}
1294 1288
1295 fn foo() { 1289 fn foo() {
1296 format!("hel<|>lo {}", 0); 1290 format!("hel$0lo {}", 0);
1297 } 1291 }
1298 "#, 1292 "#,
1299 ); 1293 );
@@ -1306,7 +1300,7 @@ fn foo() {
1306/// <- `\u{3000}` here 1300/// <- `\u{3000}` here
1307fn foo() { } 1301fn foo() { }
1308 1302
1309fn bar() { fo<|>o(); } 1303fn bar() { fo$0o(); }
1310", 1304",
1311 expect![[r#" 1305 expect![[r#"
1312 *foo* 1306 *foo*
@@ -1329,7 +1323,7 @@ fn bar() { fo<|>o(); }
1329 #[test] 1323 #[test]
1330 fn test_hover_function_show_qualifiers() { 1324 fn test_hover_function_show_qualifiers() {
1331 check( 1325 check(
1332 r#"async fn foo<|>() {}"#, 1326 r#"async fn foo$0() {}"#,
1333 expect![[r#" 1327 expect![[r#"
1334 *foo* 1328 *foo*
1335 1329
@@ -1343,7 +1337,7 @@ fn bar() { fo<|>o(); }
1343 "#]], 1337 "#]],
1344 ); 1338 );
1345 check( 1339 check(
1346 r#"pub const unsafe fn foo<|>() {}"#, 1340 r#"pub const unsafe fn foo$0() {}"#,
1347 expect![[r#" 1341 expect![[r#"
1348 *foo* 1342 *foo*
1349 1343
@@ -1357,7 +1351,7 @@ fn bar() { fo<|>o(); }
1357 "#]], 1351 "#]],
1358 ); 1352 );
1359 check( 1353 check(
1360 r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#, 1354 r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#,
1361 expect![[r#" 1355 expect![[r#"
1362 *foo* 1356 *foo*
1363 1357
@@ -1375,7 +1369,7 @@ fn bar() { fo<|>o(); }
1375 #[test] 1369 #[test]
1376 fn test_hover_trait_show_qualifiers() { 1370 fn test_hover_trait_show_qualifiers() {
1377 check_actions( 1371 check_actions(
1378 r"unsafe trait foo<|>() {}", 1372 r"unsafe trait foo$0() {}",
1379 expect![[r#" 1373 expect![[r#"
1380 [ 1374 [
1381 Implementation( 1375 Implementation(
@@ -1396,7 +1390,7 @@ fn bar() { fo<|>o(); }
1396 check( 1390 check(
1397 r#" 1391 r#"
1398//- /main.rs crate:main deps:std 1392//- /main.rs crate:main deps:std
1399extern crate st<|>d; 1393extern crate st$0d;
1400//- /std/lib.rs crate:std 1394//- /std/lib.rs crate:std
1401//! Standard library for this test 1395//! Standard library for this test
1402//! 1396//!
@@ -1414,7 +1408,7 @@ extern crate st<|>d;
1414 check( 1408 check(
1415 r#" 1409 r#"
1416//- /main.rs crate:main deps:std 1410//- /main.rs crate:main deps:std
1417extern crate std as ab<|>c; 1411extern crate std as ab$0c;
1418//- /std/lib.rs crate:std 1412//- /std/lib.rs crate:std
1419//! Standard library for this test 1413//! Standard library for this test
1420//! 1414//!
@@ -1435,7 +1429,7 @@ extern crate std as ab<|>c;
1435 fn test_hover_mod_with_same_name_as_function() { 1429 fn test_hover_mod_with_same_name_as_function() {
1436 check( 1430 check(
1437 r#" 1431 r#"
1438use self::m<|>y::Bar; 1432use self::m$0y::Bar;
1439mod my { pub struct Bar; } 1433mod my { pub struct Bar; }
1440 1434
1441fn my() {} 1435fn my() {}
@@ -1461,7 +1455,7 @@ fn my() {}
1461/// bar docs 1455/// bar docs
1462struct Bar; 1456struct Bar;
1463 1457
1464fn foo() { let bar = Ba<|>r; } 1458fn foo() { let bar = Ba$0r; }
1465"#, 1459"#,
1466 expect![[r#" 1460 expect![[r#"
1467 *Bar* 1461 *Bar*
@@ -1488,7 +1482,7 @@ fn foo() { let bar = Ba<|>r; }
1488#[doc = "bar docs"] 1482#[doc = "bar docs"]
1489struct Bar; 1483struct Bar;
1490 1484
1491fn foo() { let bar = Ba<|>r; } 1485fn foo() { let bar = Ba$0r; }
1492"#, 1486"#,
1493 expect![[r#" 1487 expect![[r#"
1494 *Bar* 1488 *Bar*
@@ -1517,7 +1511,7 @@ fn foo() { let bar = Ba<|>r; }
1517#[doc = "bar docs 2"] 1511#[doc = "bar docs 2"]
1518struct Bar; 1512struct Bar;
1519 1513
1520fn foo() { let bar = Ba<|>r; } 1514fn foo() { let bar = Ba$0r; }
1521"#, 1515"#,
1522 expect![[r#" 1516 expect![[r#"
1523 *Bar* 1517 *Bar*
@@ -1545,7 +1539,7 @@ fn foo() { let bar = Ba<|>r; }
1545 r#" 1539 r#"
1546pub struct Foo; 1540pub struct Foo;
1547/// [Foo](struct.Foo.html) 1541/// [Foo](struct.Foo.html)
1548pub struct B<|>ar 1542pub struct B$0ar
1549"#, 1543"#,
1550 expect![[r#" 1544 expect![[r#"
1551 *Bar* 1545 *Bar*
@@ -1571,7 +1565,7 @@ pub struct B<|>ar
1571 r#" 1565 r#"
1572pub struct Foo; 1566pub struct Foo;
1573/// [struct Foo](struct.Foo.html) 1567/// [struct Foo](struct.Foo.html)
1574pub struct B<|>ar 1568pub struct B$0ar
1575"#, 1569"#,
1576 expect![[r#" 1570 expect![[r#"
1577 *Bar* 1571 *Bar*
@@ -1599,7 +1593,7 @@ pub struct B<|>ar
1599pub struct Foo; 1593pub struct Foo;
1600pub struct Bar { 1594pub struct Bar {
1601 /// [Foo](struct.Foo.html) 1595 /// [Foo](struct.Foo.html)
1602 fie<|>ld: () 1596 fie$0ld: ()
1603} 1597}
1604"#, 1598"#,
1605 expect![[r#" 1599 expect![[r#"
@@ -1628,7 +1622,7 @@ pub mod foo {
1628 pub struct Foo; 1622 pub struct Foo;
1629} 1623}
1630/// [Foo](foo::Foo) 1624/// [Foo](foo::Foo)
1631pub struct B<|>ar 1625pub struct B$0ar
1632"#, 1626"#,
1633 expect![[r#" 1627 expect![[r#"
1634 *Bar* 1628 *Bar*
@@ -1658,7 +1652,7 @@ pub mod foo {
1658 pub struct Foo; 1652 pub struct Foo;
1659} 1653}
1660/// [Foo](foo::Foo) 1654/// [Foo](foo::Foo)
1661pub struct B<|>ar 1655pub struct B$0ar
1662"#, 1656"#,
1663 expect![[r#" 1657 expect![[r#"
1664 *Bar* 1658 *Bar*
@@ -1684,7 +1678,7 @@ pub struct B<|>ar
1684 r#" 1678 r#"
1685pub struct Foo; 1679pub struct Foo;
1686/// [Foo] 1680/// [Foo]
1687pub struct B<|>ar 1681pub struct B$0ar
1688"#, 1682"#,
1689 expect![[r#" 1683 expect![[r#"
1690 *Bar* 1684 *Bar*
@@ -1710,7 +1704,7 @@ pub struct B<|>ar
1710 r#" 1704 r#"
1711pub struct Foo; 1705pub struct Foo;
1712/// [`Foo`] 1706/// [`Foo`]
1713pub struct B<|>ar 1707pub struct B$0ar
1714"#, 1708"#,
1715 expect![[r#" 1709 expect![[r#"
1716 *Bar* 1710 *Bar*
@@ -1737,7 +1731,7 @@ pub struct B<|>ar
1737pub struct Foo; 1731pub struct Foo;
1738fn Foo() {} 1732fn Foo() {}
1739/// [Foo()] 1733/// [Foo()]
1740pub struct B<|>ar 1734pub struct B$0ar
1741"#, 1735"#,
1742 expect![[r#" 1736 expect![[r#"
1743 *Bar* 1737 *Bar*
@@ -1763,7 +1757,7 @@ pub struct B<|>ar
1763 r#" 1757 r#"
1764pub struct Foo; 1758pub struct Foo;
1765/// [`struct Foo`] 1759/// [`struct Foo`]
1766pub struct B<|>ar 1760pub struct B$0ar
1767"#, 1761"#,
1768 expect![[r#" 1762 expect![[r#"
1769 *Bar* 1763 *Bar*
@@ -1789,7 +1783,7 @@ pub struct B<|>ar
1789 r#" 1783 r#"
1790pub struct Foo; 1784pub struct Foo;
1791/// [`struct@Foo`] 1785/// [`struct@Foo`]
1792pub struct B<|>ar 1786pub struct B$0ar
1793"#, 1787"#,
1794 expect![[r#" 1788 expect![[r#"
1795 *Bar* 1789 *Bar*
@@ -1817,7 +1811,7 @@ pub struct Foo;
1817/// [my Foo][foo] 1811/// [my Foo][foo]
1818/// 1812///
1819/// [foo]: Foo 1813/// [foo]: Foo
1820pub struct B<|>ar 1814pub struct B$0ar
1821"#, 1815"#,
1822 expect![[r#" 1816 expect![[r#"
1823 *Bar* 1817 *Bar*
@@ -1843,7 +1837,7 @@ pub struct B<|>ar
1843 r#" 1837 r#"
1844pub struct Foo; 1838pub struct Foo;
1845/// [external](https://www.google.com) 1839/// [external](https://www.google.com)
1846pub struct B<|>ar 1840pub struct B$0ar
1847"#, 1841"#,
1848 expect![[r#" 1842 expect![[r#"
1849 *Bar* 1843 *Bar*
@@ -1870,7 +1864,7 @@ pub struct B<|>ar
1870 r#" 1864 r#"
1871pub struct Foo; 1865pub struct Foo;
1872/// [baz](Baz) 1866/// [baz](Baz)
1873pub struct B<|>ar 1867pub struct B$0ar
1874"#, 1868"#,
1875 expect![[r#" 1869 expect![[r#"
1876 *Bar* 1870 *Bar*
@@ -1896,7 +1890,7 @@ pub struct B<|>ar
1896 r#" 1890 r#"
1897enum E { 1891enum E {
1898 /// [E] 1892 /// [E]
1899 V<|> { field: i32 } 1893 V$0 { field: i32 }
1900} 1894}
1901"#, 1895"#,
1902 expect![[r#" 1896 expect![[r#"
@@ -1923,7 +1917,7 @@ enum E {
1923 r#" 1917 r#"
1924struct S { 1918struct S {
1925 /// [`S`] 1919 /// [`S`]
1926 field<|>: i32 1920 field$0: i32
1927} 1921}
1928"#, 1922"#,
1929 expect![[r#" 1923 expect![[r#"
@@ -1951,16 +1945,16 @@ struct S {
1951/// Test cases: 1945/// Test cases:
1952/// case 1. bare URL: https://www.example.com/ 1946/// case 1. bare URL: https://www.example.com/
1953/// case 2. inline URL with title: [example](https://www.example.com/) 1947/// case 2. inline URL with title: [example](https://www.example.com/)
1954/// case 3. code refrence: [`Result`] 1948/// case 3. code reference: [`Result`]
1955/// case 4. code refrence but miss footnote: [`String`] 1949/// case 4. code reference but miss footnote: [`String`]
1956/// case 5. autolink: <http://www.example.com/> 1950/// case 5. autolink: <http://www.example.com/>
1957/// case 6. email address: <[email protected]> 1951/// case 6. email address: <[email protected]>
1958/// case 7. refrence: [example][example] 1952/// case 7. reference: [example][example]
1959/// case 8. collapsed link: [example][] 1953/// case 8. collapsed link: [example][]
1960/// case 9. shortcut link: [example] 1954/// case 9. shortcut link: [example]
1961/// case 10. inline without URL: [example]() 1955/// case 10. inline without URL: [example]()
1962/// case 11. refrence: [foo][foo] 1956/// case 11. reference: [foo][foo]
1963/// case 12. refrence: [foo][bar] 1957/// case 12. reference: [foo][bar]
1964/// case 13. collapsed link: [foo][] 1958/// case 13. collapsed link: [foo][]
1965/// case 14. shortcut link: [foo] 1959/// case 14. shortcut link: [foo]
1966/// case 15. inline without URL: [foo]() 1960/// case 15. inline without URL: [foo]()
@@ -1969,7 +1963,7 @@ struct S {
1969/// 1963///
1970/// [`Result`]: ../../std/result/enum.Result.html 1964/// [`Result`]: ../../std/result/enum.Result.html
1971/// [^example]: https://www.example.com/ 1965/// [^example]: https://www.example.com/
1972pub fn fo<|>o() {} 1966pub fn fo$0o() {}
1973"#, 1967"#,
1974 expect![[r#" 1968 expect![[r#"
1975 *foo* 1969 *foo*
@@ -1987,16 +1981,16 @@ pub fn fo<|>o() {}
1987 Test cases: 1981 Test cases:
1988 case 1. bare URL: https://www.example.com/ 1982 case 1. bare URL: https://www.example.com/
1989 case 2. inline URL with title: [example](https://www.example.com/) 1983 case 2. inline URL with title: [example](https://www.example.com/)
1990 case 3. code refrence: `Result` 1984 case 3. code reference: `Result`
1991 case 4. code refrence but miss footnote: `String` 1985 case 4. code reference but miss footnote: `String`
1992 case 5. autolink: http://www.example.com/ 1986 case 5. autolink: http://www.example.com/
1993 case 6. email address: [email protected] 1987 case 6. email address: [email protected]
1994 case 7. refrence: example 1988 case 7. reference: example
1995 case 8. collapsed link: example 1989 case 8. collapsed link: example
1996 case 9. shortcut link: example 1990 case 9. shortcut link: example
1997 case 10. inline without URL: example 1991 case 10. inline without URL: example
1998 case 11. refrence: foo 1992 case 11. reference: foo
1999 case 12. refrence: foo 1993 case 12. reference: foo
2000 case 13. collapsed link: foo 1994 case 13. collapsed link: foo
2001 case 14. shortcut link: foo 1995 case 14. shortcut link: foo
2002 case 15. inline without URL: foo 1996 case 15. inline without URL: foo
@@ -2026,7 +2020,7 @@ macro_rules! bar {
2026 2020
2027bar!(); 2021bar!();
2028 2022
2029fn foo() { let bar = Bar; bar.fo<|>o(); } 2023fn foo() { let bar = Bar; bar.fo$0o(); }
2030"#, 2024"#,
2031 expect![[r#" 2025 expect![[r#"
2032 *foo* 2026 *foo*
@@ -2064,7 +2058,7 @@ macro_rules! bar {
2064 2058
2065bar!(); 2059bar!();
2066 2060
2067fn foo() { let bar = Bar; bar.fo<|>o(); } 2061fn foo() { let bar = Bar; bar.fo$0o(); }
2068"#, 2062"#,
2069 expect![[r#" 2063 expect![[r#"
2070 *foo* 2064 *foo*
@@ -2087,7 +2081,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2087 #[test] 2081 #[test]
2088 fn test_hover_trait_has_impl_action() { 2082 fn test_hover_trait_has_impl_action() {
2089 check_actions( 2083 check_actions(
2090 r#"trait foo<|>() {}"#, 2084 r#"trait foo$0() {}"#,
2091 expect![[r#" 2085 expect![[r#"
2092 [ 2086 [
2093 Implementation( 2087 Implementation(
@@ -2106,7 +2100,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2106 #[test] 2100 #[test]
2107 fn test_hover_struct_has_impl_action() { 2101 fn test_hover_struct_has_impl_action() {
2108 check_actions( 2102 check_actions(
2109 r"struct foo<|>() {}", 2103 r"struct foo$0() {}",
2110 expect![[r#" 2104 expect![[r#"
2111 [ 2105 [
2112 Implementation( 2106 Implementation(
@@ -2125,7 +2119,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2125 #[test] 2119 #[test]
2126 fn test_hover_union_has_impl_action() { 2120 fn test_hover_union_has_impl_action() {
2127 check_actions( 2121 check_actions(
2128 r#"union foo<|>() {}"#, 2122 r#"union foo$0() {}"#,
2129 expect![[r#" 2123 expect![[r#"
2130 [ 2124 [
2131 Implementation( 2125 Implementation(
@@ -2144,7 +2138,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2144 #[test] 2138 #[test]
2145 fn test_hover_enum_has_impl_action() { 2139 fn test_hover_enum_has_impl_action() {
2146 check_actions( 2140 check_actions(
2147 r"enum foo<|>() { A, B }", 2141 r"enum foo$0() { A, B }",
2148 expect![[r#" 2142 expect![[r#"
2149 [ 2143 [
2150 Implementation( 2144 Implementation(
@@ -2163,7 +2157,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2163 #[test] 2157 #[test]
2164 fn test_hover_self_has_impl_action() { 2158 fn test_hover_self_has_impl_action() {
2165 check_actions( 2159 check_actions(
2166 r#"struct foo where Self<|>:;"#, 2160 r#"struct foo where Self$0:;"#,
2167 expect![[r#" 2161 expect![[r#"
2168 [ 2162 [
2169 Implementation( 2163 Implementation(
@@ -2184,7 +2178,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2184 check_actions( 2178 check_actions(
2185 r#" 2179 r#"
2186#[test] 2180#[test]
2187fn foo_<|>test() {} 2181fn foo_$0test() {}
2188"#, 2182"#,
2189 expect![[r#" 2183 expect![[r#"
2190 [ 2184 [
@@ -2219,7 +2213,7 @@ fn foo_<|>test() {}
2219 fn test_hover_test_mod_has_action() { 2213 fn test_hover_test_mod_has_action() {
2220 check_actions( 2214 check_actions(
2221 r#" 2215 r#"
2222mod tests<|> { 2216mod tests$0 {
2223 #[test] 2217 #[test]
2224 fn foo_test() {} 2218 fn foo_test() {}
2225} 2219}
@@ -2254,7 +2248,7 @@ mod tests<|> {
2254 r#" 2248 r#"
2255struct S{ f1: u32 } 2249struct S{ f1: u32 }
2256 2250
2257fn main() { let s<|>t = S{ f1:0 }; } 2251fn main() { let s$0t = S{ f1:0 }; }
2258 "#, 2252 "#,
2259 expect![[r#" 2253 expect![[r#"
2260 [ 2254 [
@@ -2287,7 +2281,7 @@ fn main() { let s<|>t = S{ f1:0 }; }
2287struct Arg(u32); 2281struct Arg(u32);
2288struct S<T>{ f1: T } 2282struct S<T>{ f1: T }
2289 2283
2290fn main() { let s<|>t = S{ f1:Arg(0) }; } 2284fn main() { let s$0t = S{ f1:Arg(0) }; }
2291"#, 2285"#,
2292 expect![[r#" 2286 expect![[r#"
2293 [ 2287 [
@@ -2333,7 +2327,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; }
2333struct Arg(u32); 2327struct Arg(u32);
2334struct S<T>{ f1: T } 2328struct S<T>{ f1: T }
2335 2329
2336fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } 2330fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
2337 "#, 2331 "#,
2338 expect![[r#" 2332 expect![[r#"
2339 [ 2333 [
@@ -2382,7 +2376,7 @@ mod M {
2382 pub struct C(u32); 2376 pub struct C(u32);
2383} 2377}
2384 2378
2385fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } 2379fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
2386"#, 2380"#,
2387 expect![[r#" 2381 expect![[r#"
2388 [ 2382 [
@@ -2441,7 +2435,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
2441trait Foo {} 2435trait Foo {}
2442fn foo() -> impl Foo {} 2436fn foo() -> impl Foo {}
2443 2437
2444fn main() { let s<|>t = foo(); } 2438fn main() { let s$0t = foo(); }
2445"#, 2439"#,
2446 expect![[r#" 2440 expect![[r#"
2447 [ 2441 [
@@ -2475,7 +2469,7 @@ trait Foo<T> {}
2475struct S; 2469struct S;
2476fn foo() -> impl Foo<S> {} 2470fn foo() -> impl Foo<S> {}
2477 2471
2478fn main() { let s<|>t = foo(); } 2472fn main() { let s$0t = foo(); }
2479"#, 2473"#,
2480 expect![[r#" 2474 expect![[r#"
2481 [ 2475 [
@@ -2522,7 +2516,7 @@ trait Foo {}
2522trait Bar {} 2516trait Bar {}
2523fn foo() -> impl Foo + Bar {} 2517fn foo() -> impl Foo + Bar {}
2524 2518
2525fn main() { let s<|>t = foo(); } 2519fn main() { let s$0t = foo(); }
2526 "#, 2520 "#,
2527 expect![[r#" 2521 expect![[r#"
2528 [ 2522 [
@@ -2572,7 +2566,7 @@ struct S2 {}
2572 2566
2573fn foo() -> impl Foo<S1> + Bar<S2> {} 2567fn foo() -> impl Foo<S1> + Bar<S2> {}
2574 2568
2575fn main() { let s<|>t = foo(); } 2569fn main() { let s$0t = foo(); }
2576"#, 2570"#,
2577 expect![[r#" 2571 expect![[r#"
2578 [ 2572 [
@@ -2642,7 +2636,7 @@ fn main() { let s<|>t = foo(); }
2642 check_actions( 2636 check_actions(
2643 r#" 2637 r#"
2644trait Foo {} 2638trait Foo {}
2645fn foo(ar<|>g: &impl Foo) {} 2639fn foo(ar$0g: &impl Foo) {}
2646"#, 2640"#,
2647 expect![[r#" 2641 expect![[r#"
2648 [ 2642 [
@@ -2676,7 +2670,7 @@ trait Foo {}
2676trait Bar<T> {} 2670trait Bar<T> {}
2677struct S{} 2671struct S{}
2678 2672
2679fn foo(ar<|>g: &impl Foo + Bar<S>) {} 2673fn foo(ar$0g: &impl Foo + Bar<S>) {}
2680"#, 2674"#,
2681 expect![[r#" 2675 expect![[r#"
2682 [ 2676 [
@@ -2734,7 +2728,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2734 r#" 2728 r#"
2735struct S; 2729struct S;
2736fn foo() { 2730fn foo() {
2737 let fo<|>o = async { S }; 2731 let fo$0o = async { S };
2738} 2732}
2739 2733
2740#[prelude_import] use future::*; 2734#[prelude_import] use future::*;
@@ -2786,7 +2780,7 @@ mod future {
2786 r#" 2780 r#"
2787trait Foo<T> {} 2781trait Foo<T> {}
2788struct S {} 2782struct S {}
2789fn foo(ar<|>g: &impl Foo<S>) {} 2783fn foo(ar$0g: &impl Foo<S>) {}
2790"#, 2784"#,
2791 expect![[r#" 2785 expect![[r#"
2792 [ 2786 [
@@ -2836,7 +2830,7 @@ impl Foo for S {}
2836struct B<T>{} 2830struct B<T>{}
2837fn foo() -> B<dyn Foo> {} 2831fn foo() -> B<dyn Foo> {}
2838 2832
2839fn main() { let s<|>t = foo(); } 2833fn main() { let s$0t = foo(); }
2840"#, 2834"#,
2841 expect![[r#" 2835 expect![[r#"
2842 [ 2836 [
@@ -2880,7 +2874,7 @@ fn main() { let s<|>t = foo(); }
2880 check_actions( 2874 check_actions(
2881 r#" 2875 r#"
2882trait Foo {} 2876trait Foo {}
2883fn foo(ar<|>g: &dyn Foo) {} 2877fn foo(ar$0g: &dyn Foo) {}
2884"#, 2878"#,
2885 expect![[r#" 2879 expect![[r#"
2886 [ 2880 [
@@ -2912,7 +2906,7 @@ fn foo(ar<|>g: &dyn Foo) {}
2912 r#" 2906 r#"
2913trait Foo<T> {} 2907trait Foo<T> {}
2914struct S {} 2908struct S {}
2915fn foo(ar<|>g: &dyn Foo<S>) {} 2909fn foo(ar$0g: &dyn Foo<S>) {}
2916"#, 2910"#,
2917 expect![[r#" 2911 expect![[r#"
2918 [ 2912 [
@@ -2960,7 +2954,7 @@ trait DynTrait<T> {}
2960struct B<T> {} 2954struct B<T> {}
2961struct S {} 2955struct S {}
2962 2956
2963fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} 2957fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2964 "#, 2958 "#,
2965 expect![[r#" 2959 expect![[r#"
2966 [ 2960 [
@@ -3041,7 +3035,7 @@ impl Foo for S { type Item = Bar; }
3041 3035
3042fn test() -> impl Foo { S {} } 3036fn test() -> impl Foo { S {} }
3043 3037
3044fn main() { let s<|>t = test().get(); } 3038fn main() { let s$0t = test().get(); }
3045"#, 3039"#,
3046 expect![[r#" 3040 expect![[r#"
3047 [ 3041 [
@@ -3074,7 +3068,7 @@ fn main() { let s<|>t = test().get(); }
3074struct Bar; 3068struct Bar;
3075struct Foo<const BAR: Bar>; 3069struct Foo<const BAR: Bar>;
3076 3070
3077impl<const BAR: Bar> Foo<BAR<|>> {} 3071impl<const BAR: Bar> Foo<BAR$0> {}
3078"#, 3072"#,
3079 expect![[r#" 3073 expect![[r#"
3080 [ 3074 [
@@ -3106,7 +3100,7 @@ impl<const BAR: Bar> Foo<BAR<|>> {}
3106 r#" 3100 r#"
3107trait Foo {} 3101trait Foo {}
3108 3102
3109fn foo<T: Foo>(t: T<|>){} 3103fn foo<T: Foo>(t: T$0){}
3110"#, 3104"#,
3111 expect![[r#" 3105 expect![[r#"
3112 [ 3106 [
@@ -3133,6 +3127,39 @@ fn foo<T: Foo>(t: T<|>){}
3133 } 3127 }
3134 3128
3135 #[test] 3129 #[test]
3130 fn test_hover_self_has_go_to_type() {
3131 check_actions(
3132 r#"
3133struct Foo;
3134impl Foo {
3135 fn foo(&self$0) {}
3136}
3137"#,
3138 expect![[r#"
3139 [
3140 GoToType(
3141 [
3142 HoverGotoTypeData {
3143 mod_path: "test::Foo",
3144 nav: NavigationTarget {
3145 file_id: FileId(
3146 0,
3147 ),
3148 full_range: 0..11,
3149 focus_range: 7..10,
3150 name: "Foo",
3151 kind: Struct,
3152 description: "struct Foo",
3153 },
3154 },
3155 ],
3156 ),
3157 ]
3158 "#]],
3159 );
3160 }
3161
3162 #[test]
3136 fn hover_displays_normalized_crate_names() { 3163 fn hover_displays_normalized_crate_names() {
3137 check( 3164 check(
3138 r#" 3165 r#"
@@ -3146,7 +3173,7 @@ pub mod wrapper {
3146} 3173}
3147 3174
3148//- /main.rs crate:main deps:name-with-dashes 3175//- /main.rs crate:main deps:name-with-dashes
3149fn main() { let foo_test = name_with_dashes::wrapper::Thing::new<|>(); } 3176fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
3150"#, 3177"#,
3151 expect![[r#" 3178 expect![[r#"
3152 *new* 3179 *new*
@@ -3172,7 +3199,7 @@ struct S {
3172 3199
3173fn main() { 3200fn main() {
3174 let s = S { f: 0 }; 3201 let s = S { f: 0 };
3175 let S { f<|> } = &s; 3202 let S { f$0 } = &s;
3176} 3203}
3177"#, 3204"#,
3178 expect![[r#" 3205 expect![[r#"
@@ -3191,11 +3218,12 @@ fn main() {
3191 r#" 3218 r#"
3192struct Foo {} 3219struct Foo {}
3193impl Foo { 3220impl Foo {
3194 fn bar(&sel<|>f) {} 3221 fn bar(&sel$0f) {}
3195} 3222}
3196"#, 3223"#,
3197 expect![[r#" 3224 expect![[r#"
3198 *&self* 3225 *self*
3226
3199 ```rust 3227 ```rust
3200 &Foo 3228 &Foo
3201 ``` 3229 ```
@@ -3210,11 +3238,12 @@ impl Foo {
3210struct Arc<T>(T); 3238struct Arc<T>(T);
3211struct Foo {} 3239struct Foo {}
3212impl Foo { 3240impl Foo {
3213 fn bar(sel<|>f: Arc<Foo>) {} 3241 fn bar(sel$0f: Arc<Foo>) {}
3214} 3242}
3215"#, 3243"#,
3216 expect![[r#" 3244 expect![[r#"
3217 *self: Arc<Foo>* 3245 *self*
3246
3218 ```rust 3247 ```rust
3219 Arc<Foo> 3248 Arc<Foo>
3220 ``` 3249 ```
@@ -3227,7 +3256,7 @@ impl Foo {
3227 check( 3256 check(
3228 r#" 3257 r#"
3229/// Be quick; 3258/// Be quick;
3230mod Foo<|> { 3259mod Foo$0 {
3231 //! time is mana 3260 //! time is mana
3232 3261
3233 /// This comment belongs to the function 3262 /// This comment belongs to the function
@@ -3258,7 +3287,7 @@ mod Foo<|> {
3258 check( 3287 check(
3259 r#" 3288 r#"
3260#[doc = "Be quick;"] 3289#[doc = "Be quick;"]
3261mod Foo<|> { 3290mod Foo$0 {
3262 #![doc = "time is mana"] 3291 #![doc = "time is mana"]
3263 3292
3264 #[doc = "This comment belongs to the function"] 3293 #[doc = "This comment belongs to the function"]
@@ -3289,7 +3318,7 @@ mod Foo<|> {
3289 check_hover_no_result( 3318 check_hover_no_result(
3290 r#" 3319 r#"
3291fn no_hover() { 3320fn no_hover() {
3292 // no<|>hover 3321 // no$0hover
3293} 3322}
3294"#, 3323"#,
3295 ); 3324 );
@@ -3300,7 +3329,7 @@ fn no_hover() {
3300 check( 3329 check(
3301 r#" 3330 r#"
3302fn foo() { 3331fn foo() {
3303 'label<|>: loop {} 3332 'label$0: loop {}
3304} 3333}
3305"#, 3334"#,
3306 expect![[r#" 3335 expect![[r#"
@@ -3316,7 +3345,7 @@ fn foo() {
3316 #[test] 3345 #[test]
3317 fn hover_lifetime() { 3346 fn hover_lifetime() {
3318 check( 3347 check(
3319 r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#, 3348 r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#,
3320 expect![[r#" 3349 expect![[r#"
3321 *'lifetime* 3350 *'lifetime*
3322 3351
@@ -3335,7 +3364,7 @@ struct Foo<T>(T);
3335trait Copy {} 3364trait Copy {}
3336trait Clone {} 3365trait Clone {}
3337trait Sized {} 3366trait Sized {}
3338impl<T: Copy + Clone> Foo<T<|>> where T: Sized {} 3367impl<T: Copy + Clone> Foo<T$0> where T: Sized {}
3339"#, 3368"#,
3340 expect![[r#" 3369 expect![[r#"
3341 *T* 3370 *T*
@@ -3348,7 +3377,7 @@ impl<T: Copy + Clone> Foo<T<|>> where T: Sized {}
3348 check( 3377 check(
3349 r#" 3378 r#"
3350struct Foo<T>(T); 3379struct Foo<T>(T);
3351impl<T> Foo<T<|>> {} 3380impl<T> Foo<T$0> {}
3352"#, 3381"#,
3353 expect![[r#" 3382 expect![[r#"
3354 *T* 3383 *T*
@@ -3362,7 +3391,7 @@ impl<T> Foo<T<|>> {}
3362 check( 3391 check(
3363 r#" 3392 r#"
3364struct Foo<T>(T); 3393struct Foo<T>(T);
3365impl<T: 'static> Foo<T<|>> {} 3394impl<T: 'static> Foo<T$0> {}
3366"#, 3395"#,
3367 expect![[r#" 3396 expect![[r#"
3368 *T* 3397 *T*
@@ -3379,7 +3408,7 @@ impl<T: 'static> Foo<T<|>> {}
3379 check( 3408 check(
3380 r#" 3409 r#"
3381struct Foo<const LEN: usize>; 3410struct Foo<const LEN: usize>;
3382impl<const LEN: usize> Foo<LEN<|>> {} 3411impl<const LEN: usize> Foo<LEN$0> {}
3383"#, 3412"#,
3384 expect![[r#" 3413 expect![[r#"
3385 *LEN* 3414 *LEN*
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index fe60abfc8..a2039fcc7 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -353,9 +353,25 @@ fn is_argument_similar_to_param_name(
353 } 353 }
354 match get_string_representation(argument) { 354 match get_string_representation(argument) {
355 None => false, 355 None => false,
356 Some(repr) => { 356 Some(argument_string) => {
357 let argument_string = repr.trim_start_matches('_'); 357 let num_leading_underscores =
358 argument_string.starts_with(param_name) || argument_string.ends_with(param_name) 358 argument_string.bytes().take_while(|&c| c == b'_').count();
359
360 // Does the argument name begin with the parameter name? Ignore leading underscores.
361 let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
362 let starts_with_pattern = param_name.bytes().all(
363 |expected| matches!(arg_bytes.next(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
364 );
365
366 if starts_with_pattern {
367 return true;
368 }
369
370 // Does the argument name end with the parameter name?
371 let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
372 param_name.bytes().rev().all(
373 |expected| matches!(arg_bytes.next_back(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
374 )
359 } 375 }
360 } 376 }
361} 377}
@@ -901,6 +917,9 @@ fn main() {
901 twiddle(true); 917 twiddle(true);
902 doo(true); 918 doo(true);
903 919
920 const TWIDDLE_UPPERCASE: bool = true;
921 twiddle(TWIDDLE_UPPERCASE);
922
904 let mut param_begin: Param = Param {}; 923 let mut param_begin: Param = Param {};
905 different_order(&param_begin); 924 different_order(&param_begin);
906 different_order(&mut param_begin); 925 different_order(&mut param_begin);
@@ -1382,4 +1401,41 @@ fn main() {
1382"#, 1401"#,
1383 ) 1402 )
1384 } 1403 }
1404
1405 #[test]
1406 fn fn_hints() {
1407 check(
1408 r#"
1409trait Sized {}
1410
1411fn foo() -> impl Fn() { loop {} }
1412fn foo1() -> impl Fn(f64) { loop {} }
1413fn foo2() -> impl Fn(f64, f64) { loop {} }
1414fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
1415fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
1416fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
1417fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
1418fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
1419
1420fn main() {
1421 let foo = foo();
1422 // ^^^ impl Fn()
1423 let foo = foo1();
1424 // ^^^ impl Fn(f64)
1425 let foo = foo2();
1426 // ^^^ impl Fn(f64, f64)
1427 let foo = foo3();
1428 // ^^^ impl Fn(f64, f64) -> u32
1429 let foo = foo4();
1430 // ^^^ &dyn Fn(f64, f64) -> u32
1431 let foo = foo5();
1432 // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
1433 let foo = foo6();
1434 // ^^^ impl Fn(f64, f64) -> u32 + Sized
1435 let foo = foo7();
1436 // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
1437}
1438"#,
1439 )
1440 }
1385} 1441}
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index b5a6f66fd..981467c8d 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -1,7 +1,7 @@
1use assists::utils::extract_trivial_expression; 1use assists::utils::extract_trivial_expression;
2use itertools::Itertools; 2use itertools::Itertools;
3use syntax::{ 3use syntax::{
4 algo::{find_covering_element, non_trivia_sibling}, 4 algo::non_trivia_sibling,
5 ast::{self, AstNode, AstToken}, 5 ast::{self, AstNode, AstToken},
6 Direction, NodeOrToken, SourceFile, 6 Direction, NodeOrToken, SourceFile,
7 SyntaxKind::{self, USE_TREE, WHITESPACE}, 7 SyntaxKind::{self, USE_TREE, WHITESPACE},
@@ -31,7 +31,7 @@ pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
31 range 31 range
32 }; 32 };
33 33
34 let node = match find_covering_element(file.syntax(), range) { 34 let node = match file.syntax().covering_element(range) {
35 NodeOrToken::Node(node) => node, 35 NodeOrToken::Node(node) => node,
36 NodeOrToken::Token(token) => token.parent(), 36 NodeOrToken::Token(token) => token.parent(),
37 }; 37 };
@@ -104,7 +104,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
104 // Special case that turns something like: 104 // Special case that turns something like:
105 // 105 //
106 // ``` 106 // ```
107 // my_function({<|> 107 // my_function({$0
108 // <some-expr> 108 // <some-expr>
109 // }) 109 // })
110 // ``` 110 // ```
@@ -116,7 +116,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
116 // ditto for 116 // ditto for
117 // 117 //
118 // ``` 118 // ```
119 // use foo::{<|> 119 // use foo::{$0
120 // bar 120 // bar
121 // }; 121 // };
122 // ``` 122 // ```
@@ -198,8 +198,8 @@ mod tests {
198 198
199 use super::*; 199 use super::*;
200 200
201 fn check_join_lines(before: &str, after: &str) { 201 fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) {
202 let (before_cursor_pos, before) = extract_offset(before); 202 let (before_cursor_pos, before) = extract_offset(ra_fixture_before);
203 let file = SourceFile::parse(&before).ok().unwrap(); 203 let file = SourceFile::parse(&before).ok().unwrap();
204 204
205 let range = TextRange::empty(before_cursor_pos); 205 let range = TextRange::empty(before_cursor_pos);
@@ -214,7 +214,7 @@ mod tests {
214 .apply_to_offset(before_cursor_pos) 214 .apply_to_offset(before_cursor_pos)
215 .expect("cursor position is affected by the edit"); 215 .expect("cursor position is affected by the edit");
216 let actual = add_cursor(&actual, actual_cursor_pos); 216 let actual = add_cursor(&actual, actual_cursor_pos);
217 assert_eq_text!(after, &actual); 217 assert_eq_text!(ra_fixture_after, &actual);
218 } 218 }
219 219
220 #[test] 220 #[test]
@@ -222,13 +222,13 @@ mod tests {
222 check_join_lines( 222 check_join_lines(
223 r" 223 r"
224fn foo() { 224fn foo() {
225 <|>foo(1, 225 $0foo(1,
226 ) 226 )
227} 227}
228", 228",
229 r" 229 r"
230fn foo() { 230fn foo() {
231 <|>foo(1) 231 $0foo(1)
232} 232}
233", 233",
234 ); 234 );
@@ -239,14 +239,14 @@ fn foo() {
239 check_join_lines( 239 check_join_lines(
240 r" 240 r"
241pub fn reparse(&self, edit: &AtomTextEdit) -> File { 241pub fn reparse(&self, edit: &AtomTextEdit) -> File {
242 <|>self.incremental_reparse(edit).unwrap_or_else(|| { 242 $0self.incremental_reparse(edit).unwrap_or_else(|| {
243 self.full_reparse(edit) 243 self.full_reparse(edit)
244 }) 244 })
245} 245}
246", 246",
247 r" 247 r"
248pub fn reparse(&self, edit: &AtomTextEdit) -> File { 248pub fn reparse(&self, edit: &AtomTextEdit) -> File {
249 <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) 249 $0self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
250} 250}
251", 251",
252 ); 252 );
@@ -257,13 +257,13 @@ pub fn reparse(&self, edit: &AtomTextEdit) -> File {
257 check_join_lines( 257 check_join_lines(
258 r" 258 r"
259fn foo() { 259fn foo() {
260 foo(<|>{ 260 foo($0{
261 92 261 92
262 }) 262 })
263}", 263}",
264 r" 264 r"
265fn foo() { 265fn foo() {
266 foo(<|>92) 266 foo($092)
267}", 267}",
268 ); 268 );
269 } 269 }
@@ -274,7 +274,7 @@ fn foo() {
274 fn foo() { 274 fn foo() {
275 loop { 275 loop {
276 match x { 276 match x {
277 92 => <|>{ 277 92 => $0{
278 continue; 278 continue;
279 } 279 }
280 } 280 }
@@ -285,7 +285,7 @@ fn foo() {
285 fn foo() { 285 fn foo() {
286 loop { 286 loop {
287 match x { 287 match x {
288 92 => <|>continue, 288 92 => $0continue,
289 } 289 }
290 } 290 }
291 } 291 }
@@ -299,7 +299,7 @@ fn foo() {
299 r" 299 r"
300fn foo(e: Result<U, V>) { 300fn foo(e: Result<U, V>) {
301 match e { 301 match e {
302 Ok(u) => <|>{ 302 Ok(u) => $0{
303 u.foo() 303 u.foo()
304 } 304 }
305 Err(v) => v, 305 Err(v) => v,
@@ -308,7 +308,7 @@ fn foo(e: Result<U, V>) {
308 r" 308 r"
309fn foo(e: Result<U, V>) { 309fn foo(e: Result<U, V>) {
310 match e { 310 match e {
311 Ok(u) => <|>u.foo(), 311 Ok(u) => $0u.foo(),
312 Err(v) => v, 312 Err(v) => v,
313 } 313 }
314}", 314}",
@@ -321,7 +321,7 @@ fn foo(e: Result<U, V>) {
321 r" 321 r"
322fn foo() { 322fn foo() {
323 match ty { 323 match ty {
324 <|> Some(ty) => { 324 $0 Some(ty) => {
325 match ty { 325 match ty {
326 _ => false, 326 _ => false,
327 } 327 }
@@ -333,7 +333,7 @@ fn foo() {
333 r" 333 r"
334fn foo() { 334fn foo() {
335 match ty { 335 match ty {
336 <|> Some(ty) => match ty { 336 $0 Some(ty) => match ty {
337 _ => false, 337 _ => false,
338 }, 338 },
339 _ => true, 339 _ => true,
@@ -350,7 +350,7 @@ fn foo() {
350 r" 350 r"
351fn foo(e: Result<U, V>) { 351fn foo(e: Result<U, V>) {
352 match e { 352 match e {
353 Ok(u) => <|>{ 353 Ok(u) => $0{
354 u.foo() 354 u.foo()
355 }, 355 },
356 Err(v) => v, 356 Err(v) => v,
@@ -359,7 +359,7 @@ fn foo(e: Result<U, V>) {
359 r" 359 r"
360fn foo(e: Result<U, V>) { 360fn foo(e: Result<U, V>) {
361 match e { 361 match e {
362 Ok(u) => <|>u.foo(), 362 Ok(u) => $0u.foo(),
363 Err(v) => v, 363 Err(v) => v,
364 } 364 }
365}", 365}",
@@ -370,7 +370,7 @@ fn foo(e: Result<U, V>) {
370 r" 370 r"
371fn foo(e: Result<U, V>) { 371fn foo(e: Result<U, V>) {
372 match e { 372 match e {
373 Ok(u) => <|>{ 373 Ok(u) => $0{
374 u.foo() 374 u.foo()
375 } , 375 } ,
376 Err(v) => v, 376 Err(v) => v,
@@ -379,7 +379,7 @@ fn foo(e: Result<U, V>) {
379 r" 379 r"
380fn foo(e: Result<U, V>) { 380fn foo(e: Result<U, V>) {
381 match e { 381 match e {
382 Ok(u) => <|>u.foo() , 382 Ok(u) => $0u.foo() ,
383 Err(v) => v, 383 Err(v) => v,
384 } 384 }
385}", 385}",
@@ -390,7 +390,7 @@ fn foo(e: Result<U, V>) {
390 r" 390 r"
391fn foo(e: Result<U, V>) { 391fn foo(e: Result<U, V>) {
392 match e { 392 match e {
393 Ok(u) => <|>{ 393 Ok(u) => $0{
394 u.foo() 394 u.foo()
395 } 395 }
396 , 396 ,
@@ -400,7 +400,7 @@ fn foo(e: Result<U, V>) {
400 r" 400 r"
401fn foo(e: Result<U, V>) { 401fn foo(e: Result<U, V>) {
402 match e { 402 match e {
403 Ok(u) => <|>u.foo() 403 Ok(u) => $0u.foo()
404 , 404 ,
405 Err(v) => v, 405 Err(v) => v,
406 } 406 }
@@ -414,13 +414,13 @@ fn foo(e: Result<U, V>) {
414 check_join_lines( 414 check_join_lines(
415 r" 415 r"
416fn foo() { 416fn foo() {
417 let x = (<|>{ 417 let x = ($0{
418 4 418 4
419 },); 419 },);
420}", 420}",
421 r" 421 r"
422fn foo() { 422fn foo() {
423 let x = (<|>4,); 423 let x = ($04,);
424}", 424}",
425 ); 425 );
426 426
@@ -428,13 +428,13 @@ fn foo() {
428 check_join_lines( 428 check_join_lines(
429 r" 429 r"
430fn foo() { 430fn foo() {
431 let x = (<|>{ 431 let x = ($0{
432 4 432 4
433 } ,); 433 } ,);
434}", 434}",
435 r" 435 r"
436fn foo() { 436fn foo() {
437 let x = (<|>4 ,); 437 let x = ($04 ,);
438}", 438}",
439 ); 439 );
440 440
@@ -442,14 +442,14 @@ fn foo() {
442 check_join_lines( 442 check_join_lines(
443 r" 443 r"
444fn foo() { 444fn foo() {
445 let x = (<|>{ 445 let x = ($0{
446 4 446 4
447 } 447 }
448 ,); 448 ,);
449}", 449}",
450 r" 450 r"
451fn foo() { 451fn foo() {
452 let x = (<|>4 452 let x = ($04
453 ,); 453 ,);
454}", 454}",
455 ); 455 );
@@ -460,11 +460,11 @@ fn foo() {
460 // No space after the '{' 460 // No space after the '{'
461 check_join_lines( 461 check_join_lines(
462 r" 462 r"
463<|>use syntax::{ 463$0use syntax::{
464 TextSize, TextRange, 464 TextSize, TextRange,
465};", 465};",
466 r" 466 r"
467<|>use syntax::{TextSize, TextRange, 467$0use syntax::{TextSize, TextRange,
468};", 468};",
469 ); 469 );
470 } 470 }
@@ -475,11 +475,11 @@ fn foo() {
475 check_join_lines( 475 check_join_lines(
476 r" 476 r"
477use syntax::{ 477use syntax::{
478<|> TextSize, TextRange 478$0 TextSize, TextRange
479};", 479};",
480 r" 480 r"
481use syntax::{ 481use syntax::{
482<|> TextSize, TextRange};", 482$0 TextSize, TextRange};",
483 ); 483 );
484 } 484 }
485 485
@@ -489,11 +489,11 @@ use syntax::{
489 check_join_lines( 489 check_join_lines(
490 r" 490 r"
491use syntax::{ 491use syntax::{
492<|> TextSize, TextRange, 492$0 TextSize, TextRange,
493};", 493};",
494 r" 494 r"
495use syntax::{ 495use syntax::{
496<|> TextSize, TextRange};", 496$0 TextSize, TextRange};",
497 ); 497 );
498 } 498 }
499 499
@@ -502,14 +502,14 @@ use syntax::{
502 check_join_lines( 502 check_join_lines(
503 r" 503 r"
504use syntax::{ 504use syntax::{
505 algo::<|>{ 505 algo::$0{
506 find_token_at_offset, 506 find_token_at_offset,
507 }, 507 },
508 ast, 508 ast,
509};", 509};",
510 r" 510 r"
511use syntax::{ 511use syntax::{
512 algo::<|>find_token_at_offset, 512 algo::$0find_token_at_offset,
513 ast, 513 ast,
514};", 514};",
515 ); 515 );
@@ -520,13 +520,13 @@ use syntax::{
520 check_join_lines( 520 check_join_lines(
521 r" 521 r"
522fn foo() { 522fn foo() {
523 // Hello<|> 523 // Hello$0
524 // world! 524 // world!
525} 525}
526", 526",
527 r" 527 r"
528fn foo() { 528fn foo() {
529 // Hello<|> world! 529 // Hello$0 world!
530} 530}
531", 531",
532 ); 532 );
@@ -537,13 +537,13 @@ fn foo() {
537 check_join_lines( 537 check_join_lines(
538 r" 538 r"
539fn foo() { 539fn foo() {
540 /// Hello<|> 540 /// Hello$0
541 /// world! 541 /// world!
542} 542}
543", 543",
544 r" 544 r"
545fn foo() { 545fn foo() {
546 /// Hello<|> world! 546 /// Hello$0 world!
547} 547}
548", 548",
549 ); 549 );
@@ -554,13 +554,13 @@ fn foo() {
554 check_join_lines( 554 check_join_lines(
555 r" 555 r"
556fn foo() { 556fn foo() {
557 //! Hello<|> 557 //! Hello$0
558 //! world! 558 //! world!
559} 559}
560", 560",
561 r" 561 r"
562fn foo() { 562fn foo() {
563 //! Hello<|> world! 563 //! Hello$0 world!
564} 564}
565", 565",
566 ); 566 );
@@ -571,13 +571,13 @@ fn foo() {
571 check_join_lines( 571 check_join_lines(
572 r" 572 r"
573fn foo() { 573fn foo() {
574 // Hello<|> 574 // Hello$0
575 /* world! */ 575 /* world! */
576} 576}
577", 577",
578 r" 578 r"
579fn foo() { 579fn foo() {
580 // Hello<|> world! */ 580 // Hello$0 world! */
581} 581}
582", 582",
583 ); 583 );
@@ -588,7 +588,7 @@ fn foo() {
588 check_join_lines( 588 check_join_lines(
589 r" 589 r"
590fn foo() { 590fn foo() {
591 // The<|> 591 // The$0
592 /* quick 592 /* quick
593 brown 593 brown
594 fox! */ 594 fox! */
@@ -596,7 +596,7 @@ fn foo() {
596", 596",
597 r" 597 r"
598fn foo() { 598fn foo() {
599 // The<|> quick 599 // The$0 quick
600 brown 600 brown
601 fox! */ 601 fox! */
602} 602}
@@ -604,8 +604,8 @@ fn foo() {
604 ); 604 );
605 } 605 }
606 606
607 fn check_join_lines_sel(before: &str, after: &str) { 607 fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) {
608 let (sel, before) = extract_range(before); 608 let (sel, before) = extract_range(ra_fixture_before);
609 let parse = SourceFile::parse(&before); 609 let parse = SourceFile::parse(&before);
610 let result = join_lines(&parse.tree(), sel); 610 let result = join_lines(&parse.tree(), sel);
611 let actual = { 611 let actual = {
@@ -613,7 +613,7 @@ fn foo() {
613 result.apply(&mut actual); 613 result.apply(&mut actual);
614 actual 614 actual
615 }; 615 };
616 assert_eq_text!(after, &actual); 616 assert_eq_text!(ra_fixture_after, &actual);
617 } 617 }
618 618
619 #[test] 619 #[test]
@@ -621,10 +621,10 @@ fn foo() {
621 check_join_lines_sel( 621 check_join_lines_sel(
622 r" 622 r"
623fn foo() { 623fn foo() {
624 <|>foo(1, 624 $0foo(1,
625 2, 625 2,
626 3, 626 3,
627 <|>) 627 $0)
628} 628}
629 ", 629 ",
630 r" 630 r"
@@ -639,9 +639,9 @@ fn foo() {
639 fn test_join_lines_selection_struct() { 639 fn test_join_lines_selection_struct() {
640 check_join_lines_sel( 640 check_join_lines_sel(
641 r" 641 r"
642struct Foo <|>{ 642struct Foo $0{
643 f: u32, 643 f: u32,
644}<|> 644}$0
645 ", 645 ",
646 r" 646 r"
647struct Foo { f: u32 } 647struct Foo { f: u32 }
@@ -654,9 +654,9 @@ struct Foo { f: u32 }
654 check_join_lines_sel( 654 check_join_lines_sel(
655 r" 655 r"
656fn foo() { 656fn foo() {
657 join(<|>type_params.type_params() 657 join($0type_params.type_params()
658 .filter_map(|it| it.name()) 658 .filter_map(|it| it.name())
659 .map(|it| it.text())<|>) 659 .map(|it| it.text())$0)
660}", 660}",
661 r" 661 r"
662fn foo() { 662fn foo() {
@@ -671,9 +671,9 @@ fn foo() {
671 r" 671 r"
672pub fn handle_find_matching_brace() { 672pub fn handle_find_matching_brace() {
673 params.offsets 673 params.offsets
674 .map(|offset| <|>{ 674 .map(|offset| $0{
675 world.analysis().matching_brace(&file, offset).unwrap_or(offset) 675 world.analysis().matching_brace(&file, offset).unwrap_or(offset)
676 }<|>) 676 }$0)
677 .collect(); 677 .collect();
678}", 678}",
679 r" 679 r"
@@ -691,7 +691,7 @@ pub fn handle_find_matching_brace() {
691 r" 691 r"
692fn main() { 692fn main() {
693 let _ = { 693 let _ = {
694 // <|>foo 694 // $0foo
695 // bar 695 // bar
696 92 696 92
697 }; 697 };
@@ -700,7 +700,7 @@ fn main() {
700 r" 700 r"
701fn main() { 701fn main() {
702 let _ = { 702 let _ = {
703 // <|>foo bar 703 // $0foo bar
704 92 704 92
705 }; 705 };
706} 706}
@@ -712,12 +712,12 @@ fn main() {
712 fn join_lines_mandatory_blocks_block() { 712 fn join_lines_mandatory_blocks_block() {
713 check_join_lines( 713 check_join_lines(
714 r" 714 r"
715<|>fn foo() { 715$0fn foo() {
716 92 716 92
717} 717}
718 ", 718 ",
719 r" 719 r"
720<|>fn foo() { 92 720$0fn foo() { 92
721} 721}
722 ", 722 ",
723 ); 723 );
@@ -725,14 +725,14 @@ fn main() {
725 check_join_lines( 725 check_join_lines(
726 r" 726 r"
727fn foo() { 727fn foo() {
728 <|>if true { 728 $0if true {
729 92 729 92
730 } 730 }
731} 731}
732 ", 732 ",
733 r" 733 r"
734fn foo() { 734fn foo() {
735 <|>if true { 92 735 $0if true { 92
736 } 736 }
737} 737}
738 ", 738 ",
@@ -741,14 +741,14 @@ fn foo() {
741 check_join_lines( 741 check_join_lines(
742 r" 742 r"
743fn foo() { 743fn foo() {
744 <|>loop { 744 $0loop {
745 92 745 92
746 } 746 }
747} 747}
748 ", 748 ",
749 r" 749 r"
750fn foo() { 750fn foo() {
751 <|>loop { 92 751 $0loop { 92
752 } 752 }
753} 753}
754 ", 754 ",
@@ -757,14 +757,14 @@ fn foo() {
757 check_join_lines( 757 check_join_lines(
758 r" 758 r"
759fn foo() { 759fn foo() {
760 <|>unsafe { 760 $0unsafe {
761 92 761 92
762 } 762 }
763} 763}
764 ", 764 ",
765 r" 765 r"
766fn foo() { 766fn foo() {
767 <|>unsafe { 92 767 $0unsafe { 92
768 } 768 }
769} 769}
770 ", 770 ",
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index cea2a13c8..6c94c26b5 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -76,29 +76,26 @@ pub use crate::{
76 references::{rename::RenameError, Declaration, ReferenceSearchResult}, 76 references::{rename::RenameError, Declaration, ReferenceSearchResult},
77 runnables::{Runnable, RunnableKind, TestId}, 77 runnables::{Runnable, RunnableKind, TestId},
78 syntax_highlighting::{ 78 syntax_highlighting::{
79 tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag}, 79 tags::{Highlight, HlMod, HlMods, HlPunct, HlTag},
80 HighlightedRange, 80 HlRange,
81 }, 81 },
82}; 82};
83pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig}; 83pub use assists::{Assist, AssistConfig, AssistId, AssistKind};
84pub use completion::{ 84pub use completion::{
85 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, 85 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit,
86 InsertTextFormat, 86 InsertTextFormat,
87}; 87};
88pub use hir::{Documentation, Semantics}; 88pub use hir::{Documentation, Semantics};
89pub use ide_db::base_db::{
90 Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
91 SourceRootId,
92};
93pub use ide_db::{ 89pub use ide_db::{
90 base_db::{
91 Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange,
92 SourceRoot, SourceRootId,
93 },
94 call_info::CallInfo, 94 call_info::CallInfo,
95 search::{Reference, ReferenceAccess, ReferenceKind},
96};
97pub use ide_db::{
98 label::Label, 95 label::Label,
99 line_index::{LineCol, LineIndex}, 96 line_index::{LineCol, LineIndex},
100 search::SearchScope, 97 search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope},
101 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 98 source_change::{FileSystemEdit, SourceChange},
102 symbol_index::Query, 99 symbol_index::Query,
103 RootDatabase, 100 RootDatabase,
104}; 101};
@@ -449,12 +446,12 @@ impl Analysis {
449 } 446 }
450 447
451 /// Computes syntax highlighting for the given file 448 /// Computes syntax highlighting for the given file
452 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { 449 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HlRange>> {
453 self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) 450 self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false))
454 } 451 }
455 452
456 /// Computes syntax highlighting for the given file range. 453 /// Computes syntax highlighting for the given file range.
457 pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HighlightedRange>> { 454 pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HlRange>> {
458 self.with_db(|db| { 455 self.with_db(|db| {
459 syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) 456 syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false)
460 }) 457 })
@@ -553,7 +550,7 @@ impl Analysis {
553 let rule: ssr::SsrRule = query.parse()?; 550 let rule: ssr::SsrRule = query.parse()?;
554 let mut match_finder = ssr::MatchFinder::in_context(db, resolve_context, selections); 551 let mut match_finder = ssr::MatchFinder::in_context(db, resolve_context, selections);
555 match_finder.add_rule(rule)?; 552 match_finder.add_rule(rule)?;
556 let edits = if parse_only { Vec::new() } else { match_finder.edits() }; 553 let edits = if parse_only { Default::default() } else { match_finder.edits() };
557 Ok(SourceChange::from(edits)) 554 Ok(SourceChange::from(edits))
558 }) 555 })
559 } 556 }
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs
index d70248afe..1bfa1439d 100644
--- a/crates/ide/src/matching_brace.rs
+++ b/crates/ide/src/matching_brace.rs
@@ -58,15 +58,15 @@ mod tests {
58 assert_eq_text!(after, &actual); 58 assert_eq_text!(after, &actual);
59 } 59 }
60 60
61 do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); 61 do_check("struct Foo { a: i32, }$0", "struct Foo $0{ a: i32, }");
62 do_check("fn main() { |x: i32|<|> x * 2;}", "fn main() { <|>|x: i32| x * 2;}"); 62 do_check("fn main() { |x: i32|$0 x * 2;}", "fn main() { $0|x: i32| x * 2;}");
63 do_check("fn main() { <|>|x: i32| x * 2;}", "fn main() { |x: i32<|>| x * 2;}"); 63 do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}");
64 64
65 { 65 {
66 mark::check!(pipes_not_braces); 66 mark::check!(pipes_not_braces);
67 do_check( 67 do_check(
68 "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", 68 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }",
69 "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", 69 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }",
70 ); 70 );
71 } 71 }
72 } 72 }
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index be344a09b..d343638fb 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -74,7 +74,7 @@ mod tests {
74 //- /lib.rs 74 //- /lib.rs
75 mod foo; 75 mod foo;
76 //- /foo.rs 76 //- /foo.rs
77 <|>// empty 77 $0// empty
78 ", 78 ",
79 ); 79 );
80 let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); 80 let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
@@ -90,7 +90,7 @@ mod tests {
90 mod foo; 90 mod foo;
91 91
92 //- /foo.rs 92 //- /foo.rs
93 mod <|>bar; 93 mod $0bar;
94 94
95 //- /foo/bar.rs 95 //- /foo/bar.rs
96 // empty 96 // empty
@@ -107,7 +107,7 @@ mod tests {
107 //- /lib.rs 107 //- /lib.rs
108 mod foo { 108 mod foo {
109 mod bar { 109 mod bar {
110 mod baz { <|> } 110 mod baz { $0 }
111 } 111 }
112 } 112 }
113 ", 113 ",
@@ -123,7 +123,7 @@ mod tests {
123//- /main.rs 123//- /main.rs
124mod foo; 124mod foo;
125//- /foo.rs 125//- /foo.rs
126<|> 126$0
127"#, 127"#,
128 ); 128 );
129 assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); 129 assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index fa58fc319..df9c31aef 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -3,7 +3,7 @@
3//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we 3//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we
4//! try to resolve the direct tree parent of this element, otherwise we 4//! try to resolve the direct tree parent of this element, otherwise we
5//! already have a definition and just need to get its HIR together with 5//! already have a definition and just need to get its HIR together with
6//! some information that is needed for futher steps of searching. 6//! some information that is needed for further steps of searching.
7//! After that, we collect files that might contain references and look 7//! After that, we collect files that might contain references and look
8//! for text occurrences of the identifier. If there's an `ast::NameRef` 8//! for text occurrences of the identifier. If there's an `ast::NameRef`
9//! at the index that the match starts at and its tree parent is 9//! at the index that the match starts at and its tree parent is
@@ -11,25 +11,26 @@
11 11
12pub(crate) mod rename; 12pub(crate) mod rename;
13 13
14use either::Either;
14use hir::Semantics; 15use hir::Semantics;
15use ide_db::{ 16use ide_db::{
17 base_db::FileId,
16 defs::{Definition, NameClass, NameRefClass}, 18 defs::{Definition, NameClass, NameRefClass},
17 search::Reference, 19 search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult},
18 search::{ReferenceAccess, ReferenceKind, SearchScope},
19 RootDatabase, 20 RootDatabase,
20}; 21};
21use syntax::{ 22use syntax::{
22 algo::find_node_at_offset, 23 algo::find_node_at_offset,
23 ast::{self, NameOwner}, 24 ast::{self, NameOwner},
24 match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset, 25 AstNode, SyntaxNode, TextRange, TokenAtOffset, T,
25}; 26};
26 27
27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; 28use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
28 29
29#[derive(Debug, Clone)] 30#[derive(Debug, Clone)]
30pub struct ReferenceSearchResult { 31pub struct ReferenceSearchResult {
31 declaration: Declaration, 32 declaration: Declaration,
32 references: Vec<Reference>, 33 references: UsageSearchResult,
33} 34}
34 35
35#[derive(Debug, Clone)] 36#[derive(Debug, Clone)]
@@ -48,10 +49,21 @@ impl ReferenceSearchResult {
48 &self.declaration.nav 49 &self.declaration.nav
49 } 50 }
50 51
51 pub fn references(&self) -> &[Reference] { 52 pub fn references(&self) -> &UsageSearchResult {
52 &self.references 53 &self.references
53 } 54 }
54 55
56 pub fn references_with_declaration(mut self) -> UsageSearchResult {
57 let decl_ref = FileReference {
58 range: self.declaration.nav.focus_or_full_range(),
59 kind: self.declaration.kind,
60 access: self.declaration.access,
61 };
62 let file_id = self.declaration.nav.file_id;
63 self.references.references.entry(file_id).or_default().push(decl_ref);
64 self.references
65 }
66
55 /// Total number of references 67 /// Total number of references
56 /// At least 1 since all valid references should 68 /// At least 1 since all valid references should
57 /// Have a declaration 69 /// Have a declaration
@@ -63,21 +75,11 @@ impl ReferenceSearchResult {
63// allow turning ReferenceSearchResult into an iterator 75// allow turning ReferenceSearchResult into an iterator
64// over References 76// over References
65impl IntoIterator for ReferenceSearchResult { 77impl IntoIterator for ReferenceSearchResult {
66 type Item = Reference; 78 type Item = (FileId, Vec<FileReference>);
67 type IntoIter = std::vec::IntoIter<Reference>; 79 type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>;
68 80
69 fn into_iter(mut self) -> Self::IntoIter { 81 fn into_iter(self) -> Self::IntoIter {
70 let mut v = Vec::with_capacity(self.len()); 82 self.references_with_declaration().into_iter()
71 v.push(Reference {
72 file_range: FileRange {
73 file_id: self.declaration.nav.file_id,
74 range: self.declaration.nav.focus_or_full_range(),
75 },
76 kind: self.declaration.kind,
77 access: self.declaration.access,
78 });
79 v.append(&mut self.references);
80 v.into_iter()
81 } 83 }
82} 84}
83 85
@@ -89,10 +91,6 @@ pub(crate) fn find_all_refs(
89 let _p = profile::span("find_all_refs"); 91 let _p = profile::span("find_all_refs");
90 let syntax = sema.parse(position.file_id).syntax().clone(); 92 let syntax = sema.parse(position.file_id).syntax().clone();
91 93
92 if let Some(res) = try_find_self_references(&syntax, position) {
93 return Some(res);
94 }
95
96 let (opt_name, search_kind) = if let Some(name) = 94 let (opt_name, search_kind) = if let Some(name) =
97 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position) 95 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
98 { 96 {
@@ -109,34 +107,39 @@ pub(crate) fn find_all_refs(
109 107
110 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 108 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
111 109
112 let references = def 110 let mut usages = def.usages(sema).set_scope(search_scope).all();
113 .usages(sema) 111 usages
114 .set_scope(search_scope) 112 .references
115 .all() 113 .values_mut()
116 .into_iter() 114 .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind));
117 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 115 usages.references.retain(|_, it| !it.is_empty());
118 .collect();
119 116
120 let nav = def.try_to_nav(sema.db)?; 117 let nav = def.try_to_nav(sema.db)?;
121 let decl_range = nav.focus_or_full_range(); 118 let decl_range = nav.focus_or_full_range();
122 119
123 let mut kind = ReferenceKind::Other; 120 let mut kind = ReferenceKind::Other;
124 if let Definition::Local(local) = def { 121 if let Definition::Local(local) = def {
125 if let either::Either::Left(pat) = local.source(sema.db).value { 122 match local.source(sema.db).value {
126 if matches!( 123 Either::Left(pat) => {
127 pat.syntax().parent().and_then(ast::RecordPatField::cast), 124 if matches!(
128 Some(pat_field) if pat_field.name_ref().is_none() 125 pat.syntax().parent().and_then(ast::RecordPatField::cast),
129 ) { 126 Some(pat_field) if pat_field.name_ref().is_none()
130 kind = ReferenceKind::FieldShorthandForLocal; 127 ) {
128 kind = ReferenceKind::FieldShorthandForLocal;
129 }
131 } 130 }
131 Either::Right(_) => kind = ReferenceKind::SelfParam,
132 } 132 }
133 } else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) { 133 } else if matches!(
134 def,
135 Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
136 ) {
134 kind = ReferenceKind::Lifetime; 137 kind = ReferenceKind::Lifetime;
135 }; 138 };
136 139
137 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; 140 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) };
138 141
139 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 142 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages }))
140} 143}
141 144
142fn find_name( 145fn find_name(
@@ -200,7 +203,7 @@ fn get_struct_def_name_for_struct_literal_search(
200 position: FilePosition, 203 position: FilePosition,
201) -> Option<ast::Name> { 204) -> Option<ast::Name> {
202 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 205 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
203 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { 206 if right.kind() != T!['{'] && right.kind() != T!['('] {
204 return None; 207 return None;
205 } 208 }
206 if let Some(name) = 209 if let Some(name) =
@@ -227,7 +230,7 @@ fn get_enum_def_name_for_struct_literal_search(
227 position: FilePosition, 230 position: FilePosition,
228) -> Option<ast::Name> { 231) -> Option<ast::Name> {
229 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) { 232 if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
230 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { 233 if right.kind() != T!['{'] && right.kind() != T!['('] {
231 return None; 234 return None;
232 } 235 }
233 if let Some(name) = 236 if let Some(name) =
@@ -248,77 +251,6 @@ fn get_enum_def_name_for_struct_literal_search(
248 None 251 None
249} 252}
250 253
251fn try_find_self_references(
252 syntax: &SyntaxNode,
253 position: FilePosition,
254) -> Option<RangeInfo<ReferenceSearchResult>> {
255 let self_token =
256 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)?;
257 let parent = self_token.parent();
258 match_ast! {
259 match parent {
260 ast::SelfParam(it) => (),
261 ast::PathSegment(segment) => {
262 segment.self_token()?;
263 let path = segment.parent_path();
264 if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) {
265 return None;
266 }
267 },
268 _ => return None,
269 }
270 };
271 let function = parent.ancestors().find_map(ast::Fn::cast)?;
272 let self_param = function.param_list()?.self_param()?;
273 let param_self_token = self_param.self_token()?;
274
275 let declaration = Declaration {
276 nav: NavigationTarget {
277 file_id: position.file_id,
278 full_range: self_param.syntax().text_range(),
279 focus_range: Some(param_self_token.text_range()),
280 name: param_self_token.text().clone(),
281 kind: Some(SymbolKind::SelfParam),
282 container_name: None,
283 description: None,
284 docs: None,
285 },
286 kind: ReferenceKind::SelfKw,
287 access: Some(if self_param.mut_token().is_some() {
288 ReferenceAccess::Write
289 } else {
290 ReferenceAccess::Read
291 }),
292 };
293 let references = function
294 .body()
295 .map(|body| {
296 body.syntax()
297 .descendants()
298 .filter_map(ast::PathExpr::cast)
299 .filter_map(|expr| {
300 let path = expr.path()?;
301 if path.qualifier().is_none() {
302 path.segment()?.self_token()
303 } else {
304 None
305 }
306 })
307 .map(|token| Reference {
308 file_range: FileRange { file_id: position.file_id, range: token.text_range() },
309 kind: ReferenceKind::SelfKw,
310 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
311 })
312 .collect()
313 })
314 .unwrap_or_default();
315
316 Some(RangeInfo::new(
317 param_self_token.text_range(),
318 ReferenceSearchResult { declaration, references },
319 ))
320}
321
322#[cfg(test)] 254#[cfg(test)]
323mod tests { 255mod tests {
324 use expect_test::{expect, Expect}; 256 use expect_test::{expect, Expect};
@@ -331,7 +263,7 @@ mod tests {
331 fn test_struct_literal_after_space() { 263 fn test_struct_literal_after_space() {
332 check( 264 check(
333 r#" 265 r#"
334struct Foo <|>{ 266struct Foo $0{
335 a: i32, 267 a: i32,
336} 268}
337impl Foo { 269impl Foo {
@@ -354,7 +286,7 @@ fn main() {
354 fn test_struct_literal_before_space() { 286 fn test_struct_literal_before_space() {
355 check( 287 check(
356 r#" 288 r#"
357struct Foo<|> {} 289struct Foo$0 {}
358 fn main() { 290 fn main() {
359 let f: Foo; 291 let f: Foo;
360 f = Foo {}; 292 f = Foo {};
@@ -373,7 +305,7 @@ struct Foo<|> {}
373 fn test_struct_literal_with_generic_type() { 305 fn test_struct_literal_with_generic_type() {
374 check( 306 check(
375 r#" 307 r#"
376struct Foo<T> <|>{} 308struct Foo<T> $0{}
377 fn main() { 309 fn main() {
378 let f: Foo::<i32>; 310 let f: Foo::<i32>;
379 f = Foo {}; 311 f = Foo {};
@@ -391,7 +323,7 @@ struct Foo<T> <|>{}
391 fn test_struct_literal_for_tuple() { 323 fn test_struct_literal_for_tuple() {
392 check( 324 check(
393 r#" 325 r#"
394struct Foo<|>(i32); 326struct Foo$0(i32);
395 327
396fn main() { 328fn main() {
397 let f: Foo; 329 let f: Foo;
@@ -410,7 +342,7 @@ fn main() {
410 fn test_enum_after_space() { 342 fn test_enum_after_space() {
411 check( 343 check(
412 r#" 344 r#"
413enum Foo <|>{ 345enum Foo $0{
414 A, 346 A,
415 B, 347 B,
416} 348}
@@ -431,7 +363,7 @@ fn main() {
431 fn test_enum_before_space() { 363 fn test_enum_before_space() {
432 check( 364 check(
433 r#" 365 r#"
434enum Foo<|> { 366enum Foo$0 {
435 A, 367 A,
436 B, 368 B,
437} 369}
@@ -453,7 +385,7 @@ fn main() {
453 fn test_enum_with_generic_type() { 385 fn test_enum_with_generic_type() {
454 check( 386 check(
455 r#" 387 r#"
456enum Foo<T> <|>{ 388enum Foo<T> $0{
457 A(T), 389 A(T),
458 B, 390 B,
459} 391}
@@ -474,7 +406,7 @@ fn main() {
474 fn test_enum_for_tuple() { 406 fn test_enum_for_tuple() {
475 check( 407 check(
476 r#" 408 r#"
477enum Foo<|>{ 409enum Foo$0{
478 A(i8), 410 A(i8),
479 B(i8), 411 B(i8),
480} 412}
@@ -498,7 +430,7 @@ fn main() {
498fn main() { 430fn main() {
499 let mut i = 1; 431 let mut i = 1;
500 let j = 1; 432 let j = 1;
501 i = i<|> + j; 433 i = i$0 + j;
502 434
503 { 435 {
504 i = 0; 436 i = 0;
@@ -507,7 +439,7 @@ fn main() {
507 i = 5; 439 i = 5;
508}"#, 440}"#,
509 expect![[r#" 441 expect![[r#"
510 i Local FileId(0) 24..25 Other Write 442 i Local FileId(0) 20..25 24..25 Other Write
511 443
512 FileId(0) 50..51 Other Write 444 FileId(0) 50..51 Other Write
513 FileId(0) 54..55 Other Read 445 FileId(0) 54..55 Other Read
@@ -522,7 +454,7 @@ fn main() {
522 check( 454 check(
523 r#" 455 r#"
524fn foo() { 456fn foo() {
525 let spam<|> = 92; 457 let spam$0 = 92;
526 spam + spam 458 spam + spam
527} 459}
528fn bar() { 460fn bar() {
@@ -531,7 +463,7 @@ fn bar() {
531} 463}
532"#, 464"#,
533 expect![[r#" 465 expect![[r#"
534 spam Local FileId(0) 19..23 Other 466 spam Local FileId(0) 19..23 19..23 Other
535 467
536 FileId(0) 34..38 Other Read 468 FileId(0) 34..38 Other Read
537 FileId(0) 41..45 Other Read 469 FileId(0) 41..45 Other Read
@@ -543,10 +475,10 @@ fn bar() {
543 fn test_find_all_refs_for_param_inside() { 475 fn test_find_all_refs_for_param_inside() {
544 check( 476 check(
545 r#" 477 r#"
546fn foo(i : u32) -> u32 { i<|> } 478fn foo(i : u32) -> u32 { i$0 }
547"#, 479"#,
548 expect![[r#" 480 expect![[r#"
549 i ValueParam FileId(0) 7..8 Other 481 i ValueParam FileId(0) 7..8 7..8 Other
550 482
551 FileId(0) 25..26 Other Read 483 FileId(0) 25..26 Other Read
552 "#]], 484 "#]],
@@ -557,10 +489,10 @@ fn foo(i : u32) -> u32 { i<|> }
557 fn test_find_all_refs_for_fn_param() { 489 fn test_find_all_refs_for_fn_param() {
558 check( 490 check(
559 r#" 491 r#"
560fn foo(i<|> : u32) -> u32 { i } 492fn foo(i$0 : u32) -> u32 { i }
561"#, 493"#,
562 expect![[r#" 494 expect![[r#"
563 i ValueParam FileId(0) 7..8 Other 495 i ValueParam FileId(0) 7..8 7..8 Other
564 496
565 FileId(0) 25..26 Other Read 497 FileId(0) 25..26 Other Read
566 "#]], 498 "#]],
@@ -573,7 +505,7 @@ fn foo(i<|> : u32) -> u32 { i }
573 r#" 505 r#"
574//- /lib.rs 506//- /lib.rs
575struct Foo { 507struct Foo {
576 pub spam<|>: u32, 508 pub spam$0: u32,
577} 509}
578 510
579fn main(s: Foo) { 511fn main(s: Foo) {
@@ -594,7 +526,7 @@ fn main(s: Foo) {
594 r#" 526 r#"
595struct Foo; 527struct Foo;
596impl Foo { 528impl Foo {
597 fn f<|>(&self) { } 529 fn f$0(&self) { }
598} 530}
599"#, 531"#,
600 expect![[r#" 532 expect![[r#"
@@ -610,7 +542,7 @@ impl Foo {
610 r#" 542 r#"
611enum Foo { 543enum Foo {
612 A, 544 A,
613 B<|>, 545 B$0,
614 C, 546 C,
615} 547}
616"#, 548"#,
@@ -627,7 +559,7 @@ enum Foo {
627 r#" 559 r#"
628enum Foo { 560enum Foo {
629 A, 561 A,
630 B { field<|>: u8 }, 562 B { field$0: u8 },
631 C, 563 C,
632} 564}
633"#, 565"#,
@@ -669,7 +601,7 @@ pub struct Bar {
669} 601}
670 602
671fn f() { 603fn f() {
672 let i = foo::Foo<|> { n: 5 }; 604 let i = foo::Foo$0 { n: 5 };
673} 605}
674"#, 606"#,
675 expect![[r#" 607 expect![[r#"
@@ -689,7 +621,7 @@ fn f() {
689 check( 621 check(
690 r#" 622 r#"
691//- /lib.rs 623//- /lib.rs
692mod foo<|>; 624mod foo$0;
693 625
694use foo::Foo; 626use foo::Foo;
695 627
@@ -726,7 +658,7 @@ fn f() {
726} 658}
727 659
728//- /foo/some.rs 660//- /foo/some.rs
729pub(super) struct Foo<|> { 661pub(super) struct Foo$0 {
730 pub n: u32, 662 pub n: u32,
731} 663}
732"#, 664"#,
@@ -746,7 +678,7 @@ pub(super) struct Foo<|> {
746 mod foo; 678 mod foo;
747 mod bar; 679 mod bar;
748 680
749 pub fn quux<|>() {} 681 pub fn quux$0() {}
750 682
751 //- /foo.rs 683 //- /foo.rs
752 fn f() { super::quux(); } 684 fn f() { super::quux(); }
@@ -782,7 +714,7 @@ pub(super) struct Foo<|> {
782 check( 714 check(
783 r#" 715 r#"
784#[macro_export] 716#[macro_export]
785macro_rules! m1<|> { () => (()) } 717macro_rules! m1$0 { () => (()) }
786 718
787fn foo() { 719fn foo() {
788 m1(); 720 m1();
@@ -803,12 +735,12 @@ fn foo() {
803 check( 735 check(
804 r#" 736 r#"
805fn foo() { 737fn foo() {
806 let mut i<|> = 0; 738 let mut i$0 = 0;
807 i = i + 1; 739 i = i + 1;
808} 740}
809"#, 741"#,
810 expect![[r#" 742 expect![[r#"
811 i Local FileId(0) 23..24 Other Write 743 i Local FileId(0) 19..24 23..24 Other Write
812 744
813 FileId(0) 34..35 Other Write 745 FileId(0) 34..35 Other Write
814 FileId(0) 38..39 Other Read 746 FileId(0) 38..39 Other Read
@@ -826,7 +758,7 @@ struct S {
826 758
827fn foo() { 759fn foo() {
828 let mut s = S{f: 0}; 760 let mut s = S{f: 0};
829 s.f<|> = 0; 761 s.f$0 = 0;
830} 762}
831"#, 763"#,
832 expect![[r#" 764 expect![[r#"
@@ -843,12 +775,12 @@ fn foo() {
843 check( 775 check(
844 r#" 776 r#"
845fn foo() { 777fn foo() {
846 let i<|>; 778 let i$0;
847 i = 1; 779 i = 1;
848} 780}
849"#, 781"#,
850 expect![[r#" 782 expect![[r#"
851 i Local FileId(0) 19..20 Other 783 i Local FileId(0) 19..20 19..20 Other
852 784
853 FileId(0) 26..27 Other Write 785 FileId(0) 26..27 Other Write
854 "#]], 786 "#]],
@@ -863,7 +795,7 @@ mod foo {
863 pub struct Foo; 795 pub struct Foo;
864 796
865 impl Foo { 797 impl Foo {
866 pub fn new<|>() -> Foo { Foo } 798 pub fn new$0() -> Foo { Foo }
867 } 799 }
868} 800}
869 801
@@ -886,7 +818,7 @@ fn main() {
886//- /lib.rs 818//- /lib.rs
887mod foo { mod bar; } 819mod foo { mod bar; }
888 820
889fn f<|>() {} 821fn f$0() {}
890 822
891//- /foo/bar.rs 823//- /foo/bar.rs
892use crate::f; 824use crate::f;
@@ -907,7 +839,7 @@ fn g() { f(); }
907 check( 839 check(
908 r#" 840 r#"
909struct S { 841struct S {
910 field<|>: u8, 842 field$0: u8,
911} 843}
912 844
913fn f(s: S) { 845fn f(s: S) {
@@ -930,7 +862,7 @@ fn f(s: S) {
930 r#" 862 r#"
931enum En { 863enum En {
932 Variant { 864 Variant {
933 field<|>: u8, 865 field$0: u8,
934 } 866 }
935} 867}
936 868
@@ -955,7 +887,7 @@ fn f(e: En) {
955mod m { 887mod m {
956 pub enum En { 888 pub enum En {
957 Variant { 889 Variant {
958 field<|>: u8, 890 field$0: u8,
959 } 891 }
960 } 892 }
961} 893}
@@ -980,7 +912,7 @@ struct Foo { bar: i32 }
980 912
981impl Foo { 913impl Foo {
982 fn foo(self) { 914 fn foo(self) {
983 let x = self<|>.bar; 915 let x = self$0.bar;
984 if true { 916 if true {
985 let _ = match () { 917 let _ = match () {
986 () => self, 918 () => self,
@@ -990,10 +922,30 @@ impl Foo {
990} 922}
991"#, 923"#,
992 expect![[r#" 924 expect![[r#"
993 self SelfParam FileId(0) 47..51 47..51 SelfKw Read 925 self SelfParam FileId(0) 47..51 47..51 SelfParam
926
927 FileId(0) 71..75 Other Read
928 FileId(0) 152..156 Other Read
929 "#]],
930 );
931 }
932
933 #[test]
934 fn test_find_self_refs_decl() {
935 check(
936 r#"
937struct Foo { bar: i32 }
938
939impl Foo {
940 fn foo(self$0) {
941 self;
942 }
943}
944"#,
945 expect![[r#"
946 self SelfParam FileId(0) 47..51 47..51 SelfParam
994 947
995 FileId(0) 71..75 SelfKw Read 948 FileId(0) 63..67 Other Read
996 FileId(0) 152..156 SelfKw Read
997 "#]], 949 "#]],
998 ); 950 );
999 } 951 }
@@ -1016,12 +968,14 @@ impl Foo {
1016 actual += "\n\n"; 968 actual += "\n\n";
1017 } 969 }
1018 970
1019 for r in &refs.references { 971 for (file_id, references) in refs.references {
1020 format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); 972 for r in references {
1021 if let Some(access) = r.access { 973 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind);
1022 format_to!(actual, " {:?}", access); 974 if let Some(access) = r.access {
975 format_to!(actual, " {:?}", access);
976 }
977 actual += "\n";
1023 } 978 }
1024 actual += "\n";
1025 } 979 }
1026 expect.assert_eq(&actual) 980 expect.assert_eq(&actual)
1027 } 981 }
@@ -1032,7 +986,7 @@ impl Foo {
1032 r#" 986 r#"
1033trait Foo<'a> {} 987trait Foo<'a> {}
1034impl<'a> Foo<'a> for &'a () {} 988impl<'a> Foo<'a> for &'a () {}
1035fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> { 989fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
1036 fn bar<'a>(_: &'a ()) {} 990 fn bar<'a>(_: &'a ()) {}
1037 x 991 x
1038} 992}
@@ -1053,7 +1007,7 @@ fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> {
1053 fn test_find_lifetimes_type_alias() { 1007 fn test_find_lifetimes_type_alias() {
1054 check( 1008 check(
1055 r#" 1009 r#"
1056type Foo<'a, T> where T: 'a<|> = &'a T; 1010type Foo<'a, T> where T: 'a$0 = &'a T;
1057"#, 1011"#,
1058 expect![[r#" 1012 expect![[r#"
1059 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime 1013 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime
@@ -1072,7 +1026,7 @@ trait Foo<'a> {
1072 fn foo() -> &'a (); 1026 fn foo() -> &'a ();
1073} 1027}
1074impl<'a> Foo<'a> for &'a () { 1028impl<'a> Foo<'a> for &'a () {
1075 fn foo() -> &'a<|> () { 1029 fn foo() -> &'a$0 () {
1076 unimplemented!() 1030 unimplemented!()
1077 } 1031 }
1078} 1032}
@@ -1093,12 +1047,12 @@ impl<'a> Foo<'a> for &'a () {
1093 r#" 1047 r#"
1094macro_rules! foo {($i:ident) => {$i} } 1048macro_rules! foo {($i:ident) => {$i} }
1095fn main() { 1049fn main() {
1096 let a<|> = "test"; 1050 let a$0 = "test";
1097 foo!(a); 1051 foo!(a);
1098} 1052}
1099"#, 1053"#,
1100 expect![[r#" 1054 expect![[r#"
1101 a Local FileId(0) 59..60 Other 1055 a Local FileId(0) 59..60 59..60 Other
1102 1056
1103 FileId(0) 80..81 Other Read 1057 FileId(0) 80..81 Other Read
1104 "#]], 1058 "#]],
@@ -1112,11 +1066,11 @@ fn main() {
1112macro_rules! foo {($i:ident) => {$i} } 1066macro_rules! foo {($i:ident) => {$i} }
1113fn main() { 1067fn main() {
1114 let a = "test"; 1068 let a = "test";
1115 foo!(a<|>); 1069 foo!(a$0);
1116} 1070}
1117"#, 1071"#,
1118 expect![[r#" 1072 expect![[r#"
1119 a Local FileId(0) 59..60 Other 1073 a Local FileId(0) 59..60 59..60 Other
1120 1074
1121 FileId(0) 80..81 Other Read 1075 FileId(0) 80..81 Other Read
1122 "#]], 1076 "#]],
@@ -1130,7 +1084,7 @@ fn main() {
1130fn foo<'a>() -> &'a () { 1084fn foo<'a>() -> &'a () {
1131 'a: loop { 1085 'a: loop {
1132 'b: loop { 1086 'b: loop {
1133 continue 'a<|>; 1087 continue 'a$0;
1134 } 1088 }
1135 break 'a; 1089 break 'a;
1136 } 1090 }
@@ -1149,7 +1103,7 @@ fn foo<'a>() -> &'a () {
1149 fn test_find_const_param() { 1103 fn test_find_const_param() {
1150 check( 1104 check(
1151 r#" 1105 r#"
1152fn foo<const FOO<|>: usize>() -> usize { 1106fn foo<const FOO$0: usize>() -> usize {
1153 FOO 1107 FOO
1154} 1108}
1155"#, 1109"#,
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 854bf194e..4df189c98 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,29 +1,27 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use std::{ 2use std::fmt::{self, Display};
3 convert::TryInto,
4 error::Error,
5 fmt::{self, Display},
6};
7 3
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 4use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt};
10use ide_db::{ 5use ide_db::{
6 base_db::{AnchoredPathBuf, FileId, FileRange},
11 defs::{Definition, NameClass, NameRefClass}, 7 defs::{Definition, NameClass, NameRefClass},
8 search::FileReference,
12 RootDatabase, 9 RootDatabase,
13}; 10};
14use syntax::{ 11use syntax::{
15 algo::find_node_at_offset, 12 algo::find_node_at_offset,
16 ast::{self, NameOwner}, 13 ast::{self, NameOwner},
17 lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, 14 lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, T,
18}; 15};
19use test_utils::mark; 16use test_utils::mark;
20use text_edit::TextEdit; 17use text_edit::TextEdit;
21 18
22use crate::{ 19use crate::{
23 references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, 20 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange,
24 SourceChange, SourceFileEdit, TextRange, TextSize, 21 TextRange,
25}; 22};
26 23
24type RenameResult<T> = Result<T, RenameError>;
27#[derive(Debug)] 25#[derive(Debug)]
28pub struct RenameError(pub(crate) String); 26pub struct RenameError(pub(crate) String);
29 27
@@ -33,27 +31,27 @@ impl fmt::Display for RenameError {
33 } 31 }
34} 32}
35 33
36impl Error for RenameError {} 34macro_rules! format_err {
35 ($fmt:expr) => {RenameError(format!($fmt))};
36 ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))}
37}
38
39macro_rules! bail {
40 ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))}
41}
37 42
38pub(crate) fn prepare_rename( 43pub(crate) fn prepare_rename(
39 db: &RootDatabase, 44 db: &RootDatabase,
40 position: FilePosition, 45 position: FilePosition,
41) -> Result<RangeInfo<()>, RenameError> { 46) -> RenameResult<RangeInfo<()>> {
42 let sema = Semantics::new(db); 47 let sema = Semantics::new(db);
43 let source_file = sema.parse(position.file_id); 48 let source_file = sema.parse(position.file_id);
44 let syntax = source_file.syntax(); 49 let syntax = source_file.syntax();
45 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 50 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
46 rename_mod(&sema, position, module, "dummy") 51 rename_mod(&sema, position, module, "dummy")
47 } else if let Some(self_token) =
48 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
49 {
50 rename_self_to_param(&sema, position, self_token, "dummy")
51 } else { 52 } else {
52 let range = match find_all_refs(&sema, position, None) { 53 let RangeInfo { range, .. } = find_all_refs(&sema, position)?;
53 Some(RangeInfo { range, .. }) => range, 54 Ok(RangeInfo::new(range, SourceChange::default()))
54 None => return Err(RenameError("No references found at position".to_string())),
55 };
56 Ok(RangeInfo::new(range, SourceChange::from(vec![])))
57 } 55 }
58 .map(|info| RangeInfo::new(info.range, ())) 56 .map(|info| RangeInfo::new(info.range, ()))
59} 57}
@@ -62,7 +60,7 @@ pub(crate) fn rename(
62 db: &RootDatabase, 60 db: &RootDatabase,
63 position: FilePosition, 61 position: FilePosition,
64 new_name: &str, 62 new_name: &str,
65) -> Result<RangeInfo<SourceChange>, RenameError> { 63) -> RenameResult<RangeInfo<SourceChange>> {
66 let sema = Semantics::new(db); 64 let sema = Semantics::new(db);
67 rename_with_semantics(&sema, position, new_name) 65 rename_with_semantics(&sema, position, new_name)
68} 66}
@@ -71,42 +69,14 @@ pub(crate) fn rename_with_semantics(
71 sema: &Semantics<RootDatabase>, 69 sema: &Semantics<RootDatabase>,
72 position: FilePosition, 70 position: FilePosition,
73 new_name: &str, 71 new_name: &str,
74) -> Result<RangeInfo<SourceChange>, RenameError> { 72) -> RenameResult<RangeInfo<SourceChange>> {
75 let is_lifetime_name = match lex_single_syntax_kind(new_name) {
76 Some(res) => match res {
77 (SyntaxKind::IDENT, _) => false,
78 (SyntaxKind::UNDERSCORE, _) => false,
79 (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position),
80 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => true,
81 (SyntaxKind::LIFETIME_IDENT, _) => {
82 return Err(RenameError(format!(
83 "Invalid name `{0}`: Cannot rename lifetime to {0}",
84 new_name
85 )))
86 }
87 (_, Some(syntax_error)) => {
88 return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error)))
89 }
90 (_, None) => {
91 return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name)))
92 }
93 },
94 None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))),
95 };
96
97 let source_file = sema.parse(position.file_id); 73 let source_file = sema.parse(position.file_id);
98 let syntax = source_file.syntax(); 74 let syntax = source_file.syntax();
99 // this is here to prevent lifetime renames from happening on modules and self 75
100 if is_lifetime_name { 76 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
101 rename_reference(&sema, position, new_name, is_lifetime_name)
102 } else if let Some(module) = find_module_at_offset(&sema, position, syntax) {
103 rename_mod(&sema, position, module, new_name) 77 rename_mod(&sema, position, module, new_name)
104 } else if let Some(self_token) =
105 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
106 {
107 rename_self_to_param(&sema, position, self_token, new_name)
108 } else { 78 } else {
109 rename_reference(&sema, position, new_name, is_lifetime_name) 79 rename_reference(&sema, position, new_name)
110 } 80 }
111} 81}
112 82
@@ -127,6 +97,33 @@ pub(crate) fn will_rename_file(
127 Some(change) 97 Some(change)
128} 98}
129 99
100#[derive(Copy, Clone, Debug, PartialEq)]
101enum IdentifierKind {
102 Ident,
103 Lifetime,
104 ToSelf,
105 Underscore,
106}
107
108fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> {
109 match lex_single_syntax_kind(new_name) {
110 Some(res) => match res {
111 (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident),
112 (T![_], _) => Ok(IdentifierKind::Underscore),
113 (T![self], _) => Ok(IdentifierKind::ToSelf),
114 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
115 Ok(IdentifierKind::Lifetime)
116 }
117 (SyntaxKind::LIFETIME_IDENT, _) => {
118 bail!("Invalid name `{0}`: Cannot rename lifetime to {0}", new_name)
119 }
120 (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
121 (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
122 },
123 None => bail!("Invalid name `{}`: not an identifier", new_name),
124 }
125}
126
130fn find_module_at_offset( 127fn find_module_at_offset(
131 sema: &Semantics<RootDatabase>, 128 sema: &Semantics<RootDatabase>,
132 position: FilePosition, 129 position: FilePosition,
@@ -155,39 +152,53 @@ fn find_module_at_offset(
155 Some(module) 152 Some(module)
156} 153}
157 154
158fn source_edit_from_reference( 155fn find_all_refs(
156 sema: &Semantics<RootDatabase>,
157 position: FilePosition,
158) -> RenameResult<RangeInfo<ReferenceSearchResult>> {
159 crate::references::find_all_refs(sema, position, None)
160 .ok_or_else(|| format_err!("No references found at position"))
161}
162
163fn source_edit_from_references(
159 sema: &Semantics<RootDatabase>, 164 sema: &Semantics<RootDatabase>,
160 reference: Reference, 165 file_id: FileId,
166 references: &[FileReference],
161 new_name: &str, 167 new_name: &str,
162) -> SourceFileEdit { 168) -> (FileId, TextEdit) {
163 let mut replacement_text = String::new(); 169 let mut edit = TextEdit::builder();
164 let range = match reference.kind { 170 for reference in references {
165 ReferenceKind::FieldShorthandForField => { 171 let mut replacement_text = String::new();
166 mark::hit!(test_rename_struct_field_for_shorthand); 172 let range = match reference.kind {
167 replacement_text.push_str(new_name); 173 ReferenceKind::FieldShorthandForField => {
168 replacement_text.push_str(": "); 174 mark::hit!(test_rename_struct_field_for_shorthand);
169 TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) 175 replacement_text.push_str(new_name);
170 } 176 replacement_text.push_str(": ");
171 ReferenceKind::FieldShorthandForLocal => { 177 TextRange::new(reference.range.start(), reference.range.start())
172 mark::hit!(test_rename_local_for_field_shorthand); 178 }
173 replacement_text.push_str(": "); 179 ReferenceKind::FieldShorthandForLocal => {
174 replacement_text.push_str(new_name); 180 mark::hit!(test_rename_local_for_field_shorthand);
175 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) 181 replacement_text.push_str(": ");
176 } 182 replacement_text.push_str(new_name);
177 ReferenceKind::RecordFieldExprOrPat => { 183 TextRange::new(reference.range.end(), reference.range.end())
178 mark::hit!(test_rename_field_expr_pat); 184 }
179 replacement_text.push_str(new_name); 185 ReferenceKind::RecordFieldExprOrPat => {
180 edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) 186 mark::hit!(test_rename_field_expr_pat);
181 } 187 replacement_text.push_str(new_name);
182 _ => { 188 edit_text_range_for_record_field_expr_or_pat(
183 replacement_text.push_str(new_name); 189 sema,
184 reference.file_range.range 190 FileRange { file_id, range: reference.range },
185 } 191 new_name,
186 }; 192 )
187 SourceFileEdit { 193 }
188 file_id: reference.file_range.file_id, 194 _ => {
189 edit: TextEdit::replace(range, replacement_text), 195 replacement_text.push_str(new_name);
196 reference.range
197 }
198 };
199 edit.replace(range, replacement_text);
190 } 200 }
201 (file_id, edit.finish())
191} 202}
192 203
193fn edit_text_range_for_record_field_expr_or_pat( 204fn edit_text_range_for_record_field_expr_or_pat(
@@ -223,9 +234,12 @@ fn rename_mod(
223 position: FilePosition, 234 position: FilePosition,
224 module: Module, 235 module: Module,
225 new_name: &str, 236 new_name: &str,
226) -> Result<RangeInfo<SourceChange>, RenameError> { 237) -> RenameResult<RangeInfo<SourceChange>> {
227 let mut source_file_edits = Vec::new(); 238 if IdentifierKind::Ident != check_identifier(new_name)? {
228 let mut file_system_edits = Vec::new(); 239 bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
240 }
241
242 let mut source_change = SourceChange::default();
229 243
230 let src = module.definition_source(sema.db); 244 let src = module.definition_source(sema.db);
231 let file_id = src.file_id.original_file(sema.db); 245 let file_id = src.file_id.original_file(sema.db);
@@ -239,7 +253,7 @@ fn rename_mod(
239 }; 253 };
240 let dst = AnchoredPathBuf { anchor: file_id, path }; 254 let dst = AnchoredPathBuf { anchor: file_id, path };
241 let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; 255 let move_file = FileSystemEdit::MoveFile { src: file_id, dst };
242 file_system_edits.push(move_file); 256 source_change.push_file_system_edit(move_file);
243 } 257 }
244 ModuleSource::Module(..) => {} 258 ModuleSource::Module(..) => {}
245 } 259 }
@@ -247,22 +261,19 @@ fn rename_mod(
247 if let Some(src) = module.declaration_source(sema.db) { 261 if let Some(src) = module.declaration_source(sema.db) {
248 let file_id = src.file_id.original_file(sema.db); 262 let file_id = src.file_id.original_file(sema.db);
249 let name = src.value.name().unwrap(); 263 let name = src.value.name().unwrap();
250 let edit = SourceFileEdit { 264 source_change.insert_source_edit(
251 file_id, 265 file_id,
252 edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), 266 TextEdit::replace(name.syntax().text_range(), new_name.into()),
253 }; 267 );
254 source_file_edits.push(edit);
255 } 268 }
256 269
257 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) 270 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
258 .ok_or_else(|| RenameError("No references found at position".to_string()))?; 271 let ref_edits = refs.references().iter().map(|(&file_id, references)| {
259 let ref_edits = refs 272 source_edit_from_references(sema, file_id, references, new_name)
260 .references 273 });
261 .into_iter() 274 source_change.extend(ref_edits);
262 .map(|reference| source_edit_from_reference(sema, reference, new_name));
263 source_file_edits.extend(ref_edits);
264 275
265 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 276 Ok(RangeInfo::new(range, source_change))
266} 277}
267 278
268fn rename_to_self( 279fn rename_to_self(
@@ -274,27 +285,26 @@ fn rename_to_self(
274 285
275 let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) 286 let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset)
276 .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) 287 .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast)))
277 .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; 288 .ok_or_else(|| format_err!("No surrounding method declaration found"))?;
278 let param_range = fn_ast 289 let param_range = fn_ast
279 .param_list() 290 .param_list()
280 .and_then(|p| p.params().next()) 291 .and_then(|p| p.params().next())
281 .ok_or_else(|| RenameError("Method has no parameters".to_string()))? 292 .ok_or_else(|| format_err!("Method has no parameters"))?
282 .syntax() 293 .syntax()
283 .text_range(); 294 .text_range();
284 if !param_range.contains(position.offset) { 295 if !param_range.contains(position.offset) {
285 return Err(RenameError("Only the first parameter can be self".to_string())); 296 bail!("Only the first parameter can be self");
286 } 297 }
287 298
288 let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) 299 let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset)
289 .and_then(|def| sema.to_def(&def)) 300 .and_then(|def| sema.to_def(&def))
290 .ok_or_else(|| RenameError("No impl block found for function".to_string()))?; 301 .ok_or_else(|| format_err!("No impl block found for function"))?;
291 if fn_def.self_param(sema.db).is_some() { 302 if fn_def.self_param(sema.db).is_some() {
292 return Err(RenameError("Method already has a self parameter".to_string())); 303 bail!("Method already has a self parameter");
293 } 304 }
294 305
295 let params = fn_def.assoc_fn_params(sema.db); 306 let params = fn_def.assoc_fn_params(sema.db);
296 let first_param = 307 let first_param = params.first().ok_or_else(|| format_err!("Method has no parameters"))?;
297 params.first().ok_or_else(|| RenameError("Method has no parameters".into()))?;
298 let first_param_ty = first_param.ty(); 308 let first_param_ty = first_param.ty();
299 let impl_ty = impl_block.target_ty(sema.db); 309 let impl_ty = impl_block.target_ty(sema.db);
300 let (ty, self_param) = if impl_ty.remove_ref().is_some() { 310 let (ty, self_param) = if impl_ty.remove_ref().is_some() {
@@ -307,31 +317,21 @@ fn rename_to_self(
307 }; 317 };
308 318
309 if ty != impl_ty { 319 if ty != impl_ty {
310 return Err(RenameError("Parameter type differs from impl block type".to_string())); 320 bail!("Parameter type differs from impl block type");
311 }
312
313 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)
314 .ok_or_else(|| RenameError("No reference found at position".to_string()))?;
315
316 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
317 .into_iter()
318 .partition(|reference| param_range.intersect(reference.file_range.range).is_some());
319
320 if param_ref.is_empty() {
321 return Err(RenameError("Parameter to rename not found".to_string()));
322 } 321 }
323 322
324 let mut edits = usages 323 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
325 .into_iter()
326 .map(|reference| source_edit_from_reference(sema, reference, "self"))
327 .collect::<Vec<_>>();
328 324
329 edits.push(SourceFileEdit { 325 let mut source_change = SourceChange::default();
330 file_id: position.file_id, 326 source_change.extend(refs.references().iter().map(|(&file_id, references)| {
331 edit: TextEdit::replace(param_range, String::from(self_param)), 327 source_edit_from_references(sema, file_id, references, "self")
332 }); 328 }));
329 source_change.insert_source_edit(
330 position.file_id,
331 TextEdit::replace(param_range, String::from(self_param)),
332 );
333 333
334 Ok(RangeInfo::new(range, SourceChange::from(edits))) 334 Ok(RangeInfo::new(range, source_change))
335} 335}
336 336
337fn text_edit_from_self_param( 337fn text_edit_from_self_param(
@@ -364,77 +364,93 @@ fn text_edit_from_self_param(
364fn rename_self_to_param( 364fn rename_self_to_param(
365 sema: &Semantics<RootDatabase>, 365 sema: &Semantics<RootDatabase>,
366 position: FilePosition, 366 position: FilePosition,
367 self_token: SyntaxToken,
368 new_name: &str, 367 new_name: &str,
368 ident_kind: IdentifierKind,
369 range: TextRange,
370 refs: ReferenceSearchResult,
369) -> Result<RangeInfo<SourceChange>, RenameError> { 371) -> Result<RangeInfo<SourceChange>, RenameError> {
372 match ident_kind {
373 IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name),
374 IdentifierKind::ToSelf => {
375 // no-op
376 mark::hit!(rename_self_to_self);
377 return Ok(RangeInfo::new(range, SourceChange::default()));
378 }
379 _ => (),
380 }
370 let source_file = sema.parse(position.file_id); 381 let source_file = sema.parse(position.file_id);
371 let syn = source_file.syntax(); 382 let syn = source_file.syntax();
372 383
373 let text = sema.db.file_text(position.file_id);
374 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) 384 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
375 .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; 385 .ok_or_else(|| format_err!("No surrounding method declaration found"))?;
376 let search_range = fn_def.syntax().text_range(); 386
387 let mut source_change = SourceChange::default();
388 if let Some(self_param) = fn_def.param_list().and_then(|it| it.self_param()) {
389 if self_param
390 .syntax()
391 .text_range()
392 .contains_range(refs.declaration().nav.focus_or_full_range())
393 {
394 let edit = text_edit_from_self_param(syn, &self_param, new_name)
395 .ok_or_else(|| format_err!("No target type found"))?;
396 source_change.insert_source_edit(position.file_id, edit);
377 397
378 let mut edits: Vec<SourceFileEdit> = vec![]; 398 source_change.extend(refs.references().iter().map(|(&file_id, references)| {
399 source_edit_from_references(sema, file_id, &references, new_name)
400 }));
379 401
380 for (idx, _) in text.match_indices("self") { 402 if source_change.source_file_edits.len() > 1 && ident_kind == IdentifierKind::Underscore
381 let offset: TextSize = idx.try_into().unwrap(); 403 {
382 if !search_range.contains_inclusive(offset) { 404 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
383 continue; 405 }
384 } 406
385 if let Some(ref usage) = 407 return Ok(RangeInfo::new(range, source_change));
386 syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
387 {
388 let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) {
389 text_edit_from_self_param(syn, self_param, new_name)
390 .ok_or_else(|| RenameError("No target type found".to_string()))?
391 } else {
392 TextEdit::replace(usage.text_range(), String::from(new_name))
393 };
394 edits.push(SourceFileEdit { file_id: position.file_id, edit });
395 } 408 }
396 } 409 }
397 410 Err(format_err!("Method has no self param"))
398 let range = ast::SelfParam::cast(self_token.parent())
399 .map_or(self_token.text_range(), |p| p.syntax().text_range());
400
401 Ok(RangeInfo::new(range, SourceChange::from(edits)))
402} 411}
403 412
404fn rename_reference( 413fn rename_reference(
405 sema: &Semantics<RootDatabase>, 414 sema: &Semantics<RootDatabase>,
406 position: FilePosition, 415 position: FilePosition,
407 new_name: &str, 416 new_name: &str,
408 is_lifetime_name: bool,
409) -> Result<RangeInfo<SourceChange>, RenameError> { 417) -> Result<RangeInfo<SourceChange>, RenameError> {
410 let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) { 418 let ident_kind = check_identifier(new_name)?;
411 Some(range_info) => range_info, 419 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
412 None => return Err(RenameError("No references found at position".to_string())), 420
413 }; 421 match (ident_kind, &refs.declaration.kind) {
414 422 (IdentifierKind::ToSelf, ReferenceKind::Lifetime)
415 match (refs.declaration.kind == ReferenceKind::Lifetime, is_lifetime_name) { 423 | (IdentifierKind::Underscore, ReferenceKind::Lifetime)
416 (true, false) => { 424 | (IdentifierKind::Ident, ReferenceKind::Lifetime) => {
417 return Err(RenameError(format!( 425 mark::hit!(rename_not_a_lifetime_ident_ref);
418 "Invalid name `{}`: not a lifetime identifier", 426 bail!("Invalid name `{}`: not a lifetime identifier", new_name)
419 new_name
420 )))
421 } 427 }
422 (false, true) => { 428 (IdentifierKind::Lifetime, ReferenceKind::Lifetime) => mark::hit!(rename_lifetime),
423 return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) 429 (IdentifierKind::Lifetime, _) => {
430 mark::hit!(rename_not_an_ident_ref);
431 bail!("Invalid name `{}`: not an identifier", new_name)
424 } 432 }
425 _ => (), 433 (_, ReferenceKind::SelfParam) => {
434 mark::hit!(rename_self_to_param);
435 return rename_self_to_param(sema, position, new_name, ident_kind, range, refs);
436 }
437 (IdentifierKind::ToSelf, _) => {
438 mark::hit!(rename_to_self);
439 return rename_to_self(sema, position);
440 }
441 (IdentifierKind::Underscore, _) if !refs.references.is_empty() => {
442 mark::hit!(rename_underscore_multiple);
443 bail!("Cannot rename reference to `_` as it is being referenced multiple times")
444 }
445 (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident),
426 } 446 }
427 447
428 let edit = refs 448 let mut source_change = SourceChange::default();
429 .into_iter() 449 source_change.extend(refs.into_iter().map(|(file_id, references)| {
430 .map(|reference| source_edit_from_reference(sema, reference, new_name)) 450 source_edit_from_references(sema, file_id, &references, new_name)
431 .collect::<Vec<_>>(); 451 }));
432
433 if edit.is_empty() {
434 return Err(RenameError("No references found at position".to_string()));
435 }
436 452
437 Ok(RangeInfo::new(range, SourceChange::from(edit))) 453 Ok(RangeInfo::new(range, source_change))
438} 454}
439 455
440#[cfg(test)] 456#[cfg(test)]
@@ -457,14 +473,16 @@ mod tests {
457 let mut text_edit_builder = TextEdit::builder(); 473 let mut text_edit_builder = TextEdit::builder();
458 let mut file_id: Option<FileId> = None; 474 let mut file_id: Option<FileId> = None;
459 for edit in source_change.info.source_file_edits { 475 for edit in source_change.info.source_file_edits {
460 file_id = Some(edit.file_id); 476 file_id = Some(edit.0);
461 for indel in edit.edit.into_iter() { 477 for indel in edit.1.into_iter() {
462 text_edit_builder.replace(indel.delete, indel.insert); 478 text_edit_builder.replace(indel.delete, indel.insert);
463 } 479 }
464 } 480 }
465 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string(); 481 if let Some(file_id) = file_id {
466 text_edit_builder.finish().apply(&mut result); 482 let mut result = analysis.file_text(file_id).unwrap().to_string();
467 assert_eq_text!(ra_fixture_after, &*result); 483 text_edit_builder.finish().apply(&mut result);
484 assert_eq_text!(ra_fixture_after, &*result);
485 }
468 } 486 }
469 Err(err) => { 487 Err(err) => {
470 if ra_fixture_after.starts_with("error:") { 488 if ra_fixture_after.starts_with("error:") {
@@ -493,19 +511,19 @@ mod tests {
493 511
494 #[test] 512 #[test]
495 fn test_rename_to_underscore() { 513 fn test_rename_to_underscore() {
496 check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#); 514 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
497 } 515 }
498 516
499 #[test] 517 #[test]
500 fn test_rename_to_raw_identifier() { 518 fn test_rename_to_raw_identifier() {
501 check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#); 519 check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
502 } 520 }
503 521
504 #[test] 522 #[test]
505 fn test_rename_to_invalid_identifier1() { 523 fn test_rename_to_invalid_identifier1() {
506 check( 524 check(
507 "invalid!", 525 "invalid!",
508 r#"fn main() { let i<|> = 1; }"#, 526 r#"fn main() { let i$0 = 1; }"#,
509 "error: Invalid name `invalid!`: not an identifier", 527 "error: Invalid name `invalid!`: not an identifier",
510 ); 528 );
511 } 529 }
@@ -514,7 +532,7 @@ mod tests {
514 fn test_rename_to_invalid_identifier2() { 532 fn test_rename_to_invalid_identifier2() {
515 check( 533 check(
516 "multiple tokens", 534 "multiple tokens",
517 r#"fn main() { let i<|> = 1; }"#, 535 r#"fn main() { let i$0 = 1; }"#,
518 "error: Invalid name `multiple tokens`: not an identifier", 536 "error: Invalid name `multiple tokens`: not an identifier",
519 ); 537 );
520 } 538 }
@@ -523,38 +541,60 @@ mod tests {
523 fn test_rename_to_invalid_identifier3() { 541 fn test_rename_to_invalid_identifier3() {
524 check( 542 check(
525 "let", 543 "let",
526 r#"fn main() { let i<|> = 1; }"#, 544 r#"fn main() { let i$0 = 1; }"#,
527 "error: Invalid name `let`: not an identifier", 545 "error: Invalid name `let`: not an identifier",
528 ); 546 );
529 } 547 }
530 548
531 #[test] 549 #[test]
532 fn test_rename_to_invalid_identifier_lifetime() { 550 fn test_rename_to_invalid_identifier_lifetime() {
551 mark::check!(rename_not_an_ident_ref);
533 check( 552 check(
534 "'foo", 553 "'foo",
535 r#"fn main() { let i<|> = 1; }"#, 554 r#"fn main() { let i$0 = 1; }"#,
536 "error: Invalid name `'foo`: not an identifier", 555 "error: Invalid name `'foo`: not an identifier",
537 ); 556 );
538 } 557 }
539 558
540 #[test] 559 #[test]
541 fn test_rename_to_invalid_identifier_lifetime2() { 560 fn test_rename_to_invalid_identifier_lifetime2() {
561 mark::check!(rename_not_a_lifetime_ident_ref);
542 check( 562 check(
543 "foo", 563 "foo",
544 r#"fn main<'a>(_: &'a<|> ()) {}"#, 564 r#"fn main<'a>(_: &'a$0 ()) {}"#,
545 "error: Invalid name `foo`: not a lifetime identifier", 565 "error: Invalid name `foo`: not a lifetime identifier",
546 ); 566 );
547 } 567 }
548 568
549 #[test] 569 #[test]
570 fn test_rename_to_underscore_invalid() {
571 mark::check!(rename_underscore_multiple);
572 check(
573 "_",
574 r#"fn main(foo$0: ()) {foo;}"#,
575 "error: Cannot rename reference to `_` as it is being referenced multiple times",
576 );
577 }
578
579 #[test]
580 fn test_rename_mod_invalid() {
581 check(
582 "'foo",
583 r#"mod foo$0 {}"#,
584 "error: Invalid name `'foo`: cannot rename module to 'foo",
585 );
586 }
587
588 #[test]
550 fn test_rename_for_local() { 589 fn test_rename_for_local() {
590 mark::check!(rename_ident);
551 check( 591 check(
552 "k", 592 "k",
553 r#" 593 r#"
554fn main() { 594fn main() {
555 let mut i = 1; 595 let mut i = 1;
556 let j = 1; 596 let j = 1;
557 i = i<|> + j; 597 i = i$0 + j;
558 598
559 { i = 0; } 599 { i = 0; }
560 600
@@ -579,7 +619,7 @@ fn main() {
579 fn test_rename_unresolved_reference() { 619 fn test_rename_unresolved_reference() {
580 check( 620 check(
581 "new_name", 621 "new_name",
582 r#"fn main() { let _ = unresolved_ref<|>; }"#, 622 r#"fn main() { let _ = unresolved_ref$0; }"#,
583 "error: No references found at position", 623 "error: No references found at position",
584 ); 624 );
585 } 625 }
@@ -591,7 +631,7 @@ fn main() {
591 r#" 631 r#"
592macro_rules! foo {($i:ident) => {$i} } 632macro_rules! foo {($i:ident) => {$i} }
593fn main() { 633fn main() {
594 let a<|> = "test"; 634 let a$0 = "test";
595 foo!(a); 635 foo!(a);
596} 636}
597"#, 637"#,
@@ -613,7 +653,7 @@ fn main() {
613macro_rules! foo {($i:ident) => {$i} } 653macro_rules! foo {($i:ident) => {$i} }
614fn main() { 654fn main() {
615 let a = "test"; 655 let a = "test";
616 foo!(a<|>); 656 foo!(a$0);
617} 657}
618"#, 658"#,
619 r#" 659 r#"
@@ -634,7 +674,7 @@ fn main() {
634macro_rules! define_fn {($id:ident) => { fn $id{} }} 674macro_rules! define_fn {($id:ident) => { fn $id{} }}
635define_fn!(foo); 675define_fn!(foo);
636fn main() { 676fn main() {
637 fo<|>o(); 677 fo$0o();
638} 678}
639"#, 679"#,
640 r#" 680 r#"
@@ -653,7 +693,7 @@ fn main() {
653 "bar", 693 "bar",
654 r#" 694 r#"
655macro_rules! define_fn {($id:ident) => { fn $id{} }} 695macro_rules! define_fn {($id:ident) => { fn $id{} }}
656define_fn!(fo<|>o); 696define_fn!(fo$0o);
657fn main() { 697fn main() {
658 foo(); 698 foo();
659} 699}
@@ -670,17 +710,17 @@ fn main() {
670 710
671 #[test] 711 #[test]
672 fn test_rename_for_param_inside() { 712 fn test_rename_for_param_inside() {
673 check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#); 713 check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#);
674 } 714 }
675 715
676 #[test] 716 #[test]
677 fn test_rename_refs_for_fn_param() { 717 fn test_rename_refs_for_fn_param() {
678 check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); 718 check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
679 } 719 }
680 720
681 #[test] 721 #[test]
682 fn test_rename_for_mut_param() { 722 fn test_rename_for_mut_param() {
683 check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); 723 check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
684 } 724 }
685 725
686 #[test] 726 #[test]
@@ -688,7 +728,7 @@ fn main() {
688 check( 728 check(
689 "j", 729 "j",
690 r#" 730 r#"
691struct Foo { i<|>: i32 } 731struct Foo { i$0: i32 }
692 732
693impl Foo { 733impl Foo {
694 fn new(i: i32) -> Self { 734 fn new(i: i32) -> Self {
@@ -714,7 +754,7 @@ impl Foo {
714 check( 754 check(
715 "j", 755 "j",
716 r#" 756 r#"
717struct Foo { i<|>: i32 } 757struct Foo { i$0: i32 }
718 758
719impl Foo { 759impl Foo {
720 fn new(i: i32) -> Self { 760 fn new(i: i32) -> Self {
@@ -743,7 +783,7 @@ impl Foo {
743struct Foo { i: i32 } 783struct Foo { i: i32 }
744 784
745impl Foo { 785impl Foo {
746 fn new(i<|>: i32) -> Self { 786 fn new(i$0: i32) -> Self {
747 Self { i } 787 Self { i }
748 } 788 }
749} 789}
@@ -765,7 +805,7 @@ impl Foo {
765 check( 805 check(
766 "j", 806 "j",
767 r#" 807 r#"
768struct Foo { i<|>: i32 } 808struct Foo { i$0: i32 }
769struct Bar { i: i32 } 809struct Bar { i: i32 }
770 810
771impl Bar { 811impl Bar {
@@ -794,7 +834,7 @@ impl Bar {
794 r#" 834 r#"
795struct Foo { i: i32 } 835struct Foo { i: i32 }
796 836
797fn baz(i<|>: i32) -> Self { 837fn baz(i$0: i32) -> Self {
798 let x = Foo { i }; 838 let x = Foo { i };
799 { 839 {
800 let i = 0; 840 let i = 0;
@@ -825,7 +865,7 @@ fn baz(j: i32) -> Self {
825mod bar; 865mod bar;
826 866
827//- /bar.rs 867//- /bar.rs
828mod foo<|>; 868mod foo$0;
829 869
830//- /bar/foo.rs 870//- /bar/foo.rs
831// empty 871// empty
@@ -834,21 +874,18 @@ mod foo<|>;
834 RangeInfo { 874 RangeInfo {
835 range: 4..7, 875 range: 4..7,
836 info: SourceChange { 876 info: SourceChange {
837 source_file_edits: [ 877 source_file_edits: {
838 SourceFileEdit { 878 FileId(
839 file_id: FileId( 879 1,
840 1, 880 ): TextEdit {
841 ), 881 indels: [
842 edit: TextEdit { 882 Indel {
843 indels: [ 883 insert: "foo2",
844 Indel { 884 delete: 4..7,
845 insert: "foo2", 885 },
846 delete: 4..7, 886 ],
847 },
848 ],
849 },
850 }, 887 },
851 ], 888 },
852 file_system_edits: [ 889 file_system_edits: [
853 MoveFile { 890 MoveFile {
854 src: FileId( 891 src: FileId(
@@ -883,40 +920,34 @@ fn main() {}
883pub struct FooContent; 920pub struct FooContent;
884 921
885//- /bar.rs 922//- /bar.rs
886use crate::foo<|>::FooContent; 923use crate::foo$0::FooContent;
887"#, 924"#,
888 expect![[r#" 925 expect![[r#"
889 RangeInfo { 926 RangeInfo {
890 range: 11..14, 927 range: 11..14,
891 info: SourceChange { 928 info: SourceChange {
892 source_file_edits: [ 929 source_file_edits: {
893 SourceFileEdit { 930 FileId(
894 file_id: FileId( 931 0,
895 0, 932 ): TextEdit {
896 ), 933 indels: [
897 edit: TextEdit { 934 Indel {
898 indels: [ 935 insert: "quux",
899 Indel { 936 delete: 8..11,
900 insert: "quux", 937 },
901 delete: 8..11, 938 ],
902 },
903 ],
904 },
905 }, 939 },
906 SourceFileEdit { 940 FileId(
907 file_id: FileId( 941 2,
908 2, 942 ): TextEdit {
909 ), 943 indels: [
910 edit: TextEdit { 944 Indel {
911 indels: [ 945 insert: "quux",
912 Indel { 946 delete: 11..14,
913 insert: "quux", 947 },
914 delete: 11..14, 948 ],
915 },
916 ],
917 },
918 }, 949 },
919 ], 950 },
920 file_system_edits: [ 951 file_system_edits: [
921 MoveFile { 952 MoveFile {
922 src: FileId( 953 src: FileId(
@@ -943,29 +974,26 @@ use crate::foo<|>::FooContent;
943 "foo2", 974 "foo2",
944 r#" 975 r#"
945//- /lib.rs 976//- /lib.rs
946mod fo<|>o; 977mod fo$0o;
947//- /foo/mod.rs 978//- /foo/mod.rs
948// emtpy 979// empty
949"#, 980"#,
950 expect![[r#" 981 expect![[r#"
951 RangeInfo { 982 RangeInfo {
952 range: 4..7, 983 range: 4..7,
953 info: SourceChange { 984 info: SourceChange {
954 source_file_edits: [ 985 source_file_edits: {
955 SourceFileEdit { 986 FileId(
956 file_id: FileId( 987 0,
957 0, 988 ): TextEdit {
958 ), 989 indels: [
959 edit: TextEdit { 990 Indel {
960 indels: [ 991 insert: "foo2",
961 Indel { 992 delete: 4..7,
962 insert: "foo2", 993 },
963 delete: 4..7, 994 ],
964 },
965 ],
966 },
967 }, 995 },
968 ], 996 },
969 file_system_edits: [ 997 file_system_edits: [
970 MoveFile { 998 MoveFile {
971 src: FileId( 999 src: FileId(
@@ -992,30 +1020,27 @@ mod fo<|>o;
992 "bar", 1020 "bar",
993 r#" 1021 r#"
994//- /lib.rs 1022//- /lib.rs
995mod outer { mod fo<|>o; } 1023mod outer { mod fo$0o; }
996 1024
997//- /outer/foo.rs 1025//- /outer/foo.rs
998// emtpy 1026// empty
999"#, 1027"#,
1000 expect![[r#" 1028 expect![[r#"
1001 RangeInfo { 1029 RangeInfo {
1002 range: 16..19, 1030 range: 16..19,
1003 info: SourceChange { 1031 info: SourceChange {
1004 source_file_edits: [ 1032 source_file_edits: {
1005 SourceFileEdit { 1033 FileId(
1006 file_id: FileId( 1034 0,
1007 0, 1035 ): TextEdit {
1008 ), 1036 indels: [
1009 edit: TextEdit { 1037 Indel {
1010 indels: [ 1038 insert: "bar",
1011 Indel { 1039 delete: 16..19,
1012 insert: "bar", 1040 },
1013 delete: 16..19, 1041 ],
1014 },
1015 ],
1016 },
1017 }, 1042 },
1018 ], 1043 },
1019 file_system_edits: [ 1044 file_system_edits: [
1020 MoveFile { 1045 MoveFile {
1021 src: FileId( 1046 src: FileId(
@@ -1041,7 +1066,7 @@ mod outer { mod fo<|>o; }
1041 check( 1066 check(
1042 "baz", 1067 "baz",
1043 r#" 1068 r#"
1044mod <|>foo { pub fn bar() {} } 1069mod $0foo { pub fn bar() {} }
1045 1070
1046fn main() { foo::bar(); } 1071fn main() { foo::bar(); }
1047"#, 1072"#,
@@ -1065,7 +1090,7 @@ fn f() {
1065} 1090}
1066 1091
1067//- /bar.rs 1092//- /bar.rs
1068pub mod foo<|>; 1093pub mod foo$0;
1069 1094
1070//- /bar/foo.rs 1095//- /bar/foo.rs
1071// pub fn fun() {} 1096// pub fn fun() {}
@@ -1074,34 +1099,28 @@ pub mod foo<|>;
1074 RangeInfo { 1099 RangeInfo {
1075 range: 8..11, 1100 range: 8..11,
1076 info: SourceChange { 1101 info: SourceChange {
1077 source_file_edits: [ 1102 source_file_edits: {
1078 SourceFileEdit { 1103 FileId(
1079 file_id: FileId( 1104 0,
1080 1, 1105 ): TextEdit {
1081 ), 1106 indels: [
1082 edit: TextEdit { 1107 Indel {
1083 indels: [ 1108 insert: "foo2",
1084 Indel { 1109 delete: 27..30,
1085 insert: "foo2", 1110 },
1086 delete: 8..11, 1111 ],
1087 },
1088 ],
1089 },
1090 }, 1112 },
1091 SourceFileEdit { 1113 FileId(
1092 file_id: FileId( 1114 1,
1093 0, 1115 ): TextEdit {
1094 ), 1116 indels: [
1095 edit: TextEdit { 1117 Indel {
1096 indels: [ 1118 insert: "foo2",
1097 Indel { 1119 delete: 8..11,
1098 insert: "foo2", 1120 },
1099 delete: 27..30, 1121 ],
1100 },
1101 ],
1102 },
1103 }, 1122 },
1104 ], 1123 },
1105 file_system_edits: [ 1124 file_system_edits: [
1106 MoveFile { 1125 MoveFile {
1107 src: FileId( 1126 src: FileId(
@@ -1128,7 +1147,7 @@ pub mod foo<|>;
1128 "Baz", 1147 "Baz",
1129 r#" 1148 r#"
1130mod foo { 1149mod foo {
1131 pub enum Foo { Bar<|> } 1150 pub enum Foo { Bar$0 }
1132} 1151}
1133 1152
1134fn func(f: foo::Foo) { 1153fn func(f: foo::Foo) {
@@ -1157,7 +1176,7 @@ fn func(f: foo::Foo) {
1157 "baz", 1176 "baz",
1158 r#" 1177 r#"
1159mod foo { 1178mod foo {
1160 pub struct Foo { pub bar<|>: uint } 1179 pub struct Foo { pub bar$0: uint }
1161} 1180}
1162 1181
1163fn foo(f: foo::Foo) { 1182fn foo(f: foo::Foo) {
@@ -1178,13 +1197,14 @@ fn foo(f: foo::Foo) {
1178 1197
1179 #[test] 1198 #[test]
1180 fn test_parameter_to_self() { 1199 fn test_parameter_to_self() {
1200 mark::check!(rename_to_self);
1181 check( 1201 check(
1182 "self", 1202 "self",
1183 r#" 1203 r#"
1184struct Foo { i: i32 } 1204struct Foo { i: i32 }
1185 1205
1186impl Foo { 1206impl Foo {
1187 fn f(foo<|>: &mut Foo) -> i32 { 1207 fn f(foo$0: &mut Foo) -> i32 {
1188 foo.i 1208 foo.i
1189 } 1209 }
1190} 1210}
@@ -1205,7 +1225,7 @@ impl Foo {
1205struct Foo { i: i32 } 1225struct Foo { i: i32 }
1206 1226
1207impl Foo { 1227impl Foo {
1208 fn f(foo<|>: Foo) -> i32 { 1228 fn f(foo$0: Foo) -> i32 {
1209 foo.i 1229 foo.i
1210 } 1230 }
1211} 1231}
@@ -1229,7 +1249,7 @@ impl Foo {
1229 r#" 1249 r#"
1230struct Foo { i: i32 } 1250struct Foo { i: i32 }
1231 1251
1232fn f(foo<|>: &mut Foo) -> i32 { 1252fn f(foo$0: &mut Foo) -> i32 {
1233 foo.i 1253 foo.i
1234} 1254}
1235"#, 1255"#,
@@ -1242,7 +1262,7 @@ struct Foo { i: i32 }
1242struct Bar; 1262struct Bar;
1243 1263
1244impl Bar { 1264impl Bar {
1245 fn f(foo<|>: &mut Foo) -> i32 { 1265 fn f(foo$0: &mut Foo) -> i32 {
1246 foo.i 1266 foo.i
1247 } 1267 }
1248} 1268}
@@ -1258,7 +1278,7 @@ impl Bar {
1258 r#" 1278 r#"
1259struct Foo { i: i32 } 1279struct Foo { i: i32 }
1260impl Foo { 1280impl Foo {
1261 fn f(x: (), foo<|>: &mut Foo) -> i32 { 1281 fn f(x: (), foo$0: &mut Foo) -> i32 {
1262 foo.i 1282 foo.i
1263 } 1283 }
1264} 1284}
@@ -1274,7 +1294,7 @@ impl Foo {
1274 r#" 1294 r#"
1275struct Foo { i: i32 } 1295struct Foo { i: i32 }
1276impl &Foo { 1296impl &Foo {
1277 fn f(foo<|>: &Foo) -> i32 { 1297 fn f(foo$0: &Foo) -> i32 {
1278 foo.i 1298 foo.i
1279 } 1299 }
1280} 1300}
@@ -1298,7 +1318,7 @@ impl &Foo {
1298struct Foo { i: i32 } 1318struct Foo { i: i32 }
1299 1319
1300impl Foo { 1320impl Foo {
1301 fn f(&mut <|>self) -> i32 { 1321 fn f(&mut $0self) -> i32 {
1302 self.i 1322 self.i
1303 } 1323 }
1304} 1324}
@@ -1317,13 +1337,14 @@ impl Foo {
1317 1337
1318 #[test] 1338 #[test]
1319 fn test_owned_self_to_parameter() { 1339 fn test_owned_self_to_parameter() {
1340 mark::check!(rename_self_to_param);
1320 check( 1341 check(
1321 "foo", 1342 "foo",
1322 r#" 1343 r#"
1323struct Foo { i: i32 } 1344struct Foo { i: i32 }
1324 1345
1325impl Foo { 1346impl Foo {
1326 fn f(<|>self) -> i32 { 1347 fn f($0self) -> i32 {
1327 self.i 1348 self.i
1328 } 1349 }
1329} 1350}
@@ -1350,7 +1371,7 @@ struct Foo { i: i32 }
1350impl Foo { 1371impl Foo {
1351 fn f(&self) -> i32 { 1372 fn f(&self) -> i32 {
1352 let self_var = 1; 1373 let self_var = 1;
1353 self<|>.i 1374 self$0.i
1354 } 1375 }
1355} 1376}
1356"#, 1377"#,
@@ -1373,7 +1394,7 @@ impl Foo {
1373 check( 1394 check(
1374 "bar", 1395 "bar",
1375 r#" 1396 r#"
1376struct Foo { i<|>: i32 } 1397struct Foo { i$0: i32 }
1377 1398
1378fn foo(bar: i32) -> Foo { 1399fn foo(bar: i32) -> Foo {
1379 Foo { i: bar } 1400 Foo { i: bar }
@@ -1394,7 +1415,7 @@ fn foo(bar: i32) -> Foo {
1394 check( 1415 check(
1395 "baz", 1416 "baz",
1396 r#" 1417 r#"
1397struct Foo { i<|>: i32 } 1418struct Foo { i$0: i32 }
1398 1419
1399fn foo(foo: Foo) { 1420fn foo(foo: Foo) {
1400 let Foo { i: baz } = foo; 1421 let Foo { i: baz } = foo;
@@ -1433,7 +1454,7 @@ struct Foo {
1433 1454
1434fn foo(foo: Foo) { 1455fn foo(foo: Foo) {
1435 let Foo { i: b } = foo; 1456 let Foo { i: b } = foo;
1436 let _ = b<|>; 1457 let _ = b$0;
1437} 1458}
1438"#, 1459"#,
1439 expected_fixture, 1460 expected_fixture,
@@ -1447,7 +1468,7 @@ struct Foo {
1447 1468
1448fn foo(foo: Foo) { 1469fn foo(foo: Foo) {
1449 let Foo { i } = foo; 1470 let Foo { i } = foo;
1450 let _ = i<|>; 1471 let _ = i$0;
1451} 1472}
1452"#, 1473"#,
1453 expected_fixture, 1474 expected_fixture,
@@ -1464,7 +1485,7 @@ struct Foo {
1464} 1485}
1465 1486
1466fn foo(Foo { i }: foo) -> i32 { 1487fn foo(Foo { i }: foo) -> i32 {
1467 i<|> 1488 i$0
1468} 1489}
1469"#, 1490"#,
1470 r#" 1491 r#"
@@ -1481,6 +1502,7 @@ fn foo(Foo { i: bar }: foo) -> i32 {
1481 1502
1482 #[test] 1503 #[test]
1483 fn test_rename_lifetimes() { 1504 fn test_rename_lifetimes() {
1505 mark::check!(rename_lifetime);
1484 check( 1506 check(
1485 "'yeeee", 1507 "'yeeee",
1486 r#" 1508 r#"
@@ -1488,7 +1510,7 @@ trait Foo<'a> {
1488 fn foo() -> &'a (); 1510 fn foo() -> &'a ();
1489} 1511}
1490impl<'a> Foo<'a> for &'a () { 1512impl<'a> Foo<'a> for &'a () {
1491 fn foo() -> &'a<|> () { 1513 fn foo() -> &'a$0 () {
1492 unimplemented!() 1514 unimplemented!()
1493 } 1515 }
1494} 1516}
@@ -1520,7 +1542,7 @@ fn main() {
1520 let test_variable = CustomOption::Some(22); 1542 let test_variable = CustomOption::Some(22);
1521 1543
1522 match test_variable { 1544 match test_variable {
1523 CustomOption::Some(foo<|>) if foo == 11 => {} 1545 CustomOption::Some(foo$0) if foo == 11 => {}
1524 _ => (), 1546 _ => (),
1525 } 1547 }
1526}"#, 1548}"#,
@@ -1549,7 +1571,7 @@ fn main() {
1549fn foo<'a>() -> &'a () { 1571fn foo<'a>() -> &'a () {
1550 'a: { 1572 'a: {
1551 'b: loop { 1573 'b: loop {
1552 break 'a<|>; 1574 break 'a$0;
1553 } 1575 }
1554 } 1576 }
1555} 1577}
@@ -1565,4 +1587,24 @@ fn foo<'a>() -> &'a () {
1565"#, 1587"#,
1566 ) 1588 )
1567 } 1589 }
1590
1591 #[test]
1592 fn test_self_to_self() {
1593 mark::check!(rename_self_to_self);
1594 check(
1595 "self",
1596 r#"
1597struct Foo;
1598impl Foo {
1599 fn foo(self$0) {}
1600}
1601"#,
1602 r#"
1603struct Foo;
1604impl Foo {
1605 fn foo(self) {}
1606}
1607"#,
1608 )
1609 }
1568} 1610}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index f4030f3ef..f5ee7de86 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -3,7 +3,7 @@ use std::fmt;
3use assists::utils::test_related_attribute; 3use assists::utils::test_related_attribute;
4use cfg::CfgExpr; 4use cfg::CfgExpr;
5use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; 5use hir::{AsAssocItem, HasAttrs, HasSource, Semantics};
6use ide_db::RootDatabase; 6use ide_db::{defs::Definition, RootDatabase};
7use itertools::Itertools; 7use itertools::Itertools;
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, 9 ast::{self, AstNode, AttrsOwner, ModuleItemOwner},
@@ -96,21 +96,26 @@ impl Runnable {
96pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 96pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
97 let sema = Semantics::new(db); 97 let sema = Semantics::new(db);
98 let source_file = sema.parse(file_id); 98 let source_file = sema.parse(file_id);
99 source_file.syntax().descendants().filter_map(|i| runnable(&sema, i)).collect() 99 source_file
100} 100 .syntax()
101 101 .descendants()
102pub(crate) fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { 102 .filter_map(|item| {
103 let runnable_item = match_ast! { 103 let runnable = match_ast! {
104 match (item.clone()) { 104 match item {
105 ast::Fn(func) => { 105 ast::Fn(func) => {
106 let def = sema.to_def(&func)?; 106 let def = sema.to_def(&func)?;
107 runnable_fn(sema, def) 107 runnable_fn(&sema, def)
108 }, 108 },
109 ast::Module(it) => runnable_mod(sema, it), 109 ast::Module(it) => runnable_mod(&sema, it),
110 _ => None, 110 _ => None,
111 } 111 }
112 }; 112 };
113 runnable_item.or_else(|| runnable_doctest(sema, item)) 113 runnable.or_else(|| match doc_owner_to_def(&sema, item)? {
114 Definition::ModuleDef(def) => module_def_doctest(&sema, def),
115 _ => None,
116 })
117 })
118 .collect()
114} 119}
115 120
116pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { 121pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
@@ -145,20 +150,49 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) ->
145 Some(Runnable { nav, kind, cfg }) 150 Some(Runnable { nav, kind, cfg })
146} 151}
147 152
148fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { 153pub(crate) fn runnable_mod(
149 match_ast! { 154 sema: &Semantics<RootDatabase>,
155 module: ast::Module,
156) -> Option<Runnable> {
157 if !has_test_function_or_multiple_test_submodules(&module) {
158 return None;
159 }
160 let module_def = sema.to_def(&module)?;
161
162 let path = module_def
163 .path_to_root(sema.db)
164 .into_iter()
165 .rev()
166 .filter_map(|it| it.name(sema.db))
167 .join("::");
168
169 let def = sema.to_def(&module)?;
170 let attrs = def.attrs(sema.db);
171 let cfg = attrs.cfg();
172 let nav = module_def.to_nav(sema.db);
173 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
174}
175
176// FIXME: figure out a proper API here.
177pub(crate) fn doc_owner_to_def(
178 sema: &Semantics<RootDatabase>,
179 item: SyntaxNode,
180) -> Option<Definition> {
181 let res: hir::ModuleDef = match_ast! {
150 match item { 182 match item {
151 ast::Fn(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 183 ast::SourceFile(it) => sema.scope(&item).module()?.into(),
152 ast::Struct(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 184 ast::Fn(it) => sema.to_def(&it)?.into(),
153 ast::Enum(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 185 ast::Struct(it) => sema.to_def(&it)?.into(),
154 ast::Union(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 186 ast::Enum(it) => sema.to_def(&it)?.into(),
155 ast::Trait(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 187 ast::Union(it) => sema.to_def(&it)?.into(),
156 ast::Const(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 188 ast::Trait(it) => sema.to_def(&it)?.into(),
157 ast::Static(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 189 ast::Const(it) => sema.to_def(&it)?.into(),
158 ast::TypeAlias(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 190 ast::Static(it) => sema.to_def(&it)?.into(),
159 _ => None, 191 ast::TypeAlias(it) => sema.to_def(&it)?.into(),
192 _ => return None,
160 } 193 }
161 } 194 };
195 Some(Definition::ModuleDef(res))
162} 196}
163 197
164fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> { 198fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> {
@@ -253,26 +287,6 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
253 }) 287 })
254} 288}
255 289
256fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
257 if !has_test_function_or_multiple_test_submodules(&module) {
258 return None;
259 }
260 let module_def = sema.to_def(&module)?;
261
262 let path = module_def
263 .path_to_root(sema.db)
264 .into_iter()
265 .rev()
266 .filter_map(|it| it.name(sema.db))
267 .join("::");
268
269 let def = sema.to_def(&module)?;
270 let attrs = def.attrs(sema.db);
271 let cfg = attrs.cfg();
272 let nav = module_def.to_nav(sema.db);
273 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
274}
275
276// We could create runnables for modules with number_of_test_submodules > 0, 290// We could create runnables for modules with number_of_test_submodules > 0,
277// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already 291// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already
278fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { 292fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
@@ -329,7 +343,7 @@ mod tests {
329 check( 343 check(
330 r#" 344 r#"
331//- /lib.rs 345//- /lib.rs
332<|> 346$0
333fn main() {} 347fn main() {}
334 348
335#[test] 349#[test]
@@ -425,7 +439,7 @@ fn bench() {}
425 check( 439 check(
426 r#" 440 r#"
427//- /lib.rs 441//- /lib.rs
428<|> 442$0
429fn main() {} 443fn main() {}
430 444
431/// ``` 445/// ```
@@ -573,7 +587,7 @@ struct StructWithRunnable(String);
573 check( 587 check(
574 r#" 588 r#"
575//- /lib.rs 589//- /lib.rs
576<|> 590$0
577fn main() {} 591fn main() {}
578 592
579struct Data; 593struct Data;
@@ -625,7 +639,7 @@ impl Data {
625 check( 639 check(
626 r#" 640 r#"
627//- /lib.rs 641//- /lib.rs
628<|> 642$0
629mod test_mod { 643mod test_mod {
630 #[test] 644 #[test]
631 fn test_foo1() {} 645 fn test_foo1() {}
@@ -679,7 +693,7 @@ mod test_mod {
679 check( 693 check(
680 r#" 694 r#"
681//- /lib.rs 695//- /lib.rs
682<|> 696$0
683mod root_tests { 697mod root_tests {
684 mod nested_tests_0 { 698 mod nested_tests_0 {
685 mod nested_tests_1 { 699 mod nested_tests_1 {
@@ -819,7 +833,7 @@ mod root_tests {
819 check( 833 check(
820 r#" 834 r#"
821//- /lib.rs crate:foo cfg:feature=foo 835//- /lib.rs crate:foo cfg:feature=foo
822<|> 836$0
823#[test] 837#[test]
824#[cfg(feature = "foo")] 838#[cfg(feature = "foo")]
825fn test_foo1() {} 839fn test_foo1() {}
@@ -864,7 +878,7 @@ fn test_foo1() {}
864 check( 878 check(
865 r#" 879 r#"
866//- /lib.rs crate:foo cfg:feature=foo,feature=bar 880//- /lib.rs crate:foo cfg:feature=foo,feature=bar
867<|> 881$0
868#[test] 882#[test]
869#[cfg(all(feature = "foo", feature = "bar"))] 883#[cfg(all(feature = "foo", feature = "bar"))]
870fn test_foo1() {} 884fn test_foo1() {}
@@ -919,7 +933,7 @@ fn test_foo1() {}
919 check( 933 check(
920 r#" 934 r#"
921//- /lib.rs 935//- /lib.rs
922<|> 936$0
923mod test_mod { 937mod test_mod {
924 fn foo1() {} 938 fn foo1() {}
925} 939}
@@ -938,7 +952,7 @@ mod test_mod {
938//- /lib.rs 952//- /lib.rs
939mod foo; 953mod foo;
940//- /foo.rs 954//- /foo.rs
941struct Foo;<|> 955struct Foo;$0
942impl Foo { 956impl Foo {
943 /// ``` 957 /// ```
944 /// let x = 5; 958 /// let x = 5;
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index ba0085244..f2d4da78d 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -1,35 +1,39 @@
1pub(crate) mod tags;
2
3mod highlights;
4mod injector;
5
6mod highlight;
1mod format; 7mod format;
2mod html;
3mod injection;
4mod macro_rules; 8mod macro_rules;
5pub(crate) mod tags; 9mod inject;
10
11mod html;
6#[cfg(test)] 12#[cfg(test)]
7mod tests; 13mod tests;
8 14
9use hir::{AsAssocItem, Local, Name, Semantics, VariantDef}; 15use hir::{Name, Semantics};
10use ide_db::{ 16use ide_db::RootDatabase;
11 defs::{Definition, NameClass, NameRefClass},
12 RootDatabase,
13};
14use rustc_hash::FxHashMap; 17use rustc_hash::FxHashMap;
15use syntax::{ 18use syntax::{
16 ast::{self, HasFormatSpecifier}, 19 ast::{self, HasFormatSpecifier},
17 AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, 20 AstNode, AstToken, Direction, NodeOrToken,
18 SyntaxKind::{self, *}, 21 SyntaxKind::*,
19 SyntaxNode, SyntaxToken, TextRange, WalkEvent, T, 22 SyntaxNode, TextRange, WalkEvent, T,
20}; 23};
21 24
22use crate::{ 25use crate::{
23 syntax_highlighting::{ 26 syntax_highlighting::{
24 format::FormatStringHighlighter, macro_rules::MacroRulesHighlighter, tags::Highlight, 27 format::highlight_format_string, highlights::Highlights,
28 macro_rules::MacroRulesHighlighter, tags::Highlight,
25 }, 29 },
26 FileId, HighlightModifier, HighlightTag, SymbolKind, 30 FileId, HlMod, HlTag, SymbolKind,
27}; 31};
28 32
29pub(crate) use html::highlight_as_html; 33pub(crate) use html::highlight_as_html;
30 34
31#[derive(Debug, Clone)] 35#[derive(Debug, Clone, Copy)]
32pub struct HighlightedRange { 36pub struct HlRange {
33 pub range: TextRange, 37 pub range: TextRange,
34 pub highlight: Highlight, 38 pub highlight: Highlight,
35 pub binding_hash: Option<u64>, 39 pub binding_hash: Option<u64>,
@@ -49,7 +53,7 @@ pub(crate) fn highlight(
49 file_id: FileId, 53 file_id: FileId,
50 range_to_highlight: Option<TextRange>, 54 range_to_highlight: Option<TextRange>,
51 syntactic_name_ref_highlighting: bool, 55 syntactic_name_ref_highlighting: bool,
52) -> Vec<HighlightedRange> { 56) -> Vec<HlRange> {
53 let _p = profile::span("highlight"); 57 let _p = profile::span("highlight");
54 let sema = Semantics::new(db); 58 let sema = Semantics::new(db);
55 59
@@ -68,28 +72,30 @@ pub(crate) fn highlight(
68 } 72 }
69 }; 73 };
70 74
75 let mut hl = highlights::Highlights::new(range_to_highlight);
76 traverse(&mut hl, &sema, &root, range_to_highlight, syntactic_name_ref_highlighting);
77 hl.to_vec()
78}
79
80fn traverse(
81 hl: &mut Highlights,
82 sema: &Semantics<RootDatabase>,
83 root: &SyntaxNode,
84 range_to_highlight: TextRange,
85 syntactic_name_ref_highlighting: bool,
86) {
71 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); 87 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
72 // We use a stack for the DFS traversal below.
73 // When we leave a node, the we use it to flatten the highlighted ranges.
74 let mut stack = HighlightedRangeStack::new();
75 88
76 let mut current_macro_call: Option<ast::MacroCall> = None; 89 let mut current_macro_call: Option<ast::MacroCall> = None;
77 let mut current_macro_rules: Option<ast::MacroRules> = None; 90 let mut current_macro_rules: Option<ast::MacroRules> = None;
78 let mut format_string_highlighter = FormatStringHighlighter::default();
79 let mut macro_rules_highlighter = MacroRulesHighlighter::default(); 91 let mut macro_rules_highlighter = MacroRulesHighlighter::default();
80 let mut inside_attribute = false; 92 let mut inside_attribute = false;
81 93
82 // Walk all nodes, keeping track of whether we are inside a macro or not. 94 // Walk all nodes, keeping track of whether we are inside a macro or not.
83 // If in macro, expand it first and highlight the expanded code. 95 // If in macro, expand it first and highlight the expanded code.
84 for event in root.preorder_with_tokens() { 96 for event in root.preorder_with_tokens() {
85 match &event {
86 WalkEvent::Enter(_) => stack.push(),
87 WalkEvent::Leave(_) => stack.pop(),
88 };
89
90 let event_range = match &event { 97 let event_range = match &event {
91 WalkEvent::Enter(it) => it.text_range(), 98 WalkEvent::Enter(it) | WalkEvent::Leave(it) => it.text_range(),
92 WalkEvent::Leave(it) => it.text_range(),
93 }; 99 };
94 100
95 // Element outside of the viewport, no need to highlight 101 // Element outside of the viewport, no need to highlight
@@ -101,9 +107,9 @@ pub(crate) fn highlight(
101 match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) { 107 match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) {
102 WalkEvent::Enter(Some(mc)) => { 108 WalkEvent::Enter(Some(mc)) => {
103 if let Some(range) = macro_call_range(&mc) { 109 if let Some(range) = macro_call_range(&mc) {
104 stack.add(HighlightedRange { 110 hl.add(HlRange {
105 range, 111 range,
106 highlight: HighlightTag::Symbol(SymbolKind::Macro).into(), 112 highlight: HlTag::Symbol(SymbolKind::Macro).into(),
107 binding_hash: None, 113 binding_hash: None,
108 }); 114 });
109 } 115 }
@@ -113,7 +119,6 @@ pub(crate) fn highlight(
113 WalkEvent::Leave(Some(mc)) => { 119 WalkEvent::Leave(Some(mc)) => {
114 assert_eq!(current_macro_call, Some(mc)); 120 assert_eq!(current_macro_call, Some(mc));
115 current_macro_call = None; 121 current_macro_call = None;
116 format_string_highlighter = FormatStringHighlighter::default();
117 } 122 }
118 _ => (), 123 _ => (),
119 } 124 }
@@ -131,33 +136,24 @@ pub(crate) fn highlight(
131 } 136 }
132 _ => (), 137 _ => (),
133 } 138 }
134
135 match &event { 139 match &event {
136 // Check for Rust code in documentation
137 WalkEvent::Leave(NodeOrToken::Node(node)) => {
138 if ast::Attr::can_cast(node.kind()) {
139 inside_attribute = false
140 }
141 if let Some((doctest, range_mapping, new_comments)) =
142 injection::extract_doc_comments(node)
143 {
144 injection::highlight_doc_comment(
145 doctest,
146 range_mapping,
147 new_comments,
148 &mut stack,
149 );
150 }
151 }
152 WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => { 140 WalkEvent::Enter(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
153 inside_attribute = true 141 inside_attribute = true
154 } 142 }
143 WalkEvent::Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
144 inside_attribute = false
145 }
155 _ => (), 146 _ => (),
156 } 147 }
157 148
158 let element = match event { 149 let element = match event {
159 WalkEvent::Enter(it) => it, 150 WalkEvent::Enter(it) => it,
160 WalkEvent::Leave(_) => continue, 151 WalkEvent::Leave(it) => {
152 if let Some(node) = it.as_node() {
153 inject::doc_comment(hl, node);
154 }
155 continue;
156 }
161 }; 157 };
162 158
163 let range = element.text_range(); 159 let range = element.text_range();
@@ -177,8 +173,6 @@ pub(crate) fn highlight(
177 let token = sema.descend_into_macros(token.clone()); 173 let token = sema.descend_into_macros(token.clone());
178 let parent = token.parent(); 174 let parent = token.parent();
179 175
180 format_string_highlighter.check_for_format_string(&parent);
181
182 // We only care Name and Name_ref 176 // We only care Name and Name_ref
183 match (token.kind(), parent.kind()) { 177 match (token.kind(), parent.kind()) {
184 (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), 178 (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(),
@@ -191,213 +185,45 @@ pub(crate) fn highlight(
191 if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) { 185 if let Some(token) = element.as_token().cloned().and_then(ast::String::cast) {
192 if token.is_raw() { 186 if token.is_raw() {
193 let expanded = element_to_highlight.as_token().unwrap().clone(); 187 let expanded = element_to_highlight.as_token().unwrap().clone();
194 if injection::highlight_injection(&mut stack, &sema, token, expanded).is_some() { 188 if inject::ra_fixture(hl, &sema, token, expanded).is_some() {
195 continue; 189 continue;
196 } 190 }
197 } 191 }
198 } 192 }
199 193
200 if let Some((mut highlight, binding_hash)) = highlight_element( 194 if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) {
195 continue;
196 }
197
198 if let Some((mut highlight, binding_hash)) = highlight::element(
201 &sema, 199 &sema,
202 &mut bindings_shadow_count, 200 &mut bindings_shadow_count,
203 syntactic_name_ref_highlighting, 201 syntactic_name_ref_highlighting,
204 element_to_highlight.clone(), 202 element_to_highlight.clone(),
205 ) { 203 ) {
206 if inside_attribute { 204 if inside_attribute {
207 highlight = highlight | HighlightModifier::Attribute; 205 highlight = highlight | HlMod::Attribute;
208 }
209
210 if macro_rules_highlighter.highlight(element_to_highlight.clone()).is_none() {
211 stack.add(HighlightedRange { range, highlight, binding_hash });
212 } 206 }
213 207
214 if let Some(string) = 208 hl.add(HlRange { range, highlight, binding_hash });
215 element_to_highlight.as_token().cloned().and_then(ast::String::cast)
216 {
217 format_string_highlighter.highlight_format_string(&mut stack, &string, range);
218 // Highlight escape sequences
219 if let Some(char_ranges) = string.char_ranges() {
220 stack.push();
221 for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) {
222 if string.text()[piece_range.start().into()..].starts_with('\\') {
223 stack.add(HighlightedRange {
224 range: piece_range + range.start(),
225 highlight: HighlightTag::EscapeSequence.into(),
226 binding_hash: None,
227 });
228 }
229 }
230 stack.pop_and_inject(None);
231 }
232 }
233 } 209 }
234 }
235
236 stack.flattened()
237}
238
239#[derive(Debug)]
240struct HighlightedRangeStack {
241 stack: Vec<Vec<HighlightedRange>>,
242}
243
244/// We use a stack to implement the flattening logic for the highlighted
245/// syntax ranges.
246impl HighlightedRangeStack {
247 fn new() -> Self {
248 Self { stack: vec![Vec::new()] }
249 }
250
251 fn push(&mut self) {
252 self.stack.push(Vec::new());
253 }
254
255 /// Flattens the highlighted ranges.
256 ///
257 /// For example `#[cfg(feature = "foo")]` contains the nested ranges:
258 /// 1) parent-range: Attribute [0, 23)
259 /// 2) child-range: String [16, 21)
260 ///
261 /// The following code implements the flattening, for our example this results to:
262 /// `[Attribute [0, 16), String [16, 21), Attribute [21, 23)]`
263 fn pop(&mut self) {
264 let children = self.stack.pop().unwrap();
265 let prev = self.stack.last_mut().unwrap();
266 let needs_flattening = !children.is_empty()
267 && !prev.is_empty()
268 && prev.last().unwrap().range.contains_range(children.first().unwrap().range);
269 if !needs_flattening {
270 prev.extend(children);
271 } else {
272 let mut parent = prev.pop().unwrap();
273 for ele in children {
274 assert!(parent.range.contains_range(ele.range));
275
276 let cloned = Self::intersect(&mut parent, &ele);
277 if !parent.range.is_empty() {
278 prev.push(parent);
279 }
280 prev.push(ele);
281 parent = cloned;
282 }
283 if !parent.range.is_empty() {
284 prev.push(parent);
285 }
286 }
287 }
288
289 /// Intersects the `HighlightedRange` `parent` with `child`.
290 /// `parent` is mutated in place, becoming the range before `child`.
291 /// Returns the range (of the same type as `parent`) *after* `child`.
292 fn intersect(parent: &mut HighlightedRange, child: &HighlightedRange) -> HighlightedRange {
293 assert!(parent.range.contains_range(child.range));
294
295 let mut cloned = parent.clone();
296 parent.range = TextRange::new(parent.range.start(), child.range.start());
297 cloned.range = TextRange::new(child.range.end(), cloned.range.end());
298 210
299 cloned 211 if let Some(string) = element_to_highlight.as_token().cloned().and_then(ast::String::cast) {
300 } 212 highlight_format_string(hl, &string, range);
301 213 // Highlight escape sequences
302 /// Remove the `HighlightRange` of `parent` that's currently covered by `child`. 214 if let Some(char_ranges) = string.char_ranges() {
303 fn intersect_partial(parent: &mut HighlightedRange, child: &HighlightedRange) { 215 for (piece_range, _) in char_ranges.iter().filter(|(_, char)| char.is_ok()) {
304 assert!( 216 if string.text()[piece_range.start().into()..].starts_with('\\') {
305 parent.range.start() <= child.range.start() 217 hl.add(HlRange {
306 && parent.range.end() >= child.range.start() 218 range: piece_range + range.start(),
307 && child.range.end() > parent.range.end() 219 highlight: HlTag::EscapeSequence.into(),
308 ); 220 binding_hash: None,
309 221 });
310 parent.range = TextRange::new(parent.range.start(), child.range.start());
311 }
312
313 /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`)
314 /// can only modify the last range currently on the stack.
315 /// Can be used to do injections that span multiple ranges, like the
316 /// doctest injection below.
317 /// If `overwrite_parent` is non-optional, the highlighting of the parent range
318 /// is overwritten with the argument.
319 ///
320 /// Note that `pop` can be simulated by `pop_and_inject(false)` but the
321 /// latter is computationally more expensive.
322 fn pop_and_inject(&mut self, overwrite_parent: Option<Highlight>) {
323 let mut children = self.stack.pop().unwrap();
324 let prev = self.stack.last_mut().unwrap();
325 children.sort_by_key(|range| range.range.start());
326 prev.sort_by_key(|range| range.range.start());
327
328 for child in children {
329 if let Some(idx) =
330 prev.iter().position(|parent| parent.range.contains_range(child.range))
331 {
332 if let Some(tag) = overwrite_parent {
333 prev[idx].highlight = tag;
334 }
335
336 let cloned = Self::intersect(&mut prev[idx], &child);
337 let insert_idx = if prev[idx].range.is_empty() {
338 prev.remove(idx);
339 idx
340 } else {
341 idx + 1
342 };
343 prev.insert(insert_idx, child);
344 if !cloned.range.is_empty() {
345 prev.insert(insert_idx + 1, cloned);
346 }
347 } else {
348 let maybe_idx =
349 prev.iter().position(|parent| parent.range.contains(child.range.start()));
350 match (overwrite_parent, maybe_idx) {
351 (Some(_), Some(idx)) => {
352 Self::intersect_partial(&mut prev[idx], &child);
353 let insert_idx = if prev[idx].range.is_empty() {
354 prev.remove(idx);
355 idx
356 } else {
357 idx + 1
358 };
359 prev.insert(insert_idx, child);
360 }
361 (_, None) => {
362 let idx = prev
363 .binary_search_by_key(&child.range.start(), |range| range.range.start())
364 .unwrap_or_else(|x| x);
365 prev.insert(idx, child);
366 }
367 _ => {
368 unreachable!("child range should be completely contained in parent range");
369 } 222 }
370 } 223 }
371 } 224 }
372 } 225 }
373 } 226 }
374
375 fn add(&mut self, range: HighlightedRange) {
376 self.stack
377 .last_mut()
378 .expect("during DFS traversal, the stack must not be empty")
379 .push(range)
380 }
381
382 fn flattened(mut self) -> Vec<HighlightedRange> {
383 assert_eq!(
384 self.stack.len(),
385 1,
386 "after DFS traversal, the stack should only contain a single element"
387 );
388 let mut res = self.stack.pop().unwrap();
389 res.sort_by_key(|range| range.range.start());
390 // Check that ranges are sorted and disjoint
391 for (left, right) in res.iter().zip(res.iter().skip(1)) {
392 assert!(
393 left.range.end() <= right.range.start(),
394 "left: {:#?}, right: {:#?}",
395 left,
396 right
397 );
398 }
399 res
400 }
401} 227}
402 228
403fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { 229fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
@@ -415,524 +241,3 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
415 241
416 Some(TextRange::new(range_start, range_end)) 242 Some(TextRange::new(range_start, range_end))
417} 243}
418
419/// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly.