aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/call_hierarchy.rs73
-rw-r--r--crates/ide/src/diagnostics.rs97
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs8
-rw-r--r--crates/ide/src/diagnostics/fixes.rs13
-rw-r--r--crates/ide/src/display/navigation_target.rs14
-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.rs108
-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.rs237
-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.rs290
-rw-r--r--crates/ide/src/inlay_hints.rs46
-rw-r--r--crates/ide/src/join_lines.rs136
-rw-r--r--crates/ide/src/lib.rs16
-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.rs167
-rw-r--r--crates/ide/src/references/rename.rs433
-rw-r--r--crates/ide/src/runnables.rs151
-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.rs530
-rw-r--r--crates/ide/src/syntax_highlighting/highlights.rs102
-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.rs80
-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.rs20
-rw-r--r--crates/ide/src/typing.rs30
-rw-r--r--crates/ide/src/typing/on_enter.rs18
45 files changed, 2584 insertions, 2256 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..055c0a79c 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -125,7 +125,7 @@ pub(crate) fn diagnostics(
125 .on::<hir::diagnostics::MissingFields, _>(|d| { 125 .on::<hir::diagnostics::MissingFields, _>(|d| {
126 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 126 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
127 }) 127 })
128 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { 128 .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| {
129 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 129 res.borrow_mut().push(diagnostic_with_fix(d, &sema));
130 }) 130 })
131 .on::<hir::diagnostics::NoSuchField, _>(|d| { 131 .on::<hir::diagnostics::NoSuchField, _>(|d| {
@@ -305,6 +305,40 @@ mod tests {
305 } 305 }
306 306
307 #[test] 307 #[test]
308 fn test_wrap_return_type_option() {
309 check_fix(
310 r#"
311//- /main.rs crate:main deps:core
312use core::option::Option::{self, Some, None};
313
314fn div(x: i32, y: i32) -> Option<i32> {
315 if y == 0 {
316 return None;
317 }
318 x / y$0
319}
320//- /core/lib.rs crate:core
321pub mod result {
322 pub enum Result<T, E> { Ok(T), Err(E) }
323}
324pub mod option {
325 pub enum Option<T> { Some(T), None }
326}
327"#,
328 r#"
329use core::option::Option::{self, Some, None};
330
331fn div(x: i32, y: i32) -> Option<i32> {
332 if y == 0 {
333 return None;
334 }
335 Some(x / y)
336}
337"#,
338 );
339 }
340
341 #[test]
308 fn test_wrap_return_type() { 342 fn test_wrap_return_type() {
309 check_fix( 343 check_fix(
310 r#" 344 r#"
@@ -315,12 +349,15 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
315 if y == 0 { 349 if y == 0 {
316 return Err(()); 350 return Err(());
317 } 351 }
318 x / y<|> 352 x / y$0
319} 353}
320//- /core/lib.rs crate:core 354//- /core/lib.rs crate:core
321pub mod result { 355pub mod result {
322 pub enum Result<T, E> { Ok(T), Err(E) } 356 pub enum Result<T, E> { Ok(T), Err(E) }
323} 357}
358pub mod option {
359 pub enum Option<T> { Some(T), None }
360}
324"#, 361"#,
325 r#" 362 r#"
326use core::result::Result::{self, Ok, Err}; 363use core::result::Result::{self, Ok, Err};
@@ -346,12 +383,15 @@ fn div<T>(x: T) -> Result<T, i32> {
346 if x == 0 { 383 if x == 0 {
347 return Err(7); 384 return Err(7);
348 } 385 }
349 <|>x 386 $0x
350} 387}
351//- /core/lib.rs crate:core 388//- /core/lib.rs crate:core
352pub mod result { 389pub mod result {
353 pub enum Result<T, E> { Ok(T), Err(E) } 390 pub enum Result<T, E> { Ok(T), Err(E) }
354} 391}
392pub mod option {
393 pub enum Option<T> { Some(T), None }
394}
355"#, 395"#,
356 r#" 396 r#"
357use core::result::Result::{self, Ok, Err}; 397use core::result::Result::{self, Ok, Err};
@@ -379,12 +419,15 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
379 if y == 0 { 419 if y == 0 {
380 return Err(()); 420 return Err(());
381 } 421 }
382 x <|>/ y 422 x $0/ y
383} 423}
384//- /core/lib.rs crate:core 424//- /core/lib.rs crate:core
385pub mod result { 425pub mod result {
386 pub enum Result<T, E> { Ok(T), Err(E) } 426 pub enum Result<T, E> { Ok(T), Err(E) }
387} 427}
428pub mod option {
429 pub enum Option<T> { Some(T), None }
430}
388"#, 431"#,
389 r#" 432 r#"
390use core::result::Result::{self, Ok, Err}; 433use core::result::Result::{self, Ok, Err};
@@ -414,12 +457,15 @@ fn foo() -> Result<(), i32> { 0 }
414pub mod result { 457pub mod result {
415 pub enum Result<T, E> { Ok(T), Err(E) } 458 pub enum Result<T, E> { Ok(T), Err(E) }
416} 459}
460pub mod option {
461 pub enum Option<T> { Some(T), None }
462}
417"#, 463"#,
418 ); 464 );
419 } 465 }
420 466
421 #[test] 467 #[test]
422 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { 468 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
423 check_no_diagnostics( 469 check_no_diagnostics(
424 r#" 470 r#"
425//- /main.rs crate:main deps:core 471//- /main.rs crate:main deps:core
@@ -433,6 +479,9 @@ fn foo() -> SomeOtherEnum { 0 }
433pub mod result { 479pub mod result {
434 pub enum Result<T, E> { Ok(T), Err(E) } 480 pub enum Result<T, E> { Ok(T), Err(E) }
435} 481}
482pub mod option {
483 pub enum Option<T> { Some(T), None }
484}
436"#, 485"#,
437 ); 486 );
438 } 487 }
@@ -444,7 +493,7 @@ pub mod result {
444struct TestStruct { one: i32, two: i64 } 493struct TestStruct { one: i32, two: i64 }
445 494
446fn test_fn() { 495fn test_fn() {
447 let s = TestStruct {<|>}; 496 let s = TestStruct {$0};
448} 497}
449"#, 498"#,
450 r#" 499 r#"
@@ -464,7 +513,7 @@ fn test_fn() {
464struct TestStruct { one: i32 } 513struct TestStruct { one: i32 }
465 514
466impl TestStruct { 515impl TestStruct {
467 fn test_fn() { let s = Self {<|>}; } 516 fn test_fn() { let s = Self {$0}; }
468} 517}
469"#, 518"#,
470 r#" 519 r#"
@@ -487,7 +536,7 @@ enum Expr {
487 536
488impl Expr { 537impl Expr {
489 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { 538 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
490 Expr::Bin {<|> } 539 Expr::Bin {$0 }
491 } 540 }
492} 541}
493"#, 542"#,
@@ -512,7 +561,7 @@ impl Expr {
512struct TestStruct { one: i32, two: i64 } 561struct TestStruct { one: i32, two: i64 }
513 562
514fn test_fn() { 563fn test_fn() {
515 let s = TestStruct{ two: 2<|> }; 564 let s = TestStruct{ two: 2$0 };
516} 565}
517"#, 566"#,
518 r" 567 r"
@@ -608,7 +657,7 @@ fn here() {}
608macro_rules! id { ($($tt:tt)*) => { $($tt)*}; } 657macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
609 658
610fn main() { 659fn main() {
611 let _x = id![Foo { a: <|>42 }]; 660 let _x = id![Foo { a: $042 }];
612} 661}
613 662
614pub struct Foo { pub a: i32, pub b: i32 } 663pub struct Foo { pub a: i32, pub b: i32 }
@@ -663,7 +712,7 @@ mod a {
663 check_fix( 712 check_fix(
664 r" 713 r"
665 mod b {} 714 mod b {}
666 use {<|>b}; 715 use {$0b};
667 ", 716 ",
668 r" 717 r"
669 mod b {} 718 mod b {}
@@ -673,7 +722,7 @@ mod a {
673 check_fix( 722 check_fix(
674 r" 723 r"
675 mod b {} 724 mod b {}
676 use {b<|>}; 725 use {b$0};
677 ", 726 ",
678 r" 727 r"
679 mod b {} 728 mod b {}
@@ -683,7 +732,7 @@ mod a {
683 check_fix( 732 check_fix(
684 r" 733 r"
685 mod a { mod c {} } 734 mod a { mod c {} }
686 use a::{c<|>}; 735 use a::{c$0};
687 ", 736 ",
688 r" 737 r"
689 mod a { mod c {} } 738 mod a { mod c {} }
@@ -693,7 +742,7 @@ mod a {
693 check_fix( 742 check_fix(
694 r" 743 r"
695 mod a {} 744 mod a {}
696 use a::{self<|>}; 745 use a::{self$0};
697 ", 746 ",
698 r" 747 r"
699 mod a {} 748 mod a {}
@@ -703,7 +752,7 @@ mod a {
703 check_fix( 752 check_fix(
704 r" 753 r"
705 mod a { mod c {} mod d { mod e {} } } 754 mod a { mod c {} mod d { mod e {} } }
706 use a::{c, d::{e<|>}}; 755 use a::{c, d::{e$0}};
707 ", 756 ",
708 r" 757 r"
709 mod a { mod c {} mod d { mod e {} } } 758 mod a { mod c {} mod d { mod e {} } }
@@ -717,7 +766,7 @@ mod a {
717 check_fix( 766 check_fix(
718 r" 767 r"
719fn main() { 768fn main() {
720 Foo { bar: 3, baz<|>: false}; 769 Foo { bar: 3, baz$0: false};
721} 770}
722struct Foo { 771struct Foo {
723 bar: i32 772 bar: i32
@@ -743,7 +792,7 @@ struct Foo {
743mod foo; 792mod foo;
744 793
745fn main() { 794fn main() {
746 foo::Foo { bar: 3, <|>baz: false}; 795 foo::Foo { bar: 3, $0baz: false};
747} 796}
748//- /foo.rs 797//- /foo.rs
749struct Foo { 798struct Foo {
@@ -777,7 +826,7 @@ struct Foo {
777 fn test_rename_incorrect_case() { 826 fn test_rename_incorrect_case() {
778 check_fix( 827 check_fix(
779 r#" 828 r#"
780pub struct test_struct<|> { one: i32 } 829pub struct test_struct$0 { one: i32 }
781 830
782pub fn some_fn(val: test_struct) -> test_struct { 831pub fn some_fn(val: test_struct) -> test_struct {
783 test_struct { one: val.one + 1 } 832 test_struct { one: val.one + 1 }
@@ -794,7 +843,7 @@ pub fn some_fn(val: TestStruct) -> TestStruct {
794 843
795 check_fix( 844 check_fix(
796 r#" 845 r#"
797pub fn some_fn(NonSnakeCase<|>: u8) -> u8 { 846pub fn some_fn(NonSnakeCase$0: u8) -> u8 {
798 NonSnakeCase 847 NonSnakeCase
799} 848}
800"#, 849"#,
@@ -807,7 +856,7 @@ pub fn some_fn(non_snake_case: u8) -> u8 {
807 856
808 check_fix( 857 check_fix(
809 r#" 858 r#"
810pub fn SomeFn<|>(val: u8) -> u8 { 859pub fn SomeFn$0(val: u8) -> u8 {
811 if val != 0 { SomeFn(val - 1) } else { val } 860 if val != 0 { SomeFn(val - 1) } else { val }
812} 861}
813"#, 862"#,
@@ -821,7 +870,7 @@ pub fn some_fn(val: u8) -> u8 {
821 check_fix( 870 check_fix(
822 r#" 871 r#"
823fn some_fn() { 872fn some_fn() {
824 let whatAWeird_Formatting<|> = 10; 873 let whatAWeird_Formatting$0 = 10;
825 another_func(whatAWeird_Formatting); 874 another_func(whatAWeird_Formatting);
826} 875}
827"#, 876"#,
@@ -839,7 +888,7 @@ fn some_fn() {
839 check_no_diagnostics( 888 check_no_diagnostics(
840 r#" 889 r#"
841fn foo() { 890fn foo() {
842 const ANOTHER_ITEM<|>: &str = "some_item"; 891 const ANOTHER_ITEM$0: &str = "some_item";
843} 892}
844"#, 893"#,
845 ); 894 );
@@ -852,7 +901,7 @@ fn foo() {
852pub struct TestStruct; 901pub struct TestStruct;
853 902
854impl TestStruct { 903impl TestStruct {
855 pub fn SomeFn<|>() -> TestStruct { 904 pub fn SomeFn$0() -> TestStruct {
856 TestStruct 905 TestStruct
857 } 906 }
858} 907}
@@ -871,7 +920,7 @@ impl TestStruct {
871 920
872 #[test] 921 #[test]
873 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { 922 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
874 let input = r#"fn FOO<|>() {}"#; 923 let input = r#"fn FOO$0() {}"#;
875 let expected = r#"fn foo() {}"#; 924 let expected = r#"fn foo() {}"#;
876 925
877 let (analysis, file_position) = fixture::position(input); 926 let (analysis, file_position) = fixture::position(input);
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs
index f41bcd619..16c6ea827 100644
--- a/crates/ide/src/diagnostics/field_shorthand.rs
+++ b/crates/ide/src/diagnostics/field_shorthand.rs
@@ -120,7 +120,7 @@ fn main() { A { 0: 0 } }
120struct A { a: &'static str } 120struct A { a: &'static str }
121fn main() { 121fn main() {
122 let a = "haha"; 122 let a = "haha";
123 A { a<|>: a } 123 A { a$0: a }
124} 124}
125"#, 125"#,
126 r#" 126 r#"
@@ -138,7 +138,7 @@ struct A { a: &'static str, b: &'static str }
138fn main() { 138fn main() {
139 let a = "haha"; 139 let a = "haha";
140 let b = "bb"; 140 let b = "bb";
141 A { a<|>: a, b } 141 A { a$0: a, b }
142} 142}
143"#, 143"#,
144 r#" 144 r#"
@@ -171,7 +171,7 @@ fn f(a: A) { let A { 0: 0 } = a; }
171 r#" 171 r#"
172struct A { a: &'static str } 172struct A { a: &'static str }
173fn f(a: A) { 173fn f(a: A) {
174 let A { a<|>: a } = a; 174 let A { a$0: a } = a;
175} 175}
176"#, 176"#,
177 r#" 177 r#"
@@ -186,7 +186,7 @@ fn f(a: A) {
186 r#" 186 r#"
187struct A { a: &'static str, b: &'static str } 187struct A { a: &'static str, b: &'static str }
188fn f(a: A) { 188fn f(a: A) {
189 let A { a<|>: a, b } = a; 189 let A { a$0: a, b } = a;
190} 190}
191"#, 191"#,
192 r#" 192 r#"
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index ec0f840e9..d7ad88ed5 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -3,7 +3,7 @@
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,
@@ -94,15 +94,17 @@ impl DiagnosticWithFix for MissingFields {
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 edit = TextEdit::replace(tail_expr_range, replacement);
103 let source_change = 104 let source_change =
104 SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); 105 SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
105 Some(Fix::new("Wrap with ok", source_change, tail_expr_range)) 106 let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
107 Some(Fix::new(name, source_change, tail_expr_range))
106 } 108 }
107} 109}
108 110
@@ -156,7 +158,6 @@ fn missing_record_expr_field_fix(
156 let record_fields = match VariantDef::from(def_id) { 158 let record_fields = match VariantDef::from(def_id) {
157 VariantDef::Struct(s) => { 159 VariantDef::Struct(s) => {
158 module = s.module(sema.db); 160 module = s.module(sema.db);
159 #[allow(deprecated)]
160 let source = s.source(sema.db)?; 161 let source = s.source(sema.db)?;
161 def_file_id = source.file_id; 162 def_file_id = source.file_id;
162 let fields = source.value.field_list()?; 163 let fields = source.value.field_list()?;
@@ -164,14 +165,12 @@ fn missing_record_expr_field_fix(
164 } 165 }
165 VariantDef::Union(u) => { 166 VariantDef::Union(u) => {
166 module = u.module(sema.db); 167 module = u.module(sema.db);
167 #[allow(deprecated)]
168 let source = u.source(sema.db)?; 168 let source = u.source(sema.db)?;
169 def_file_id = source.file_id; 169 def_file_id = source.file_id;
170 source.value.record_field_list()? 170 source.value.record_field_list()?
171 } 171 }
172 VariantDef::Variant(e) => { 172 VariantDef::Variant(e) => {
173 module = e.module(sema.db); 173 module = e.module(sema.db);
174 #[allow(deprecated)]
175 let source = e.source(sema.db)?; 174 let source = e.source(sema.db)?;
176 def_file_id = source.file_id; 175 def_file_id = source.file_id;
177 let fields = source.value.field_list()?; 176 let fields = source.value.field_list()?;
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index e24c78301..4eecae697 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,6 +387,16 @@ 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);
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..56418c960 100644
--- a/crates/ide/src/extend_selection.rs
+++ b/crates/ide/src/extend_selection.rs
@@ -334,29 +334,29 @@ mod tests {
334 334
335 #[test] 335 #[test]
336 fn test_extend_selection_arith() { 336 fn test_extend_selection_arith() {
337 do_check(r#"fn foo() { <|>1 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); 337 do_check(r#"fn foo() { $01 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]);
338 } 338 }
339 339
340 #[test] 340 #[test]
341 fn test_extend_selection_list() { 341 fn test_extend_selection_list() {
342 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]); 342 do_check(r#"fn foo($0x: i32) {}"#, &["x", "x: i32"]);
343 do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); 343 do_check(r#"fn foo($0x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]);
344 do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]); 344 do_check(r#"fn foo($0x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]);
345 do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]); 345 do_check(r#"fn foo(x: i32, $0y: i32) {}"#, &["y", "y: i32", ", y: i32"]);
346 do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]); 346 do_check(r#"fn foo(x: i32, $0y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]);
347 do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]); 347 do_check(r#"fn foo(x: i32,$0y: i32) {}"#, &["y", "y: i32", ",y: i32"]);
348 348
349 do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]); 349 do_check(r#"const FOO: [usize; 2] = [ 22$0 , 33];"#, &["22", "22 , "]);
350 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); 350 do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0];"#, &["33", ", 33"]);
351 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]); 351 do_check(r#"const FOO: [usize; 2] = [ 22 , 33$0 ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]);
352 352
353 do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]); 353 do_check(r#"fn main() { (1, 2$0) }"#, &["2", ", 2", "(1, 2)"]);
354 354
355 do_check( 355 do_check(
356 r#" 356 r#"
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..cd4afc804 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,14 +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 base_db::FileId,
5 defs::{NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
6 symbol_index, RootDatabase, 6 symbol_index, RootDatabase,
7}; 7};
8use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 8use syntax::{
9 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T,
10};
9 11
10use crate::{ 12use crate::{
11 display::{ToNav, TryToNav}, 13 display::{ToNav, TryToNav},
14 doc_links::extract_definitions_from_markdown,
15 runnables::doc_owner_to_def,
12 FilePosition, NavigationTarget, RangeInfo, SymbolKind, 16 FilePosition, NavigationTarget, RangeInfo, SymbolKind,
13}; 17};
14 18
@@ -30,6 +34,10 @@ pub(crate) fn goto_definition(
30 let original_token = pick_best(file.token_at_offset(position.offset))?; 34 let original_token = pick_best(file.token_at_offset(position.offset))?;
31 let token = sema.descend_into_macros(original_token.clone()); 35 let token = sema.descend_into_macros(original_token.clone());
32 let parent = token.parent(); 36 let parent = token.parent();
37 if let Some(comment) = ast::Comment::cast(token.clone()) {
38 let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?;
39 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
40 }
33 41
34 let nav_targets = match_ast! { 42 let nav_targets = match_ast! {
35 match parent { 43 match parent {
@@ -68,11 +76,58 @@ pub(crate) fn goto_definition(
68 Some(RangeInfo::new(original_token.text_range(), nav_targets)) 76 Some(RangeInfo::new(original_token.text_range(), nav_targets))
69} 77}
70 78
79fn def_for_doc_comment(
80 sema: &Semantics<RootDatabase>,
81 position: FilePosition,
82 doc_comment: &ast::Comment,
83) -> Option<hir::ModuleDef> {
84 let parent = doc_comment.syntax().parent();
85 let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?;
86
87 let def = doc_owner_to_def(sema, parent)?;
88 match def {
89 Definition::ModuleDef(def) => match def {
90 ModuleDef::Module(it) => it.resolve_doc_path(sema.db, &link, ns),
91 ModuleDef::Function(it) => it.resolve_doc_path(sema.db, &link, ns),
92 ModuleDef::Adt(it) => it.resolve_doc_path(sema.db, &link, ns),
93 ModuleDef::Variant(it) => it.resolve_doc_path(sema.db, &link, ns),
94 ModuleDef::Const(it) => it.resolve_doc_path(sema.db, &link, ns),
95 ModuleDef::Static(it) => it.resolve_doc_path(sema.db, &link, ns),
96 ModuleDef::Trait(it) => it.resolve_doc_path(sema.db, &link, ns),
97 ModuleDef::TypeAlias(it) => it.resolve_doc_path(sema.db, &link, ns),
98 ModuleDef::BuiltinType(_) => return None,
99 },
100 Definition::Macro(it) => it.resolve_doc_path(sema.db, &link, ns),
101 Definition::Field(it) => it.resolve_doc_path(sema.db, &link, ns),
102 Definition::SelfType(_)
103 | Definition::Local(_)
104 | Definition::GenericParam(_)
105 | Definition::Label(_) => return None,
106 }
107}
108
109fn extract_positioned_link_from_comment(
110 position: FilePosition,
111 comment: &ast::Comment,
112) -> Option<(String, Option<hir::Namespace>)> {
113 let comment_range = comment.syntax().text_range();
114 let doc_comment = comment.doc_comment()?;
115 let def_links = extract_definitions_from_markdown(doc_comment);
116 let (def_link, ns, _) = def_links.iter().min_by_key(|(_, _, def_link_range)| {
117 let matched_position = comment_range.start() + TextSize::from(def_link_range.start as u32);
118 match position.offset.checked_sub(matched_position) {
119 Some(distance) => distance,
120 None => comment_range.end(),
121 }
122 })?;
123 Some((def_link.to_string(), ns.clone()))
124}
125
71fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 126fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
72 return tokens.max_by_key(priority); 127 return tokens.max_by_key(priority);
73 fn priority(n: &SyntaxToken) -> usize { 128 fn priority(n: &SyntaxToken) -> usize {
74 match n.kind() { 129 match n.kind() {
75 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 2, 130 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | COMMENT => 2,
76 kind if kind.is_trivia() => 0, 131 kind if kind.is_trivia() => 0,
77 _ => 1, 132 _ => 1,
78 } 133 }
@@ -166,7 +221,7 @@ mod tests {
166 check( 221 check(
167 r#" 222 r#"
168 //- /main.rs crate:main deps:std 223 //- /main.rs crate:main deps:std
169 extern crate std<|>; 224 extern crate std$0;
170 //- /std/lib.rs crate:std 225 //- /std/lib.rs crate:std
171 // empty 226 // empty
172 //^ file 227 //^ file
@@ -179,7 +234,7 @@ mod tests {
179 check( 234 check(
180 r#" 235 r#"
181 //- /main.rs crate:main deps:std 236 //- /main.rs crate:main deps:std
182 extern crate std as abc<|>; 237 extern crate std as abc$0;
183 //- /std/lib.rs crate:std 238 //- /std/lib.rs crate:std
184 // empty 239 // empty
185 //^ file 240 //^ file
@@ -193,7 +248,7 @@ mod tests {
193 r#" 248 r#"
194struct Foo; 249struct Foo;
195 //^^^ 250 //^^^
196enum E { X(Foo<|>) } 251enum E { X(Foo$0) }
197"#, 252"#,
198 ); 253 );
199 } 254 }
@@ -204,7 +259,7 @@ enum E { X(Foo<|>) }
204 r#" 259 r#"
205struct Foo; 260struct Foo;
206 //^^^ 261 //^^^
207enum E { X(<|>Foo) } 262enum E { X($0Foo) }
208"#, 263"#,
209 ); 264 );
210 } 265 }
@@ -217,7 +272,7 @@ enum E { X(<|>Foo) }
217use a::Foo; 272use a::Foo;
218mod a; 273mod a;
219mod b; 274mod b;
220enum E { X(Foo<|>) } 275enum E { X(Foo$0) }
221 276
222//- /a.rs 277//- /a.rs
223struct Foo; 278struct Foo;
@@ -233,7 +288,7 @@ struct Foo;
233 check( 288 check(
234 r#" 289 r#"
235//- /lib.rs 290//- /lib.rs
236mod <|>foo; 291mod $0foo;
237 292
238//- /foo.rs 293//- /foo.rs
239// empty 294// empty
@@ -244,7 +299,7 @@ mod <|>foo;
244 check( 299 check(
245 r#" 300 r#"
246//- /lib.rs 301//- /lib.rs
247mod <|>foo; 302mod $0foo;
248 303
249//- /foo/mod.rs 304//- /foo/mod.rs
250// empty 305// empty
@@ -260,7 +315,7 @@ mod <|>foo;
260macro_rules! foo { () => { () } } 315macro_rules! foo { () => { () } }
261 //^^^ 316 //^^^
262fn bar() { 317fn bar() {
263 <|>foo!(); 318 $0foo!();
264} 319}
265"#, 320"#,
266 ); 321 );
@@ -273,7 +328,7 @@ fn bar() {
273//- /lib.rs 328//- /lib.rs
274use foo::foo; 329use foo::foo;
275fn bar() { 330fn bar() {
276 <|>foo!(); 331 $0foo!();
277} 332}
278 333
279//- /foo/lib.rs 334//- /foo/lib.rs
@@ -289,7 +344,7 @@ macro_rules! foo { () => { () } }
289 check( 344 check(
290 r#" 345 r#"
291//- /lib.rs 346//- /lib.rs
292use foo::foo<|>; 347use foo::foo$0;
293 348
294//- /foo/lib.rs 349//- /foo/lib.rs
295#[macro_export] 350#[macro_export]
@@ -312,7 +367,7 @@ define_fn!(foo);
312 //^^^ 367 //^^^
313 368
314fn bar() { 369fn bar() {
315 <|>foo(); 370 $0foo();
316} 371}
317"#, 372"#,
318 ); 373 );
@@ -331,7 +386,7 @@ macro_rules! define_fn {
331//^^^^^^^^^^^^^ 386//^^^^^^^^^^^^^
332 387
333fn bar() { 388fn bar() {
334 <|>foo(); 389 $0foo();
335} 390}
336"#, 391"#,
337 ); 392 );
@@ -347,7 +402,7 @@ macro_rules! foo {() => {0}}
347 402
348fn bar() { 403fn bar() {
349 match (0,1) { 404 match (0,1) {
350 (<|>foo!(), _) => {} 405 ($0foo!(), _) => {}
351 } 406 }
352} 407}
353"#, 408"#,
@@ -363,7 +418,7 @@ macro_rules! foo {() => {0}}
363 //^^^ 418 //^^^
364fn bar() { 419fn bar() {
365 match 0 { 420 match 0 {
366 <|>foo!() => {} 421 $0foo!() => {}
367 } 422 }
368} 423}
369"#, 424"#,
@@ -375,7 +430,7 @@ fn bar() {
375 check( 430 check(
376 r#" 431 r#"
377//- /lib.rs crate:main deps:foo 432//- /lib.rs crate:main deps:foo
378use foo as bar<|>; 433use foo as bar$0;
379 434
380//- /foo/lib.rs crate:foo 435//- /foo/lib.rs crate:foo
381// empty 436// empty
@@ -389,7 +444,7 @@ use foo as bar<|>;
389 check( 444 check(
390 r#" 445 r#"
391//- /lib.rs crate:main deps:foo 446//- /lib.rs crate:main deps:foo
392use foo::foo as bar<|>; 447use foo::foo as bar$0;
393 448
394//- /foo/lib.rs crate:foo 449//- /foo/lib.rs crate:foo
395#[macro_export] 450#[macro_export]
@@ -410,7 +465,7 @@ impl Foo {
410} 465}
411 466
412fn bar(foo: &Foo) { 467fn bar(foo: &Foo) {
413 foo.frobnicate<|>(); 468 foo.frobnicate$0();
414} 469}
415"#, 470"#,
416 ); 471 );
@@ -425,7 +480,7 @@ struct Foo {
425} //^^^^ 480} //^^^^
426 481
427fn bar(foo: &Foo) { 482fn bar(foo: &Foo) {
428 foo.spam<|>; 483 foo.spam$0;
429} 484}
430"#, 485"#,
431 ); 486 );
@@ -442,7 +497,7 @@ struct Foo {
442 497
443fn bar() -> Foo { 498fn bar() -> Foo {
444 Foo { 499 Foo {
445 spam<|>: 0, 500 spam$0: 0,
446 } 501 }
447} 502}
448"#, 503"#,
@@ -459,7 +514,7 @@ struct Foo {
459} //^^^^ 514} //^^^^
460 515
461fn bar(foo: Foo) -> Foo { 516fn bar(foo: Foo) -> Foo {
462 let Foo { spam<|>: _, } = foo 517 let Foo { spam$0: _, } = foo
463} 518}
464"#, 519"#,
465 ); 520 );
@@ -474,7 +529,7 @@ struct Foo { spam: u32 }
474 //^^^^ 529 //^^^^
475 530
476fn bar() -> Foo { 531fn bar() -> Foo {
477 Foo { spam<|>: m!() } 532 Foo { spam$0: m!() }
478} 533}
479", 534",
480 ); 535 );
@@ -489,7 +544,7 @@ struct Foo(u32);
489 544
490fn bar() { 545fn bar() {
491 let foo = Foo(0); 546 let foo = Foo(0);
492 foo.<|>0; 547 foo.$00;
493} 548}
494"#, 549"#,
495 ); 550 );
@@ -505,7 +560,7 @@ impl Foo {
505} //^^^^^^^^^^ 560} //^^^^^^^^^^
506 561
507fn bar(foo: &Foo) { 562fn bar(foo: &Foo) {
508 Foo::frobnicate<|>(); 563 Foo::frobnicate$0();
509} 564}
510"#, 565"#,
511 ); 566 );
@@ -520,7 +575,7 @@ trait Foo {
520} //^^^^^^^^^^ 575} //^^^^^^^^^^
521 576
522fn bar() { 577fn bar() {
523 Foo::frobnicate<|>(); 578 Foo::frobnicate$0();
524} 579}
525"#, 580"#,
526 ); 581 );
@@ -537,7 +592,7 @@ trait Trait {
537impl Trait for Foo {} 592impl Trait for Foo {}
538 593
539fn bar() { 594fn bar() {
540 Foo::frobnicate<|>(); 595 Foo::frobnicate$0();
541} 596}
542"#, 597"#,
543 ); 598 );
@@ -551,7 +606,7 @@ struct Foo;
551impl Foo { 606impl Foo {
552 //^^^ 607 //^^^
553 pub fn new() -> Self { 608 pub fn new() -> Self {
554 Self<|> {} 609 Self$0 {}
555 } 610 }
556} 611}
557"#, 612"#,
@@ -561,7 +616,7 @@ impl Foo {
561struct Foo; 616struct Foo;
562impl Foo { 617impl Foo {
563 //^^^ 618 //^^^
564 pub fn new() -> Self<|> { 619 pub fn new() -> Self$0 {
565 Self {} 620 Self {}
566 } 621 }
567} 622}
@@ -573,7 +628,7 @@ impl Foo {
573enum Foo { A } 628enum Foo { A }
574impl Foo { 629impl Foo {
575 //^^^ 630 //^^^
576 pub fn new() -> Self<|> { 631 pub fn new() -> Self$0 {
577 Foo::A 632 Foo::A
578 } 633 }
579} 634}
@@ -585,7 +640,7 @@ impl Foo {
585enum Foo { A } 640enum Foo { A }
586impl Foo { 641impl Foo {
587 //^^^ 642 //^^^
588 pub fn thing(a: &Self<|>) { 643 pub fn thing(a: &Self$0) {
589 } 644 }
590} 645}
591"#, 646"#,
@@ -603,7 +658,7 @@ trait Make {
603impl Make for Foo { 658impl Make for Foo {
604 //^^^ 659 //^^^
605 fn new() -> Self { 660 fn new() -> Self {
606 Self<|> {} 661 Self$0 {}
607 } 662 }
608} 663}
609"#, 664"#,
@@ -617,7 +672,7 @@ trait Make {
617} 672}
618impl Make for Foo { 673impl Make for Foo {
619 //^^^ 674 //^^^
620 fn new() -> Self<|> { 675 fn new() -> Self$0 {
621 Self {} 676 Self {}
622 } 677 }
623} 678}
@@ -629,7 +684,7 @@ impl Make for Foo {
629 fn goto_def_when_used_on_definition_name_itself() { 684 fn goto_def_when_used_on_definition_name_itself() {
630 check( 685 check(
631 r#" 686 r#"
632struct Foo<|> { value: u32 } 687struct Foo$0 { value: u32 }
633 //^^^ 688 //^^^
634 "#, 689 "#,
635 ); 690 );
@@ -637,21 +692,21 @@ struct Foo<|> { value: u32 }
637 check( 692 check(
638 r#" 693 r#"
639struct Foo { 694struct Foo {
640 field<|>: string, 695 field$0: string,
641} //^^^^^ 696} //^^^^^
642"#, 697"#,
643 ); 698 );
644 699
645 check( 700 check(
646 r#" 701 r#"
647fn foo_test<|>() { } 702fn foo_test$0() { }
648 //^^^^^^^^ 703 //^^^^^^^^
649"#, 704"#,
650 ); 705 );
651 706
652 check( 707 check(
653 r#" 708 r#"
654enum Foo<|> { Variant } 709enum Foo$0 { Variant }
655 //^^^ 710 //^^^
656"#, 711"#,
657 ); 712 );
@@ -660,7 +715,7 @@ enum Foo<|> { Variant }
660 r#" 715 r#"
661enum Foo { 716enum Foo {
662 Variant1, 717 Variant1,
663 Variant2<|>, 718 Variant2$0,
664 //^^^^^^^^ 719 //^^^^^^^^
665 Variant3, 720 Variant3,
666} 721}
@@ -669,35 +724,35 @@ enum Foo {
669 724
670 check( 725 check(
671 r#" 726 r#"
672static INNER<|>: &str = ""; 727static INNER$0: &str = "";
673 //^^^^^ 728 //^^^^^
674"#, 729"#,
675 ); 730 );
676 731
677 check( 732 check(
678 r#" 733 r#"
679const INNER<|>: &str = ""; 734const INNER$0: &str = "";
680 //^^^^^ 735 //^^^^^
681"#, 736"#,
682 ); 737 );
683 738
684 check( 739 check(
685 r#" 740 r#"
686type Thing<|> = Option<()>; 741type Thing$0 = Option<()>;
687 //^^^^^ 742 //^^^^^
688"#, 743"#,
689 ); 744 );
690 745
691 check( 746 check(
692 r#" 747 r#"
693trait Foo<|> { } 748trait Foo$0 { }
694 //^^^ 749 //^^^
695"#, 750"#,
696 ); 751 );
697 752
698 check( 753 check(
699 r#" 754 r#"
700mod bar<|> { } 755mod bar$0 { }
701 //^^^ 756 //^^^
702"#, 757"#,
703 ); 758 );
@@ -714,7 +769,7 @@ fn foo() {}
714 //^^^ 769 //^^^
715id! { 770id! {
716 fn bar() { 771 fn bar() {
717 fo<|>o(); 772 fo$0o();
718 } 773 }
719} 774}
720mod confuse_index { fn foo(); } 775mod confuse_index { fn foo(); }
@@ -743,7 +798,7 @@ pub mod __export {
743fn foo() -> i8 {} 798fn foo() -> i8 {}
744 //^^^ 799 //^^^
745fn test() { 800fn test() {
746 format!("{}", fo<|>o()) 801 format!("{}", fo$0o())
747} 802}
748"#, 803"#,
749 ); 804 );
@@ -761,7 +816,7 @@ macro_rules! include {}
761//^^^^^^^^^^^^^^^^^^^ 816//^^^^^^^^^^^^^^^^^^^
762 817
763fn f() { 818fn f() {
764 foo<|>(); 819 foo$0();
765} 820}
766 821
767mod confuse_index { 822mod confuse_index {
@@ -778,7 +833,7 @@ fn foo() {}
778 fn goto_for_type_param() { 833 fn goto_for_type_param() {
779 check( 834 check(
780 r#" 835 r#"
781struct Foo<T: Clone> { t: <|>T } 836struct Foo<T: Clone> { t: $0T }
782 //^ 837 //^
783"#, 838"#,
784 ); 839 );
@@ -796,7 +851,7 @@ fn foo() {
796 let x = 1; 851 let x = 1;
797 //^ 852 //^
798 id!({ 853 id!({
799 let y = <|>x; 854 let y = $0x;
800 let z = y; 855 let z = y;
801 }); 856 });
802} 857}
@@ -814,7 +869,7 @@ fn foo() {
814 id!({ 869 id!({
815 let y = x; 870 let y = x;
816 //^ 871 //^
817 let z = <|>y; 872 let z = $0y;
818 }); 873 });
819} 874}
820"#, 875"#,
@@ -829,7 +884,7 @@ fn main() {
829 fn foo() { 884 fn foo() {
830 let x = 92; 885 let x = 92;
831 //^ 886 //^
832 <|>x; 887 $0x;
833 } 888 }
834} 889}
835"#, 890"#,
@@ -843,7 +898,7 @@ fn main() {
843fn bar() { 898fn bar() {
844 macro_rules! foo { () => { () } } 899 macro_rules! foo { () => { () } }
845 //^^^ 900 //^^^
846 <|>foo!(); 901 $0foo!();
847} 902}
848"#, 903"#,
849 ); 904 );
@@ -857,7 +912,7 @@ struct Foo { x: i32 }
857fn main() { 912fn main() {
858 let x = 92; 913 let x = 92;
859 //^ 914 //^
860 Foo { x<|> }; 915 Foo { x$0 };
861} 916}
862"#, 917"#,
863 ) 918 )
@@ -872,7 +927,7 @@ enum Foo {
872} //^ 927} //^
873fn baz(foo: Foo) { 928fn baz(foo: Foo) {
874 match foo { 929 match foo {
875 Foo::Bar { x<|> } => x 930 Foo::Bar { x$0 } => x
876 }; 931 };
877} 932}
878"#, 933"#,
@@ -887,7 +942,7 @@ enum Foo { Bar }
887 //^^^ 942 //^^^
888impl Foo { 943impl Foo {
889 fn baz(self) { 944 fn baz(self) {
890 match self { Self::Bar<|> => {} } 945 match self { Self::Bar$0 => {} }
891 } 946 }
892} 947}
893"#, 948"#,
@@ -902,7 +957,7 @@ enum Foo { Bar { val: i32 } }
902 //^^^ 957 //^^^
903impl Foo { 958impl Foo {
904 fn baz(self) -> i32 { 959 fn baz(self) -> i32 {
905 match self { Self::Bar<|> { val } => {} } 960 match self { Self::Bar$0 { val } => {} }
906 } 961 }
907} 962}
908"#, 963"#,
@@ -916,7 +971,7 @@ impl Foo {
916enum Foo { Bar } 971enum Foo { Bar }
917 //^^^ 972 //^^^
918impl Foo { 973impl Foo {
919 fn baz(self) { Self::Bar<|>; } 974 fn baz(self) { Self::Bar$0; }
920} 975}
921"#, 976"#,
922 ); 977 );
@@ -929,7 +984,7 @@ impl Foo {
929enum Foo { Bar { val: i32 } } 984enum Foo { Bar { val: i32 } }
930 //^^^ 985 //^^^
931impl Foo { 986impl Foo {
932 fn baz(self) { Self::Bar<|> {val: 4}; } 987 fn baz(self) { Self::Bar$0 {val: 4}; }
933} 988}
934"#, 989"#,
935 ); 990 );
@@ -939,7 +994,7 @@ impl Foo {
939 fn goto_def_for_type_alias_generic_parameter() { 994 fn goto_def_for_type_alias_generic_parameter() {
940 check( 995 check(
941 r#" 996 r#"
942type Alias<T> = T<|>; 997type Alias<T> = T$0;
943 //^ 998 //^
944"#, 999"#,
945 ) 1000 )
@@ -950,7 +1005,7 @@ type Alias<T> = T<|>;
950 check( 1005 check(
951 r#" 1006 r#"
952//- /lib.rs 1007//- /lib.rs
953foo::module<|>::mac!(); 1008foo::module$0::mac!();
954 1009
955//- /foo/lib.rs 1010//- /foo/lib.rs
956pub mod module { 1011pub mod module {
@@ -972,7 +1027,7 @@ trait Iterator {
972 //^^^^ 1027 //^^^^
973} 1028}
974 1029
975fn f() -> impl Iterator<Item<|> = u8> {} 1030fn f() -> impl Iterator<Item$0 = u8> {}
976"#, 1031"#,
977 ); 1032 );
978 } 1033 }
@@ -987,7 +1042,7 @@ trait Iterator {
987 type B; 1042 type B;
988} 1043}
989 1044
990fn f() -> impl Iterator<A<|> = u8, B = ()> {} 1045fn f() -> impl Iterator<A$0 = u8, B = ()> {}
991"#, 1046"#,
992 ); 1047 );
993 check( 1048 check(
@@ -998,7 +1053,7 @@ trait Iterator {
998 //^ 1053 //^
999} 1054}
1000 1055
1001fn f() -> impl Iterator<A = u8, B<|> = ()> {} 1056fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1002"#, 1057"#,
1003 ); 1058 );
1004 } 1059 }
@@ -1012,7 +1067,7 @@ trait Iterator {
1012 //^^^^ 1067 //^^^^
1013} 1068}
1014 1069
1015fn g() -> <() as Iterator<Item<|> = ()>>::Item {} 1070fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1016"#, 1071"#,
1017 ); 1072 );
1018 } 1073 }
@@ -1027,7 +1082,7 @@ trait Iterator {
1027 type B; 1082 type B;
1028} 1083}
1029 1084
1030fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {} 1085fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1031"#, 1086"#,
1032 ); 1087 );
1033 check( 1088 check(
@@ -1038,7 +1093,7 @@ trait Iterator {
1038 //^ 1093 //^
1039} 1094}
1040 1095
1041fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {} 1096fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1042"#, 1097"#,
1043 ); 1098 );
1044 } 1099 }
@@ -1052,7 +1107,7 @@ struct Foo {}
1052impl Foo { 1107impl Foo {
1053 fn bar(self: &Foo) { 1108 fn bar(self: &Foo) {
1054 //^^^^ 1109 //^^^^
1055 let foo = sel<|>f; 1110 let foo = sel$0f;
1056 } 1111 }
1057}"#, 1112}"#,
1058 ) 1113 )
@@ -1065,7 +1120,7 @@ impl Foo {
1065struct Foo {} 1120struct Foo {}
1066 1121
1067impl Foo { 1122impl Foo {
1068 fn bar(&self<|>) { 1123 fn bar(&self$0) {
1069 //^^^^ 1124 //^^^^
1070 } 1125 }
1071}"#, 1126}"#,
@@ -1076,7 +1131,7 @@ impl Foo {
1076 fn goto_lifetime_param_on_decl() { 1131 fn goto_lifetime_param_on_decl() {
1077 check( 1132 check(
1078 r#" 1133 r#"
1079fn foo<'foobar<|>>(_: &'foobar ()) { 1134fn foo<'foobar$0>(_: &'foobar ()) {
1080 //^^^^^^^ 1135 //^^^^^^^
1081}"#, 1136}"#,
1082 ) 1137 )
@@ -1086,7 +1141,7 @@ fn foo<'foobar<|>>(_: &'foobar ()) {
1086 fn goto_lifetime_param_decl() { 1141 fn goto_lifetime_param_decl() {
1087 check( 1142 check(
1088 r#" 1143 r#"
1089fn foo<'foobar>(_: &'foobar<|> ()) { 1144fn foo<'foobar>(_: &'foobar$0 ()) {
1090 //^^^^^^^ 1145 //^^^^^^^
1091}"#, 1146}"#,
1092 ) 1147 )
@@ -1097,7 +1152,7 @@ fn foo<'foobar>(_: &'foobar<|> ()) {
1097 check( 1152 check(
1098 r#" 1153 r#"
1099fn foo<'foobar>(_: &'foobar ()) { 1154fn foo<'foobar>(_: &'foobar ()) {
1100 fn foo<'foobar>(_: &'foobar<|> ()) {} 1155 fn foo<'foobar>(_: &'foobar$0 ()) {}
1101 //^^^^^^^ 1156 //^^^^^^^
1102}"#, 1157}"#,
1103 ) 1158 )
@@ -1108,13 +1163,13 @@ fn foo<'foobar>(_: &'foobar ()) {
1108 fn goto_lifetime_hrtb() { 1163 fn goto_lifetime_hrtb() {
1109 check( 1164 check(
1110 r#"trait Foo<T> {} 1165 r#"trait Foo<T> {}
1111fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {} 1166fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1112 //^^ 1167 //^^
1113"#, 1168"#,
1114 ); 1169 );
1115 check( 1170 check(
1116 r#"trait Foo<T> {} 1171 r#"trait Foo<T> {}
1117fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} 1172fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1118 //^^ 1173 //^^
1119"#, 1174"#,
1120 ); 1175 );
@@ -1125,7 +1180,7 @@ fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {}
1125 fn goto_lifetime_hrtb_for_type() { 1180 fn goto_lifetime_hrtb_for_type() {
1126 check( 1181 check(
1127 r#"trait Foo<T> {} 1182 r#"trait Foo<T> {}
1128fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {} 1183fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1129 //^^ 1184 //^^
1130"#, 1185"#,
1131 ); 1186 );
@@ -1139,10 +1194,40 @@ fn foo<'foo>(_: &'foo ()) {
1139 'foo: { 1194 'foo: {
1140 //^^^^ 1195 //^^^^
1141 'bar: loop { 1196 'bar: loop {
1142 break 'foo<|>; 1197 break 'foo$0;
1143 } 1198 }
1144 } 1199 }
1145}"#, 1200}"#,
1146 ) 1201 )
1147 } 1202 }
1203
1204 #[test]
1205 fn goto_def_for_intra_doc_link_same_file() {
1206 check(
1207 r#"
1208/// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar)
1209pub fn bar() { }
1210
1211/// You might want to see [`std::fs::read()`] too.
1212pub fn foo() { }
1213 //^^^
1214
1215}"#,
1216 )
1217 }
1218
1219 #[test]
1220 fn goto_def_for_intra_doc_link_inner() {
1221 check(
1222 r#"
1223//- /main.rs
1224mod m;
1225struct S;
1226 //^
1227
1228//- /m.rs
1229//! [`super::S$0`]
1230"#,
1231 )
1232 }
1148} 1233}
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 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 f2ad95cb6..317b6f011 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, 20 runnables::{runnable_fn, runnable_mod},
21 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, 21 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
22}; 22};
23 23
@@ -31,19 +31,6 @@ pub struct HoverConfig {
31 pub markdown: bool, 31 pub markdown: bool,
32} 32}
33 33
34impl Default for HoverConfig {
35 fn default() -> Self {
36 Self {
37 implementations: true,
38 run: true,
39 debug: true,
40 goto_type_def: true,
41 links_in_hover: true,
42 markdown: true,
43 }
44 }
45}
46
47impl HoverConfig { 34impl HoverConfig {
48 pub const NO_ACTIONS: Self = Self { 35 pub const NO_ACTIONS: Self = Self {
49 implementations: false, 36 implementations: false,
@@ -188,12 +175,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
188 Definition::SelfType(it) => it.target_ty(db).as_adt(), 175 Definition::SelfType(it) => it.target_ty(db).as_adt(),
189 _ => None, 176 _ => None,
190 }?; 177 }?;
191 match adt { 178 adt.try_to_nav(db).map(to_action)
192 Adt::Struct(it) => it.try_to_nav(db),
193 Adt::Union(it) => it.try_to_nav(db),
194 Adt::Enum(it) => it.try_to_nav(db),
195 }
196 .map(to_action)
197} 179}
198 180
199fn runnable_action( 181fn runnable_action(
@@ -204,22 +186,20 @@ fn runnable_action(
204 match def { 186 match def {
205 Definition::ModuleDef(it) => match it { 187 Definition::ModuleDef(it) => match it {
206 ModuleDef::Module(it) => match it.definition_source(sema.db).value { 188 ModuleDef::Module(it) => match it.definition_source(sema.db).value {
207 ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id) 189 ModuleSource::Module(it) => {
208 .map(|it| HoverAction::Runnable(it)), 190 runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it))
191 }
209 _ => None, 192 _ => None,
210 }, 193 },
211 ModuleDef::Function(it) => { 194 ModuleDef::Function(func) => {
212 #[allow(deprecated)] 195 let src = func.source(sema.db)?;
213 let src = it.source(sema.db)?;
214 if src.file_id != file_id.into() { 196 if src.file_id != file_id.into() {
215 mark::hit!(hover_macro_generated_struct_fn_doc_comment); 197 mark::hit!(hover_macro_generated_struct_fn_doc_comment);
216 mark::hit!(hover_macro_generated_struct_fn_doc_attr); 198 mark::hit!(hover_macro_generated_struct_fn_doc_attr);
217
218 return None; 199 return None;
219 } 200 }
220 201
221 runnable(&sema, src.value.syntax().clone(), file_id) 202 runnable_fn(&sema, func).map(HoverAction::Runnable)
222 .map(|it| HoverAction::Runnable(it))
223 } 203 }
224 _ => None, 204 _ => None,
225 }, 205 },
@@ -235,12 +215,12 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
235 } 215 }
236 }; 216 };
237 217
238 if let Definition::TypeParam(it) = def { 218 if let Definition::GenericParam(GenericParam::TypeParam(it)) = def {
239 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); 219 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
240 } else { 220 } else {
241 let ty = match def { 221 let ty = match def {
242 Definition::Local(it) => it.ty(db), 222 Definition::Local(it) => it.ty(db),
243 Definition::ConstParam(it) => it.ty(db), 223 Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db),
244 _ => return None, 224 _ => return None,
245 }; 225 };
246 226
@@ -335,7 +315,6 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
335 from_def_source_labeled(db, it, Some(label), mod_path) 315 from_def_source_labeled(db, it, Some(label), mod_path)
336 } 316 }
337 Definition::Field(def) => { 317 Definition::Field(def) => {
338 #[allow(deprecated)]
339 let src = def.source(db)?.value; 318 let src = def.source(db)?.value;
340 if let FieldSource::Named(it) = src { 319 if let FieldSource::Named(it) = src {
341 from_def_source_labeled(db, def, it.short_label(), mod_path) 320 from_def_source_labeled(db, def, it.short_label(), mod_path)
@@ -373,9 +352,11 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
373 }) 352 })
374 } 353 }
375 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 354 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
376 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), 355 Definition::GenericParam(it) => match it {
377 Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))), 356 GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))),
378 Definition::ConstParam(it) => from_def_source(db, it, None), 357 GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
358 GenericParam::ConstParam(it) => from_def_source(db, it, None),
359 },
379 }; 360 };
380 361
381 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> 362 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
@@ -383,7 +364,6 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
383 D: HasSource<Ast = A> + HasAttrs + Copy, 364 D: HasSource<Ast = A> + HasAttrs + Copy,
384 A: ShortLabel, 365 A: ShortLabel,
385 { 366 {
386 #[allow(deprecated)]
387 let short_label = def.source(db)?.value.short_label(); 367 let short_label = def.source(db)?.value.short_label();
388 from_def_source_labeled(db, def, short_label, mod_path) 368 from_def_source_labeled(db, def, short_label, mod_path)
389 } 369 }
@@ -474,7 +454,7 @@ mod tests {
474pub fn foo() -> u32 { 1 } 454pub fn foo() -> u32 { 1 }
475 455
476fn main() { 456fn main() {
477 let foo_test = foo()<|>; 457 let foo_test = foo()$0;
478} 458}
479"#, 459"#,
480 expect![[r#" 460 expect![[r#"
@@ -493,7 +473,7 @@ fn main() {
493pub fn foo() -> u32 { 1 } 473pub fn foo() -> u32 { 1 }
494 474
495fn main() { 475fn main() {
496 let foo_test = foo()<|>; 476 let foo_test = foo()$0;
497} 477}
498"#, 478"#,
499 expect![[r#" 479 expect![[r#"
@@ -523,7 +503,7 @@ fn main() {
523 Option::Some(*memo + value) 503 Option::Some(*memo + value)
524 }; 504 };
525 let number = 5u32; 505 let number = 5u32;
526 let mut iter<|> = scan(OtherStruct { i: num }, closure, number); 506 let mut iter$0 = scan(OtherStruct { i: num }, closure, number);
527} 507}
528"#, 508"#,
529 expect![[r#" 509 expect![[r#"
@@ -543,7 +523,7 @@ fn main() {
543 r#" 523 r#"
544pub fn foo() -> u32 { 1 } 524pub fn foo() -> u32 { 1 }
545 525
546fn main() { let foo_test = fo<|>o(); } 526fn main() { let foo_test = fo$0o(); }
547"#, 527"#,
548 expect![[r#" 528 expect![[r#"
549 *foo* 529 *foo*
@@ -575,7 +555,7 @@ mod a;
575mod b; 555mod b;
576mod c; 556mod c;
577 557
578fn main() { let foo_test = fo<|>o(); } 558fn main() { let foo_test = fo$0o(); }
579 "#, 559 "#,
580 expect![[r#" 560 expect![[r#"
581 *foo* 561 *foo*
@@ -592,7 +572,7 @@ fn main() { let foo_test = fo<|>o(); }
592 r#" 572 r#"
593pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { } 573pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
594 574
595fn main() { let foo_test = fo<|>o(); } 575fn main() { let foo_test = fo$0o(); }
596 "#, 576 "#,
597 expect![[r#" 577 expect![[r#"
598 *foo* 578 *foo*
@@ -612,7 +592,7 @@ fn main() { let foo_test = fo<|>o(); }
612 fn hover_shows_fn_signature_on_fn_name() { 592 fn hover_shows_fn_signature_on_fn_name() {
613 check( 593 check(
614 r#" 594 r#"
615pub fn foo<|>(a: u32, b: u32) -> u32 {} 595pub fn foo$0(a: u32, b: u32) -> u32 {}
616 596
617fn main() { } 597fn main() { }
618"#, 598"#,
@@ -640,7 +620,7 @@ fn main() { }
640/// # 620/// #
641/// foo(Path::new("hello, world!")) 621/// foo(Path::new("hello, world!"))
642/// ``` 622/// ```
643pub fn foo<|>(_: &Path) {} 623pub fn foo$0(_: &Path) {}
644 624
645fn main() { } 625fn main() { }
646"#, 626"#,
@@ -673,7 +653,7 @@ fn main() { }
673 check( 653 check(
674 r##" 654 r##"
675#[doc = r#"Raw string doc attr"#] 655#[doc = r#"Raw string doc attr"#]
676pub fn foo<|>(_: &Path) {} 656pub fn foo$0(_: &Path) {}
677 657
678fn main() { } 658fn main() { }
679"##, 659"##,
@@ -703,7 +683,7 @@ fn main() { }
703struct Foo { field_a: u32 } 683struct Foo { field_a: u32 }
704 684
705fn main() { 685fn main() {
706 let foo = Foo { field_a<|>: 0, }; 686 let foo = Foo { field_a$0: 0, };
707} 687}
708"#, 688"#,
709 expect![[r#" 689 expect![[r#"
@@ -722,7 +702,7 @@ fn main() {
722 // Hovering over the field in the definition 702 // Hovering over the field in the definition
723 check( 703 check(
724 r#" 704 r#"
725struct Foo { field_a<|>: u32 } 705struct Foo { field_a$0: u32 }
726 706
727fn main() { 707fn main() {
728 let foo = Foo { field_a: 0 }; 708 let foo = Foo { field_a: 0 };
@@ -745,7 +725,7 @@ fn main() {
745 #[test] 725 #[test]
746 fn hover_const_static() { 726 fn hover_const_static() {
747 check( 727 check(
748 r#"const foo<|>: u32 = 123;"#, 728 r#"const foo$0: u32 = 123;"#,
749 expect![[r#" 729 expect![[r#"
750 *foo* 730 *foo*
751 731
@@ -759,7 +739,7 @@ fn main() {
759 "#]], 739 "#]],
760 ); 740 );
761 check( 741 check(
762 r#"static foo<|>: u32 = 456;"#, 742 r#"static foo$0: u32 = 456;"#,
763 expect![[r#" 743 expect![[r#"
764 *foo* 744 *foo*
765 745
@@ -781,7 +761,7 @@ fn main() {
781struct Test<K, T = u8> { k: K, t: T } 761struct Test<K, T = u8> { k: K, t: T }
782 762
783fn main() { 763fn main() {
784 let zz<|> = Test { t: 23u8, k: 33 }; 764 let zz$0 = Test { t: 23u8, k: 33 };
785}"#, 765}"#,
786 expect![[r#" 766 expect![[r#"
787 *zz* 767 *zz*
@@ -800,7 +780,7 @@ fn main() {
800enum Option<T> { Some(T) } 780enum Option<T> { Some(T) }
801use Option::Some; 781use Option::Some;
802 782
803fn main() { So<|>me(12); } 783fn main() { So$0me(12); }
804"#, 784"#,
805 expect![[r#" 785 expect![[r#"
806 *Some* 786 *Some*
@@ -820,7 +800,7 @@ fn main() { So<|>me(12); }
820enum Option<T> { Some(T) } 800enum Option<T> { Some(T) }
821use Option::Some; 801use Option::Some;
822 802
823fn main() { let b<|>ar = Some(12); } 803fn main() { let b$0ar = Some(12); }
824"#, 804"#,
825 expect![[r#" 805 expect![[r#"
826 *bar* 806 *bar*
@@ -838,7 +818,7 @@ fn main() { let b<|>ar = Some(12); }
838 r#" 818 r#"
839enum Option<T> { 819enum Option<T> {
840 /// The None variant 820 /// The None variant
841 Non<|>e 821 Non$0e
842} 822}
843"#, 823"#,
844 expect![[r#" 824 expect![[r#"
@@ -865,7 +845,7 @@ enum Option<T> {
865 Some(T) 845 Some(T)
866} 846}
867fn main() { 847fn main() {
868 let s = Option::Som<|>e(12); 848 let s = Option::Som$0e(12);
869} 849}
870"#, 850"#,
871 expect![[r#" 851 expect![[r#"
@@ -889,7 +869,7 @@ fn main() {
889 #[test] 869 #[test]
890 fn hover_for_local_variable() { 870 fn hover_for_local_variable() {
891 check( 871 check(
892 r#"fn func(foo: i32) { fo<|>o; }"#, 872 r#"fn func(foo: i32) { fo$0o; }"#,
893 expect![[r#" 873 expect![[r#"
894 *foo* 874 *foo*
895 875
@@ -903,7 +883,7 @@ fn main() {
903 #[test] 883 #[test]
904 fn hover_for_local_variable_pat() { 884 fn hover_for_local_variable_pat() {
905 check( 885 check(
906 r#"fn func(fo<|>o: i32) {}"#, 886 r#"fn func(fo$0o: i32) {}"#,
907 expect![[r#" 887 expect![[r#"
908 *foo* 888 *foo*
909 889
@@ -917,7 +897,7 @@ fn main() {
917 #[test] 897 #[test]
918 fn hover_local_var_edge() { 898 fn hover_local_var_edge() {
919 check( 899 check(
920 r#"fn func(foo: i32) { if true { <|>foo; }; }"#, 900 r#"fn func(foo: i32) { if true { $0foo; }; }"#,
921 expect![[r#" 901 expect![[r#"
922 *foo* 902 *foo*
923 903
@@ -931,7 +911,7 @@ fn main() {
931 #[test] 911 #[test]
932 fn hover_for_param_edge() { 912 fn hover_for_param_edge() {
933 check( 913 check(
934 r#"fn func(<|>foo: i32) {}"#, 914 r#"fn func($0foo: i32) {}"#,
935 expect![[r#" 915 expect![[r#"
936 *foo* 916 *foo*
937 917
@@ -951,7 +931,7 @@ fn main() {
951 trait DerefMut { 931 trait DerefMut {
952 type Target: ?Sized; 932 type Target: ?Sized;
953 } 933 }
954 fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#, 934 fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
955 expect![[r#" 935 expect![[r#"
956 *_x* 936 *_x*
957 937
@@ -972,7 +952,7 @@ impl Thing {
972 fn new() -> Thing { Thing { x: 0 } } 952 fn new() -> Thing { Thing { x: 0 } }
973} 953}
974 954
975fn main() { let foo_<|>test = Thing::new(); } 955fn main() { let foo_$0test = Thing::new(); }
976 "#, 956 "#,
977 expect![[r#" 957 expect![[r#"
978 *foo_test* 958 *foo_test*
@@ -996,7 +976,7 @@ mod wrapper {
996 } 976 }
997} 977}
998 978
999fn main() { let foo_test = wrapper::Thing::new<|>(); } 979fn main() { let foo_test = wrapper::Thing::new$0(); }
1000"#, 980"#,
1001 expect![[r#" 981 expect![[r#"
1002 *new* 982 *new*
@@ -1023,7 +1003,7 @@ impl X {
1023 1003
1024fn main() { 1004fn main() {
1025 match 1 { 1005 match 1 {
1026 X::C<|> => {}, 1006 X::C$0 => {},
1027 2 => {}, 1007 2 => {},
1028 _ => {} 1008 _ => {}
1029 }; 1009 };
@@ -1049,7 +1029,7 @@ fn main() {
1049 r#" 1029 r#"
1050struct Thing { x: u32 } 1030struct Thing { x: u32 }
1051impl Thing { 1031impl Thing {
1052 fn new() -> Self { Self<|> { x: 0 } } 1032 fn new() -> Self { Self$0 { x: 0 } }
1053} 1033}
1054"#, 1034"#,
1055 expect![[r#" 1035 expect![[r#"
@@ -1068,7 +1048,7 @@ impl Thing {
1068 r#" 1048 r#"
1069struct Thing { x: u32 } 1049struct Thing { x: u32 }
1070impl Thing { 1050impl Thing {
1071 fn new() -> Self<|> { Self { x: 0 } } 1051 fn new() -> Self$0 { Self { x: 0 } }
1072} 1052}
1073"#, 1053"#,
1074 expect![[r#" 1054 expect![[r#"
@@ -1087,7 +1067,7 @@ impl Thing {
1087 r#" 1067 r#"
1088enum Thing { A } 1068enum Thing { A }
1089impl Thing { 1069impl Thing {
1090 pub fn new() -> Self<|> { Thing::A } 1070 pub fn new() -> Self$0 { Thing::A }
1091} 1071}
1092"#, 1072"#,
1093 expect![[r#" 1073 expect![[r#"
@@ -1106,7 +1086,7 @@ impl Thing {
1106 r#" 1086 r#"
1107 enum Thing { A } 1087 enum Thing { A }
1108 impl Thing { 1088 impl Thing {
1109 pub fn thing(a: Self<|>) {} 1089 pub fn thing(a: Self$0) {}
1110 } 1090 }
1111 "#, 1091 "#,
1112 expect![[r#" 1092 expect![[r#"
@@ -1131,7 +1111,7 @@ fn x() {}
1131 1111
1132fn y() { 1112fn y() {
1133 let x = 0i32; 1113 let x = 0i32;
1134 x<|>; 1114 x$0;
1135} 1115}
1136"#, 1116"#,
1137 expect![[r#" 1117 expect![[r#"
@@ -1150,7 +1130,7 @@ fn y() {
1150 r#" 1130 r#"
1151macro_rules! foo { () => {} } 1131macro_rules! foo { () => {} }
1152 1132
1153fn f() { fo<|>o!(); } 1133fn f() { fo$0o!(); }
1154"#, 1134"#,
1155 expect![[r#" 1135 expect![[r#"
1156 *foo* 1136 *foo*
@@ -1169,7 +1149,7 @@ fn f() { fo<|>o!(); }
1169 #[test] 1149 #[test]
1170 fn test_hover_tuple_field() { 1150 fn test_hover_tuple_field() {
1171 check( 1151 check(
1172 r#"struct TS(String, i32<|>);"#, 1152 r#"struct TS(String, i32$0);"#,
1173 expect![[r#" 1153 expect![[r#"
1174 *i32* 1154 *i32*
1175 1155
@@ -1187,7 +1167,7 @@ fn f() { fo<|>o!(); }
1187macro_rules! id { ($($tt:tt)*) => { $($tt)* } } 1167macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1188fn foo() {} 1168fn foo() {}
1189id! { 1169id! {
1190 fn bar() { fo<|>o(); } 1170 fn bar() { fo$0o(); }
1191} 1171}
1192"#, 1172"#,
1193 expect![[r#" 1173 expect![[r#"
@@ -1209,7 +1189,7 @@ id! {
1209 check( 1189 check(
1210 r#" 1190 r#"
1211macro_rules! id { ($($tt:tt)*) => { $($tt)* } } 1191macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1212fn foo(bar:u32) { let a = id!(ba<|>r); } 1192fn foo(bar:u32) { let a = id!(ba$0r); }
1213"#, 1193"#,
1214 expect![[r#" 1194 expect![[r#"
1215 *bar* 1195 *bar*
@@ -1227,7 +1207,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); }
1227 r#" 1207 r#"
1228macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } 1208macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1229macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } 1209macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1230fn foo(bar:u32) { let a = id!(ba<|>r); } 1210fn foo(bar:u32) { let a = id!(ba$0r); }
1231"#, 1211"#,
1232 expect![[r#" 1212 expect![[r#"
1233 *bar* 1213 *bar*
@@ -1246,7 +1226,7 @@ fn foo(bar:u32) { let a = id!(ba<|>r); }
1246macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } } 1226macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1247macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } 1227macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1248fn bar() -> u32 { 0 } 1228fn bar() -> u32 { 0 }
1249fn foo() { let a = id!([0u32, bar(<|>)] ); } 1229fn foo() { let a = id!([0u32, bar($0)] ); }
1250"#, 1230"#,
1251 expect![[r#" 1231 expect![[r#"
1252 *bar()* 1232 *bar()*
@@ -1264,7 +1244,7 @@ fn foo() { let a = id!([0u32, bar(<|>)] ); }
1264macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } } 1244macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
1265fn foo() { 1245fn foo() {
1266 let mastered_for_itunes = ""; 1246 let mastered_for_itunes = "";
1267 let _ = arr!("Tr<|>acks", &mastered_for_itunes); 1247 let _ = arr!("Tr$0acks", &mastered_for_itunes);
1268} 1248}
1269"#, 1249"#,
1270 expect![[r#" 1250 expect![[r#"
@@ -1285,7 +1265,7 @@ macro_rules! assert {}
1285 1265
1286fn bar() -> bool { true } 1266fn bar() -> bool { true }
1287fn foo() { 1267fn foo() {
1288 assert!(ba<|>r()); 1268 assert!(ba$0r());
1289} 1269}
1290"#, 1270"#,
1291 expect![[r#" 1271 expect![[r#"
@@ -1310,7 +1290,7 @@ fn foo() {
1310 macro_rules! format {} 1290 macro_rules! format {}
1311 1291
1312 fn foo() { 1292 fn foo() {
1313 format!("hel<|>lo {}", 0); 1293 format!("hel$0lo {}", 0);
1314 } 1294 }
1315 "#, 1295 "#,
1316 ); 1296 );
@@ -1323,7 +1303,7 @@ fn foo() {
1323/// <- `\u{3000}` here 1303/// <- `\u{3000}` here
1324fn foo() { } 1304fn foo() { }
1325 1305
1326fn bar() { fo<|>o(); } 1306fn bar() { fo$0o(); }
1327", 1307",
1328 expect![[r#" 1308 expect![[r#"
1329 *foo* 1309 *foo*
@@ -1346,7 +1326,7 @@ fn bar() { fo<|>o(); }
1346 #[test] 1326 #[test]
1347 fn test_hover_function_show_qualifiers() { 1327 fn test_hover_function_show_qualifiers() {
1348 check( 1328 check(
1349 r#"async fn foo<|>() {}"#, 1329 r#"async fn foo$0() {}"#,
1350 expect![[r#" 1330 expect![[r#"
1351 *foo* 1331 *foo*
1352 1332
@@ -1360,7 +1340,7 @@ fn bar() { fo<|>o(); }
1360 "#]], 1340 "#]],
1361 ); 1341 );
1362 check( 1342 check(
1363 r#"pub const unsafe fn foo<|>() {}"#, 1343 r#"pub const unsafe fn foo$0() {}"#,
1364 expect![[r#" 1344 expect![[r#"
1365 *foo* 1345 *foo*
1366 1346
@@ -1374,7 +1354,7 @@ fn bar() { fo<|>o(); }
1374 "#]], 1354 "#]],
1375 ); 1355 );
1376 check( 1356 check(
1377 r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#, 1357 r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#,
1378 expect![[r#" 1358 expect![[r#"
1379 *foo* 1359 *foo*
1380 1360
@@ -1392,7 +1372,7 @@ fn bar() { fo<|>o(); }
1392 #[test] 1372 #[test]
1393 fn test_hover_trait_show_qualifiers() { 1373 fn test_hover_trait_show_qualifiers() {
1394 check_actions( 1374 check_actions(
1395 r"unsafe trait foo<|>() {}", 1375 r"unsafe trait foo$0() {}",
1396 expect![[r#" 1376 expect![[r#"
1397 [ 1377 [
1398 Implementation( 1378 Implementation(
@@ -1413,7 +1393,7 @@ fn bar() { fo<|>o(); }
1413 check( 1393 check(
1414 r#" 1394 r#"
1415//- /main.rs crate:main deps:std 1395//- /main.rs crate:main deps:std
1416extern crate st<|>d; 1396extern crate st$0d;
1417//- /std/lib.rs crate:std 1397//- /std/lib.rs crate:std
1418//! Standard library for this test 1398//! Standard library for this test
1419//! 1399//!
@@ -1431,7 +1411,7 @@ extern crate st<|>d;
1431 check( 1411 check(
1432 r#" 1412 r#"
1433//- /main.rs crate:main deps:std 1413//- /main.rs crate:main deps:std
1434extern crate std as ab<|>c; 1414extern crate std as ab$0c;
1435//- /std/lib.rs crate:std 1415//- /std/lib.rs crate:std
1436//! Standard library for this test 1416//! Standard library for this test
1437//! 1417//!
@@ -1452,7 +1432,7 @@ extern crate std as ab<|>c;
1452 fn test_hover_mod_with_same_name_as_function() { 1432 fn test_hover_mod_with_same_name_as_function() {
1453 check( 1433 check(
1454 r#" 1434 r#"
1455use self::m<|>y::Bar; 1435use self::m$0y::Bar;
1456mod my { pub struct Bar; } 1436mod my { pub struct Bar; }
1457 1437
1458fn my() {} 1438fn my() {}
@@ -1478,7 +1458,7 @@ fn my() {}
1478/// bar docs 1458/// bar docs
1479struct Bar; 1459struct Bar;
1480 1460
1481fn foo() { let bar = Ba<|>r; } 1461fn foo() { let bar = Ba$0r; }
1482"#, 1462"#,
1483 expect![[r#" 1463 expect![[r#"
1484 *Bar* 1464 *Bar*
@@ -1505,7 +1485,7 @@ fn foo() { let bar = Ba<|>r; }
1505#[doc = "bar docs"] 1485#[doc = "bar docs"]
1506struct Bar; 1486struct Bar;
1507 1487
1508fn foo() { let bar = Ba<|>r; } 1488fn foo() { let bar = Ba$0r; }
1509"#, 1489"#,
1510 expect![[r#" 1490 expect![[r#"
1511 *Bar* 1491 *Bar*
@@ -1534,7 +1514,7 @@ fn foo() { let bar = Ba<|>r; }
1534#[doc = "bar docs 2"] 1514#[doc = "bar docs 2"]
1535struct Bar; 1515struct Bar;
1536 1516
1537fn foo() { let bar = Ba<|>r; } 1517fn foo() { let bar = Ba$0r; }
1538"#, 1518"#,
1539 expect![[r#" 1519 expect![[r#"
1540 *Bar* 1520 *Bar*
@@ -1562,7 +1542,7 @@ fn foo() { let bar = Ba<|>r; }
1562 r#" 1542 r#"
1563pub struct Foo; 1543pub struct Foo;
1564/// [Foo](struct.Foo.html) 1544/// [Foo](struct.Foo.html)
1565pub struct B<|>ar 1545pub struct B$0ar
1566"#, 1546"#,
1567 expect![[r#" 1547 expect![[r#"
1568 *Bar* 1548 *Bar*
@@ -1588,7 +1568,7 @@ pub struct B<|>ar
1588 r#" 1568 r#"
1589pub struct Foo; 1569pub struct Foo;
1590/// [struct Foo](struct.Foo.html) 1570/// [struct Foo](struct.Foo.html)
1591pub struct B<|>ar 1571pub struct B$0ar
1592"#, 1572"#,
1593 expect![[r#" 1573 expect![[r#"
1594 *Bar* 1574 *Bar*
@@ -1616,7 +1596,7 @@ pub struct B<|>ar
1616pub struct Foo; 1596pub struct Foo;
1617pub struct Bar { 1597pub struct Bar {
1618 /// [Foo](struct.Foo.html) 1598 /// [Foo](struct.Foo.html)
1619 fie<|>ld: () 1599 fie$0ld: ()
1620} 1600}
1621"#, 1601"#,
1622 expect![[r#" 1602 expect![[r#"
@@ -1645,7 +1625,7 @@ pub mod foo {
1645 pub struct Foo; 1625 pub struct Foo;
1646} 1626}
1647/// [Foo](foo::Foo) 1627/// [Foo](foo::Foo)
1648pub struct B<|>ar 1628pub struct B$0ar
1649"#, 1629"#,
1650 expect![[r#" 1630 expect![[r#"
1651 *Bar* 1631 *Bar*
@@ -1675,7 +1655,7 @@ pub mod foo {
1675 pub struct Foo; 1655 pub struct Foo;
1676} 1656}
1677/// [Foo](foo::Foo) 1657/// [Foo](foo::Foo)
1678pub struct B<|>ar 1658pub struct B$0ar
1679"#, 1659"#,
1680 expect![[r#" 1660 expect![[r#"
1681 *Bar* 1661 *Bar*
@@ -1701,7 +1681,7 @@ pub struct B<|>ar
1701 r#" 1681 r#"
1702pub struct Foo; 1682pub struct Foo;
1703/// [Foo] 1683/// [Foo]
1704pub struct B<|>ar 1684pub struct B$0ar
1705"#, 1685"#,
1706 expect![[r#" 1686 expect![[r#"
1707 *Bar* 1687 *Bar*
@@ -1727,7 +1707,7 @@ pub struct B<|>ar
1727 r#" 1707 r#"
1728pub struct Foo; 1708pub struct Foo;
1729/// [`Foo`] 1709/// [`Foo`]
1730pub struct B<|>ar 1710pub struct B$0ar
1731"#, 1711"#,
1732 expect![[r#" 1712 expect![[r#"
1733 *Bar* 1713 *Bar*
@@ -1754,7 +1734,7 @@ pub struct B<|>ar
1754pub struct Foo; 1734pub struct Foo;
1755fn Foo() {} 1735fn Foo() {}
1756/// [Foo()] 1736/// [Foo()]
1757pub struct B<|>ar 1737pub struct B$0ar
1758"#, 1738"#,
1759 expect![[r#" 1739 expect![[r#"
1760 *Bar* 1740 *Bar*
@@ -1780,7 +1760,7 @@ pub struct B<|>ar
1780 r#" 1760 r#"
1781pub struct Foo; 1761pub struct Foo;
1782/// [`struct Foo`] 1762/// [`struct Foo`]
1783pub struct B<|>ar 1763pub struct B$0ar
1784"#, 1764"#,
1785 expect![[r#" 1765 expect![[r#"
1786 *Bar* 1766 *Bar*
@@ -1806,7 +1786,7 @@ pub struct B<|>ar
1806 r#" 1786 r#"
1807pub struct Foo; 1787pub struct Foo;
1808/// [`struct@Foo`] 1788/// [`struct@Foo`]
1809pub struct B<|>ar 1789pub struct B$0ar
1810"#, 1790"#,
1811 expect![[r#" 1791 expect![[r#"
1812 *Bar* 1792 *Bar*
@@ -1834,7 +1814,7 @@ pub struct Foo;
1834/// [my Foo][foo] 1814/// [my Foo][foo]
1835/// 1815///
1836/// [foo]: Foo 1816/// [foo]: Foo
1837pub struct B<|>ar 1817pub struct B$0ar
1838"#, 1818"#,
1839 expect![[r#" 1819 expect![[r#"
1840 *Bar* 1820 *Bar*
@@ -1860,7 +1840,7 @@ pub struct B<|>ar
1860 r#" 1840 r#"
1861pub struct Foo; 1841pub struct Foo;
1862/// [external](https://www.google.com) 1842/// [external](https://www.google.com)
1863pub struct B<|>ar 1843pub struct B$0ar
1864"#, 1844"#,
1865 expect![[r#" 1845 expect![[r#"
1866 *Bar* 1846 *Bar*
@@ -1887,7 +1867,7 @@ pub struct B<|>ar
1887 r#" 1867 r#"
1888pub struct Foo; 1868pub struct Foo;
1889/// [baz](Baz) 1869/// [baz](Baz)
1890pub struct B<|>ar 1870pub struct B$0ar
1891"#, 1871"#,
1892 expect![[r#" 1872 expect![[r#"
1893 *Bar* 1873 *Bar*
@@ -1913,7 +1893,7 @@ pub struct B<|>ar
1913 r#" 1893 r#"
1914enum E { 1894enum E {
1915 /// [E] 1895 /// [E]
1916 V<|> { field: i32 } 1896 V$0 { field: i32 }
1917} 1897}
1918"#, 1898"#,
1919 expect![[r#" 1899 expect![[r#"
@@ -1940,7 +1920,7 @@ enum E {
1940 r#" 1920 r#"
1941struct S { 1921struct S {
1942 /// [`S`] 1922 /// [`S`]
1943 field<|>: i32 1923 field$0: i32
1944} 1924}
1945"#, 1925"#,
1946 expect![[r#" 1926 expect![[r#"
@@ -1968,16 +1948,16 @@ struct S {
1968/// Test cases: 1948/// Test cases:
1969/// case 1. bare URL: https://www.example.com/ 1949/// case 1. bare URL: https://www.example.com/
1970/// case 2. inline URL with title: [example](https://www.example.com/) 1950/// case 2. inline URL with title: [example](https://www.example.com/)
1971/// case 3. code refrence: [`Result`] 1951/// case 3. code reference: [`Result`]
1972/// case 4. code refrence but miss footnote: [`String`] 1952/// case 4. code reference but miss footnote: [`String`]
1973/// case 5. autolink: <http://www.example.com/> 1953/// case 5. autolink: <http://www.example.com/>
1974/// case 6. email address: <[email protected]> 1954/// case 6. email address: <[email protected]>
1975/// case 7. refrence: [example][example] 1955/// case 7. reference: [example][example]
1976/// case 8. collapsed link: [example][] 1956/// case 8. collapsed link: [example][]
1977/// case 9. shortcut link: [example] 1957/// case 9. shortcut link: [example]
1978/// case 10. inline without URL: [example]() 1958/// case 10. inline without URL: [example]()
1979/// case 11. refrence: [foo][foo] 1959/// case 11. reference: [foo][foo]
1980/// case 12. refrence: [foo][bar] 1960/// case 12. reference: [foo][bar]
1981/// case 13. collapsed link: [foo][] 1961/// case 13. collapsed link: [foo][]
1982/// case 14. shortcut link: [foo] 1962/// case 14. shortcut link: [foo]
1983/// case 15. inline without URL: [foo]() 1963/// case 15. inline without URL: [foo]()
@@ -1986,7 +1966,7 @@ struct S {
1986/// 1966///
1987/// [`Result`]: ../../std/result/enum.Result.html 1967/// [`Result`]: ../../std/result/enum.Result.html
1988/// [^example]: https://www.example.com/ 1968/// [^example]: https://www.example.com/
1989pub fn fo<|>o() {} 1969pub fn fo$0o() {}
1990"#, 1970"#,
1991 expect![[r#" 1971 expect![[r#"
1992 *foo* 1972 *foo*
@@ -2004,16 +1984,16 @@ pub fn fo<|>o() {}
2004 Test cases: 1984 Test cases:
2005 case 1. bare URL: https://www.example.com/ 1985 case 1. bare URL: https://www.example.com/
2006 case 2. inline URL with title: [example](https://www.example.com/) 1986 case 2. inline URL with title: [example](https://www.example.com/)
2007 case 3. code refrence: `Result` 1987 case 3. code reference: `Result`
2008 case 4. code refrence but miss footnote: `String` 1988 case 4. code reference but miss footnote: `String`
2009 case 5. autolink: http://www.example.com/ 1989 case 5. autolink: http://www.example.com/
2010 case 6. email address: [email protected] 1990 case 6. email address: [email protected]
2011 case 7. refrence: example 1991 case 7. reference: example
2012 case 8. collapsed link: example 1992 case 8. collapsed link: example
2013 case 9. shortcut link: example 1993 case 9. shortcut link: example
2014 case 10. inline without URL: example 1994 case 10. inline without URL: example
2015 case 11. refrence: foo 1995 case 11. reference: foo
2016 case 12. refrence: foo 1996 case 12. reference: foo
2017 case 13. collapsed link: foo 1997 case 13. collapsed link: foo
2018 case 14. shortcut link: foo 1998 case 14. shortcut link: foo
2019 case 15. inline without URL: foo 1999 case 15. inline without URL: foo
@@ -2043,7 +2023,7 @@ macro_rules! bar {
2043 2023
2044bar!(); 2024bar!();
2045 2025
2046fn foo() { let bar = Bar; bar.fo<|>o(); } 2026fn foo() { let bar = Bar; bar.fo$0o(); }
2047"#, 2027"#,
2048 expect![[r#" 2028 expect![[r#"
2049 *foo* 2029 *foo*
@@ -2081,7 +2061,7 @@ macro_rules! bar {
2081 2061
2082bar!(); 2062bar!();
2083 2063
2084fn foo() { let bar = Bar; bar.fo<|>o(); } 2064fn foo() { let bar = Bar; bar.fo$0o(); }
2085"#, 2065"#,
2086 expect![[r#" 2066 expect![[r#"
2087 *foo* 2067 *foo*
@@ -2104,7 +2084,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2104 #[test] 2084 #[test]
2105 fn test_hover_trait_has_impl_action() { 2085 fn test_hover_trait_has_impl_action() {
2106 check_actions( 2086 check_actions(
2107 r#"trait foo<|>() {}"#, 2087 r#"trait foo$0() {}"#,
2108 expect![[r#" 2088 expect![[r#"
2109 [ 2089 [
2110 Implementation( 2090 Implementation(
@@ -2123,7 +2103,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2123 #[test] 2103 #[test]
2124 fn test_hover_struct_has_impl_action() { 2104 fn test_hover_struct_has_impl_action() {
2125 check_actions( 2105 check_actions(
2126 r"struct foo<|>() {}", 2106 r"struct foo$0() {}",
2127 expect![[r#" 2107 expect![[r#"
2128 [ 2108 [
2129 Implementation( 2109 Implementation(
@@ -2142,7 +2122,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2142 #[test] 2122 #[test]
2143 fn test_hover_union_has_impl_action() { 2123 fn test_hover_union_has_impl_action() {
2144 check_actions( 2124 check_actions(
2145 r#"union foo<|>() {}"#, 2125 r#"union foo$0() {}"#,
2146 expect![[r#" 2126 expect![[r#"
2147 [ 2127 [
2148 Implementation( 2128 Implementation(
@@ -2161,7 +2141,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2161 #[test] 2141 #[test]
2162 fn test_hover_enum_has_impl_action() { 2142 fn test_hover_enum_has_impl_action() {
2163 check_actions( 2143 check_actions(
2164 r"enum foo<|>() { A, B }", 2144 r"enum foo$0() { A, B }",
2165 expect![[r#" 2145 expect![[r#"
2166 [ 2146 [
2167 Implementation( 2147 Implementation(
@@ -2180,7 +2160,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2180 #[test] 2160 #[test]
2181 fn test_hover_self_has_impl_action() { 2161 fn test_hover_self_has_impl_action() {
2182 check_actions( 2162 check_actions(
2183 r#"struct foo where Self<|>:;"#, 2163 r#"struct foo where Self$0:;"#,
2184 expect![[r#" 2164 expect![[r#"
2185 [ 2165 [
2186 Implementation( 2166 Implementation(
@@ -2201,7 +2181,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2201 check_actions( 2181 check_actions(
2202 r#" 2182 r#"
2203#[test] 2183#[test]
2204fn foo_<|>test() {} 2184fn foo_$0test() {}
2205"#, 2185"#,
2206 expect![[r#" 2186 expect![[r#"
2207 [ 2187 [
@@ -2236,7 +2216,7 @@ fn foo_<|>test() {}
2236 fn test_hover_test_mod_has_action() { 2216 fn test_hover_test_mod_has_action() {
2237 check_actions( 2217 check_actions(
2238 r#" 2218 r#"
2239mod tests<|> { 2219mod tests$0 {
2240 #[test] 2220 #[test]
2241 fn foo_test() {} 2221 fn foo_test() {}
2242} 2222}
@@ -2271,7 +2251,7 @@ mod tests<|> {
2271 r#" 2251 r#"
2272struct S{ f1: u32 } 2252struct S{ f1: u32 }
2273 2253
2274fn main() { let s<|>t = S{ f1:0 }; } 2254fn main() { let s$0t = S{ f1:0 }; }
2275 "#, 2255 "#,
2276 expect![[r#" 2256 expect![[r#"
2277 [ 2257 [
@@ -2304,7 +2284,7 @@ fn main() { let s<|>t = S{ f1:0 }; }
2304struct Arg(u32); 2284struct Arg(u32);
2305struct S<T>{ f1: T } 2285struct S<T>{ f1: T }
2306 2286
2307fn main() { let s<|>t = S{ f1:Arg(0) }; } 2287fn main() { let s$0t = S{ f1:Arg(0) }; }
2308"#, 2288"#,
2309 expect![[r#" 2289 expect![[r#"
2310 [ 2290 [
@@ -2350,7 +2330,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; }
2350struct Arg(u32); 2330struct Arg(u32);
2351struct S<T>{ f1: T } 2331struct S<T>{ f1: T }
2352 2332
2353fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } 2333fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
2354 "#, 2334 "#,
2355 expect![[r#" 2335 expect![[r#"
2356 [ 2336 [
@@ -2399,7 +2379,7 @@ mod M {
2399 pub struct C(u32); 2379 pub struct C(u32);
2400} 2380}
2401 2381
2402fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } 2382fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
2403"#, 2383"#,
2404 expect![[r#" 2384 expect![[r#"
2405 [ 2385 [
@@ -2458,7 +2438,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
2458trait Foo {} 2438trait Foo {}
2459fn foo() -> impl Foo {} 2439fn foo() -> impl Foo {}
2460 2440
2461fn main() { let s<|>t = foo(); } 2441fn main() { let s$0t = foo(); }
2462"#, 2442"#,
2463 expect![[r#" 2443 expect![[r#"
2464 [ 2444 [
@@ -2492,7 +2472,7 @@ trait Foo<T> {}
2492struct S; 2472struct S;
2493fn foo() -> impl Foo<S> {} 2473fn foo() -> impl Foo<S> {}
2494 2474
2495fn main() { let s<|>t = foo(); } 2475fn main() { let s$0t = foo(); }
2496"#, 2476"#,
2497 expect![[r#" 2477 expect![[r#"
2498 [ 2478 [
@@ -2539,7 +2519,7 @@ trait Foo {}
2539trait Bar {} 2519trait Bar {}
2540fn foo() -> impl Foo + Bar {} 2520fn foo() -> impl Foo + Bar {}
2541 2521
2542fn main() { let s<|>t = foo(); } 2522fn main() { let s$0t = foo(); }
2543 "#, 2523 "#,
2544 expect![[r#" 2524 expect![[r#"
2545 [ 2525 [
@@ -2589,7 +2569,7 @@ struct S2 {}
2589 2569
2590fn foo() -> impl Foo<S1> + Bar<S2> {} 2570fn foo() -> impl Foo<S1> + Bar<S2> {}
2591 2571
2592fn main() { let s<|>t = foo(); } 2572fn main() { let s$0t = foo(); }
2593"#, 2573"#,
2594 expect![[r#" 2574 expect![[r#"
2595 [ 2575 [
@@ -2659,7 +2639,7 @@ fn main() { let s<|>t = foo(); }
2659 check_actions( 2639 check_actions(
2660 r#" 2640 r#"
2661trait Foo {} 2641trait Foo {}
2662fn foo(ar<|>g: &impl Foo) {} 2642fn foo(ar$0g: &impl Foo) {}
2663"#, 2643"#,
2664 expect![[r#" 2644 expect![[r#"
2665 [ 2645 [
@@ -2693,7 +2673,7 @@ trait Foo {}
2693trait Bar<T> {} 2673trait Bar<T> {}
2694struct S{} 2674struct S{}
2695 2675
2696fn foo(ar<|>g: &impl Foo + Bar<S>) {} 2676fn foo(ar$0g: &impl Foo + Bar<S>) {}
2697"#, 2677"#,
2698 expect![[r#" 2678 expect![[r#"
2699 [ 2679 [
@@ -2751,7 +2731,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2751 r#" 2731 r#"
2752struct S; 2732struct S;
2753fn foo() { 2733fn foo() {
2754 let fo<|>o = async { S }; 2734 let fo$0o = async { S };
2755} 2735}
2756 2736
2757#[prelude_import] use future::*; 2737#[prelude_import] use future::*;
@@ -2803,7 +2783,7 @@ mod future {
2803 r#" 2783 r#"
2804trait Foo<T> {} 2784trait Foo<T> {}
2805struct S {} 2785struct S {}
2806fn foo(ar<|>g: &impl Foo<S>) {} 2786fn foo(ar$0g: &impl Foo<S>) {}
2807"#, 2787"#,
2808 expect![[r#" 2788 expect![[r#"
2809 [ 2789 [
@@ -2853,7 +2833,7 @@ impl Foo for S {}
2853struct B<T>{} 2833struct B<T>{}
2854fn foo() -> B<dyn Foo> {} 2834fn foo() -> B<dyn Foo> {}
2855 2835
2856fn main() { let s<|>t = foo(); } 2836fn main() { let s$0t = foo(); }
2857"#, 2837"#,
2858 expect![[r#" 2838 expect![[r#"
2859 [ 2839 [
@@ -2897,7 +2877,7 @@ fn main() { let s<|>t = foo(); }
2897 check_actions( 2877 check_actions(
2898 r#" 2878 r#"
2899trait Foo {} 2879trait Foo {}
2900fn foo(ar<|>g: &dyn Foo) {} 2880fn foo(ar$0g: &dyn Foo) {}
2901"#, 2881"#,
2902 expect![[r#" 2882 expect![[r#"
2903 [ 2883 [
@@ -2929,7 +2909,7 @@ fn foo(ar<|>g: &dyn Foo) {}
2929 r#" 2909 r#"
2930trait Foo<T> {} 2910trait Foo<T> {}
2931struct S {} 2911struct S {}
2932fn foo(ar<|>g: &dyn Foo<S>) {} 2912fn foo(ar$0g: &dyn Foo<S>) {}
2933"#, 2913"#,
2934 expect![[r#" 2914 expect![[r#"
2935 [ 2915 [
@@ -2977,7 +2957,7 @@ trait DynTrait<T> {}
2977struct B<T> {} 2957struct B<T> {}
2978struct S {} 2958struct S {}
2979 2959
2980fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} 2960fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2981 "#, 2961 "#,
2982 expect![[r#" 2962 expect![[r#"
2983 [ 2963 [
@@ -3058,7 +3038,7 @@ impl Foo for S { type Item = Bar; }
3058 3038
3059fn test() -> impl Foo { S {} } 3039fn test() -> impl Foo { S {} }
3060 3040
3061fn main() { let s<|>t = test().get(); } 3041fn main() { let s$0t = test().get(); }
3062"#, 3042"#,
3063 expect![[r#" 3043 expect![[r#"
3064 [ 3044 [
@@ -3091,7 +3071,7 @@ fn main() { let s<|>t = test().get(); }
3091struct Bar; 3071struct Bar;
3092struct Foo<const BAR: Bar>; 3072struct Foo<const BAR: Bar>;
3093 3073
3094impl<const BAR: Bar> Foo<BAR<|>> {} 3074impl<const BAR: Bar> Foo<BAR$0> {}
3095"#, 3075"#,
3096 expect![[r#" 3076 expect![[r#"
3097 [ 3077 [
@@ -3123,7 +3103,7 @@ impl<const BAR: Bar> Foo<BAR<|>> {}
3123 r#" 3103 r#"
3124trait Foo {} 3104trait Foo {}
3125 3105
3126fn foo<T: Foo>(t: T<|>){} 3106fn foo<T: Foo>(t: T$0){}
3127"#, 3107"#,
3128 expect![[r#" 3108 expect![[r#"
3129 [ 3109 [
@@ -3163,7 +3143,7 @@ pub mod wrapper {
3163} 3143}
3164 3144
3165//- /main.rs crate:main deps:name-with-dashes 3145//- /main.rs crate:main deps:name-with-dashes
3166fn main() { let foo_test = name_with_dashes::wrapper::Thing::new<|>(); } 3146fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
3167"#, 3147"#,
3168 expect![[r#" 3148 expect![[r#"
3169 *new* 3149 *new*
@@ -3189,7 +3169,7 @@ struct S {
3189 3169
3190fn main() { 3170fn main() {
3191 let s = S { f: 0 }; 3171 let s = S { f: 0 };
3192 let S { f<|> } = &s; 3172 let S { f$0 } = &s;
3193} 3173}
3194"#, 3174"#,
3195 expect![[r#" 3175 expect![[r#"
@@ -3208,7 +3188,7 @@ fn main() {
3208 r#" 3188 r#"
3209struct Foo {} 3189struct Foo {}
3210impl Foo { 3190impl Foo {
3211 fn bar(&sel<|>f) {} 3191 fn bar(&sel$0f) {}
3212} 3192}
3213"#, 3193"#,
3214 expect![[r#" 3194 expect![[r#"
@@ -3227,7 +3207,7 @@ impl Foo {
3227struct Arc<T>(T); 3207struct Arc<T>(T);
3228struct Foo {} 3208struct Foo {}
3229impl Foo { 3209impl Foo {
3230 fn bar(sel<|>f: Arc<Foo>) {} 3210 fn bar(sel$0f: Arc<Foo>) {}
3231} 3211}
3232"#, 3212"#,
3233 expect![[r#" 3213 expect![[r#"
@@ -3244,7 +3224,7 @@ impl Foo {
3244 check( 3224 check(
3245 r#" 3225 r#"
3246/// Be quick; 3226/// Be quick;
3247mod Foo<|> { 3227mod Foo$0 {
3248 //! time is mana 3228 //! time is mana
3249 3229
3250 /// This comment belongs to the function 3230 /// This comment belongs to the function
@@ -3275,7 +3255,7 @@ mod Foo<|> {
3275 check( 3255 check(
3276 r#" 3256 r#"
3277#[doc = "Be quick;"] 3257#[doc = "Be quick;"]
3278mod Foo<|> { 3258mod Foo$0 {
3279 #![doc = "time is mana"] 3259 #![doc = "time is mana"]
3280 3260
3281 #[doc = "This comment belongs to the function"] 3261 #[doc = "This comment belongs to the function"]
@@ -3306,7 +3286,7 @@ mod Foo<|> {
3306 check_hover_no_result( 3286 check_hover_no_result(
3307 r#" 3287 r#"
3308fn no_hover() { 3288fn no_hover() {
3309 // no<|>hover 3289 // no$0hover
3310} 3290}
3311"#, 3291"#,
3312 ); 3292 );
@@ -3317,7 +3297,7 @@ fn no_hover() {
3317 check( 3297 check(
3318 r#" 3298 r#"
3319fn foo() { 3299fn foo() {
3320 'label<|>: loop {} 3300 'label$0: loop {}
3321} 3301}
3322"#, 3302"#,
3323 expect![[r#" 3303 expect![[r#"
@@ -3333,7 +3313,7 @@ fn foo() {
3333 #[test] 3313 #[test]
3334 fn hover_lifetime() { 3314 fn hover_lifetime() {
3335 check( 3315 check(
3336 r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#, 3316 r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#,
3337 expect![[r#" 3317 expect![[r#"
3338 *'lifetime* 3318 *'lifetime*
3339 3319
@@ -3352,7 +3332,7 @@ struct Foo<T>(T);
3352trait Copy {} 3332trait Copy {}
3353trait Clone {} 3333trait Clone {}
3354trait Sized {} 3334trait Sized {}
3355impl<T: Copy + Clone> Foo<T<|>> where T: Sized {} 3335impl<T: Copy + Clone> Foo<T$0> where T: Sized {}
3356"#, 3336"#,
3357 expect![[r#" 3337 expect![[r#"
3358 *T* 3338 *T*
@@ -3365,7 +3345,7 @@ impl<T: Copy + Clone> Foo<T<|>> where T: Sized {}
3365 check( 3345 check(
3366 r#" 3346 r#"
3367struct Foo<T>(T); 3347struct Foo<T>(T);
3368impl<T> Foo<T<|>> {} 3348impl<T> Foo<T$0> {}
3369"#, 3349"#,
3370 expect![[r#" 3350 expect![[r#"
3371 *T* 3351 *T*
@@ -3379,7 +3359,7 @@ impl<T> Foo<T<|>> {}
3379 check( 3359 check(
3380 r#" 3360 r#"
3381struct Foo<T>(T); 3361struct Foo<T>(T);
3382impl<T: 'static> Foo<T<|>> {} 3362impl<T: 'static> Foo<T$0> {}
3383"#, 3363"#,
3384 expect![[r#" 3364 expect![[r#"
3385 *T* 3365 *T*
@@ -3396,7 +3376,7 @@ impl<T: 'static> Foo<T<|>> {}
3396 check( 3376 check(
3397 r#" 3377 r#"
3398struct Foo<const LEN: usize>; 3378struct Foo<const LEN: usize>;
3399impl<const LEN: usize> Foo<LEN<|>> {} 3379impl<const LEN: usize> Foo<LEN$0> {}
3400"#, 3380"#,
3401 expect![[r#" 3381 expect![[r#"
3402 *LEN* 3382 *LEN*
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 65df7979c..3e9a65d9c 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -18,12 +18,6 @@ pub struct InlayHintsConfig {
18 pub max_length: Option<usize>, 18 pub max_length: Option<usize>,
19} 19}
20 20
21impl Default for InlayHintsConfig {
22 fn default() -> Self {
23 Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None }
24 }
25}
26
27#[derive(Clone, Debug, PartialEq, Eq)] 21#[derive(Clone, Debug, PartialEq, Eq)]
28pub enum InlayKind { 22pub enum InlayKind {
29 TypeHint, 23 TypeHint,
@@ -359,9 +353,25 @@ fn is_argument_similar_to_param_name(
359 } 353 }
360 match get_string_representation(argument) { 354 match get_string_representation(argument) {
361 None => false, 355 None => false,
362 Some(repr) => { 356 Some(argument_string) => {
363 let argument_string = repr.trim_start_matches('_'); 357 let num_leading_underscores =
364 argument_string.starts_with(param_name) || argument_string.ends_with(param_name) 358 argument_string.bytes().take_while(|&c| c == b'_').count();
359
360 // Does the argument name begin with the parameter name? Ignore leading underscores.
361 let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
362 let starts_with_pattern = param_name.bytes().all(
363 |expected| matches!(arg_bytes.next(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
364 );
365
366 if starts_with_pattern {
367 return true;
368 }
369
370 // Does the argument name end with the parameter name?
371 let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
372 param_name.bytes().rev().all(
373 |expected| matches!(arg_bytes.next_back(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
374 )
365 } 375 }
366 } 376 }
367} 377}
@@ -433,8 +443,15 @@ mod tests {
433 443
434 use crate::{fixture, inlay_hints::InlayHintsConfig}; 444 use crate::{fixture, inlay_hints::InlayHintsConfig};
435 445
446 const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
447 type_hints: true,
448 parameter_hints: true,
449 chaining_hints: true,
450 max_length: None,
451 };
452
436 fn check(ra_fixture: &str) { 453 fn check(ra_fixture: &str) {
437 check_with_config(InlayHintsConfig::default(), ra_fixture); 454 check_with_config(TEST_CONFIG, ra_fixture);
438 } 455 }
439 456
440 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { 457 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
@@ -748,7 +765,7 @@ fn main() {
748 #[test] 765 #[test]
749 fn hint_truncation() { 766 fn hint_truncation() {
750 check_with_config( 767 check_with_config(
751 InlayHintsConfig { max_length: Some(8), ..Default::default() }, 768 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
752 r#" 769 r#"
753struct Smol<T>(T); 770struct Smol<T>(T);
754 771
@@ -831,7 +848,7 @@ fn main() {
831 #[test] 848 #[test]
832 fn omitted_parameters_hints_heuristics() { 849 fn omitted_parameters_hints_heuristics() {
833 check_with_config( 850 check_with_config(
834 InlayHintsConfig { max_length: Some(8), ..Default::default() }, 851 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
835 r#" 852 r#"
836fn map(f: i32) {} 853fn map(f: i32) {}
837fn filter(predicate: i32) {} 854fn filter(predicate: i32) {}
@@ -900,6 +917,9 @@ fn main() {
900 twiddle(true); 917 twiddle(true);
901 doo(true); 918 doo(true);
902 919
920 const TWIDDLE_UPPERCASE: bool = true;
921 twiddle(TWIDDLE_UPPERCASE);
922
903 let mut param_begin: Param = Param {}; 923 let mut param_begin: Param = Param {};
904 different_order(&param_begin); 924 different_order(&param_begin);
905 different_order(&mut param_begin); 925 different_order(&mut param_begin);
@@ -924,7 +944,7 @@ fn main() {
924 #[test] 944 #[test]
925 fn unit_structs_have_no_type_hints() { 945 fn unit_structs_have_no_type_hints() {
926 check_with_config( 946 check_with_config(
927 InlayHintsConfig { max_length: Some(8), ..Default::default() }, 947 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
928 r#" 948 r#"
929enum Result<T, E> { Ok(T), Err(E) } 949enum Result<T, E> { Ok(T), Err(E) }
930use Result::*; 950use Result::*;
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index b5a6f66fd..05380f2a1 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -104,7 +104,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
104 // Special case that turns something like: 104 // Special case that turns something like:
105 // 105 //
106 // ``` 106 // ```
107 // my_function({<|> 107 // my_function({$0
108 // <some-expr> 108 // <some-expr>
109 // }) 109 // })
110 // ``` 110 // ```
@@ -116,7 +116,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
116 // ditto for 116 // ditto for
117 // 117 //
118 // ``` 118 // ```
119 // use foo::{<|> 119 // use foo::{$0
120 // bar 120 // bar
121 // }; 121 // };
122 // ``` 122 // ```
@@ -198,8 +198,8 @@ mod tests {
198 198
199 use super::*; 199 use super::*;
200 200
201 fn check_join_lines(before: &str, after: &str) { 201 fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) {
202 let (before_cursor_pos, before) = extract_offset(before); 202 let (before_cursor_pos, before) = extract_offset(ra_fixture_before);
203 let file = SourceFile::parse(&before).ok().unwrap(); 203 let file = SourceFile::parse(&before).ok().unwrap();
204 204
205 let range = TextRange::empty(before_cursor_pos); 205 let range = TextRange::empty(before_cursor_pos);
@@ -214,7 +214,7 @@ mod tests {
214 .apply_to_offset(before_cursor_pos) 214 .apply_to_offset(before_cursor_pos)
215 .expect("cursor position is affected by the edit"); 215 .expect("cursor position is affected by the edit");
216 let actual = add_cursor(&actual, actual_cursor_pos); 216 let actual = add_cursor(&actual, actual_cursor_pos);
217 assert_eq_text!(after, &actual); 217 assert_eq_text!(ra_fixture_after, &actual);
218 } 218 }
219 219
220 #[test] 220 #[test]
@@ -222,13 +222,13 @@ mod tests {
222 check_join_lines( 222 check_join_lines(
223 r" 223 r"
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 a450794f3..1e03832ec 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -76,14 +76,14 @@ 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}; 83pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig};
84pub use completion::{ 84pub use completion::{
85 CompletionConfig, CompletionItem, CompletionItemKind, CompletionResolveCapability, 85 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit,
86 CompletionScore, ImportEdit, InsertTextFormat, 86 InsertTextFormat,
87}; 87};
88pub use hir::{Documentation, Semantics}; 88pub use hir::{Documentation, Semantics};
89pub use ide_db::base_db::{ 89pub use ide_db::base_db::{
@@ -92,7 +92,7 @@ pub use ide_db::base_db::{
92}; 92};
93pub use ide_db::{ 93pub use ide_db::{
94 call_info::CallInfo, 94 call_info::CallInfo,
95 search::{Reference, ReferenceAccess, ReferenceKind}, 95 search::{FileReference, ReferenceAccess, ReferenceKind},
96}; 96};
97pub use ide_db::{ 97pub use ide_db::{
98 label::Label, 98 label::Label,
@@ -449,12 +449,12 @@ impl Analysis {
449 } 449 }
450 450
451 /// Computes syntax highlighting for the given file 451 /// Computes syntax highlighting for the given file
452 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { 452 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HlRange>> {
453 self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) 453 self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false))
454 } 454 }
455 455
456 /// Computes syntax highlighting for the given file range. 456 /// Computes syntax highlighting for the given file range.
457 pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HighlightedRange>> { 457 pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HlRange>> {
458 self.with_db(|db| { 458 self.with_db(|db| {
459 syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) 459 syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false)
460 }) 460 })
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs
index d70248afe..1bfa1439d 100644
--- a/crates/ide/src/matching_brace.rs
+++ b/crates/ide/src/matching_brace.rs
@@ -58,15 +58,15 @@ mod tests {
58 assert_eq_text!(after, &actual); 58 assert_eq_text!(after, &actual);
59 } 59 }
60 60
61 do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); 61 do_check("struct Foo { a: i32, }$0", "struct Foo $0{ a: i32, }");
62 do_check("fn main() { |x: i32|<|> x * 2;}", "fn main() { <|>|x: i32| x * 2;}"); 62 do_check("fn main() { |x: i32|$0 x * 2;}", "fn main() { $0|x: i32| x * 2;}");
63 do_check("fn main() { <|>|x: i32| x * 2;}", "fn main() { |x: i32<|>| x * 2;}"); 63 do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}");
64 64
65 { 65 {
66 mark::check!(pipes_not_braces); 66 mark::check!(pipes_not_braces);
67 do_check( 67 do_check(
68 "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", 68 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }",
69 "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }", 69 "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }",
70 ); 70 );
71 } 71 }
72 } 72 }
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index be344a09b..d343638fb 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -74,7 +74,7 @@ mod tests {
74 //- /lib.rs 74 //- /lib.rs
75 mod foo; 75 mod foo;
76 //- /foo.rs 76 //- /foo.rs
77 <|>// empty 77 $0// empty
78 ", 78 ",
79 ); 79 );
80 let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); 80 let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
@@ -90,7 +90,7 @@ mod tests {
90 mod foo; 90 mod foo;
91 91
92 //- /foo.rs 92 //- /foo.rs
93 mod <|>bar; 93 mod $0bar;
94 94
95 //- /foo/bar.rs 95 //- /foo/bar.rs
96 // empty 96 // empty
@@ -107,7 +107,7 @@ mod tests {
107 //- /lib.rs 107 //- /lib.rs
108 mod foo { 108 mod foo {
109 mod bar { 109 mod bar {
110 mod baz { <|> } 110 mod baz { $0 }
111 } 111 }
112 } 112 }
113 ", 113 ",
@@ -123,7 +123,7 @@ mod tests {
123//- /main.rs 123//- /main.rs
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..7d4757e02 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -3,7 +3,7 @@
3//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we 3//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we
4//! try to resolve the direct tree parent of this element, otherwise we 4//! try to resolve the direct tree parent of this element, otherwise we
5//! already have a definition and just need to get its HIR together with 5//! already have a definition and just need to get its HIR together with
6//! some information that is needed for futher steps of searching. 6//! some information that is needed for further steps of searching.
7//! After that, we collect files that might contain references and look 7//! After that, we collect files that might contain references and look
8//! for text occurrences of the identifier. If there's an `ast::NameRef` 8//! for text occurrences of the identifier. If there's an `ast::NameRef`
9//! at the index that the match starts at and its tree parent is 9//! at the index that the match starts at and its tree parent is
@@ -13,15 +13,15 @@ pub(crate) mod rename;
13 13
14use hir::Semantics; 14use hir::Semantics;
15use ide_db::{ 15use ide_db::{
16 base_db::FileId,
16 defs::{Definition, NameClass, NameRefClass}, 17 defs::{Definition, NameClass, NameRefClass},
17 search::Reference, 18 search::{FileReference, ReferenceAccess, ReferenceKind, SearchScope, UsageSearchResult},
18 search::{ReferenceAccess, ReferenceKind, SearchScope},
19 RootDatabase, 19 RootDatabase,
20}; 20};
21use syntax::{ 21use syntax::{
22 algo::find_node_at_offset, 22 algo::find_node_at_offset,
23 ast::{self, NameOwner}, 23 ast::{self, NameOwner},
24 match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset, 24 match_ast, AstNode, SyntaxNode, TextRange, TokenAtOffset, T,
25}; 25};
26 26
27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind}; 27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, SymbolKind};
@@ -29,7 +29,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI
29#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
30pub struct ReferenceSearchResult { 30pub struct ReferenceSearchResult {
31 declaration: Declaration, 31 declaration: Declaration,
32 references: Vec<Reference>, 32 references: UsageSearchResult,
33} 33}
34 34
35#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
@@ -48,10 +48,21 @@ impl ReferenceSearchResult {
48 &self.declaration.nav 48 &self.declaration.nav
49 } 49 }
50 50
51 pub fn references(&self) -> &[Reference] { 51 pub fn references(&self) -> &UsageSearchResult {
52 &self.references 52 &self.references
53 } 53 }
54 54
55 pub fn references_with_declaration(mut self) -> UsageSearchResult {
56 let decl_ref = FileReference {
57 range: self.declaration.nav.focus_or_full_range(),
58 kind: self.declaration.kind,
59 access: self.declaration.access,
60 };
61 let file_id = self.declaration.nav.file_id;
62 self.references.references.entry(file_id).or_default().push(decl_ref);
63 self.references
64 }
65
55 /// Total number of references 66 /// Total number of references
56 /// At least 1 since all valid references should 67 /// At least 1 since all valid references should
57 /// Have a declaration 68 /// Have a declaration
@@ -63,21 +74,11 @@ impl ReferenceSearchResult {
63// allow turning ReferenceSearchResult into an iterator 74// allow turning ReferenceSearchResult into an iterator
64// over References 75// over References
65impl IntoIterator for ReferenceSearchResult { 76impl IntoIterator for ReferenceSearchResult {
66 type Item = Reference; 77 type Item = (FileId, Vec<FileReference>);
67 type IntoIter = std::vec::IntoIter<Reference>; 78 type IntoIter = std::collections::hash_map::IntoIter<FileId, Vec<FileReference>>;
68 79
69 fn into_iter(mut self) -> Self::IntoIter { 80 fn into_iter(self) -> Self::IntoIter {
70 let mut v = Vec::with_capacity(self.len()); 81 self.references_with_declaration().into_iter()
71 v.push(Reference {
72 file_range: FileRange {
73 file_id: self.declaration.nav.file_id,
74 range: self.declaration.nav.focus_or_full_range(),
75 },
76 kind: self.declaration.kind,
77 access: self.declaration.access,
78 });
79 v.append(&mut self.references);
80 v.into_iter()
81 } 82 }
82} 83}
83 84
@@ -109,13 +110,12 @@ pub(crate) fn find_all_refs(
109 110
110 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 111 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
111 112
112 let references = def 113 let mut usages = def.usages(sema).set_scope(search_scope).all();
113 .usages(sema) 114 usages
114 .set_scope(search_scope) 115 .references
115 .all() 116 .values_mut()
116 .into_iter() 117 .for_each(|it| it.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind));
117 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 118 usages.references.retain(|_, it| !it.is_empty());
118 .collect();
119 119
120 let nav = def.try_to_nav(sema.db)?; 120 let nav = def.try_to_nav(sema.db)?;
121 let decl_range = nav.focus_or_full_range(); 121 let decl_range = nav.focus_or_full_range();
@@ -130,13 +130,16 @@ pub(crate) fn find_all_refs(
130 kind = ReferenceKind::FieldShorthandForLocal; 130 kind = ReferenceKind::FieldShorthandForLocal;
131 } 131 }
132 } 132 }
133 } else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) { 133 } else if matches!(
134 def,
135 Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
136 ) {
134 kind = ReferenceKind::Lifetime; 137 kind = ReferenceKind::Lifetime;
135 }; 138 };
136 139
137 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) }; 140 let declaration = Declaration { nav, kind, access: decl_access(&def, &syntax, decl_range) };
138 141
139 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 142 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references: usages }))
140} 143}
141 144
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) =
@@ -252,8 +255,8 @@ fn try_find_self_references(
252 syntax: &SyntaxNode, 255 syntax: &SyntaxNode,
253 position: FilePosition, 256 position: FilePosition,
254) -> Option<RangeInfo<ReferenceSearchResult>> { 257) -> Option<RangeInfo<ReferenceSearchResult>> {
255 let self_token = 258 let FilePosition { file_id, offset } = position;
256 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)?; 259 let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?;
257 let parent = self_token.parent(); 260 let parent = self_token.parent();
258 match_ast! { 261 match_ast! {
259 match parent { 262 match parent {
@@ -274,7 +277,7 @@ fn try_find_self_references(
274 277
275 let declaration = Declaration { 278 let declaration = Declaration {
276 nav: NavigationTarget { 279 nav: NavigationTarget {
277 file_id: position.file_id, 280 file_id,
278 full_range: self_param.syntax().text_range(), 281 full_range: self_param.syntax().text_range(),
279 focus_range: Some(param_self_token.text_range()), 282 focus_range: Some(param_self_token.text_range()),
280 name: param_self_token.text().clone(), 283 name: param_self_token.text().clone(),
@@ -290,7 +293,7 @@ fn try_find_self_references(
290 ReferenceAccess::Read 293 ReferenceAccess::Read
291 }), 294 }),
292 }; 295 };
293 let references = function 296 let refs = function
294 .body() 297 .body()
295 .map(|body| { 298 .map(|body| {
296 body.syntax() 299 body.syntax()
@@ -304,14 +307,16 @@ fn try_find_self_references(
304 None 307 None
305 } 308 }
306 }) 309 })
307 .map(|token| Reference { 310 .map(|token| FileReference {
308 file_range: FileRange { file_id: position.file_id, range: token.text_range() }, 311 range: token.text_range(),
309 kind: ReferenceKind::SelfKw, 312 kind: ReferenceKind::SelfKw,
310 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration 313 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
311 }) 314 })
312 .collect() 315 .collect()
313 }) 316 })
314 .unwrap_or_default(); 317 .unwrap_or_default();
318 let mut references = UsageSearchResult::default();
319 references.references.insert(file_id, refs);
315 320
316 Some(RangeInfo::new( 321 Some(RangeInfo::new(
317 param_self_token.text_range(), 322 param_self_token.text_range(),
@@ -331,7 +336,7 @@ mod tests {
331 fn test_struct_literal_after_space() { 336 fn test_struct_literal_after_space() {
332 check( 337 check(
333 r#" 338 r#"
334struct Foo <|>{ 339struct Foo $0{
335 a: i32, 340 a: i32,
336} 341}
337impl Foo { 342impl Foo {
@@ -354,7 +359,7 @@ fn main() {
354 fn test_struct_literal_before_space() { 359 fn test_struct_literal_before_space() {
355 check( 360 check(
356 r#" 361 r#"
357struct Foo<|> {} 362struct Foo$0 {}
358 fn main() { 363 fn main() {
359 let f: Foo; 364 let f: Foo;
360 f = Foo {}; 365 f = Foo {};
@@ -373,7 +378,7 @@ struct Foo<|> {}
373 fn test_struct_literal_with_generic_type() { 378 fn test_struct_literal_with_generic_type() {
374 check( 379 check(
375 r#" 380 r#"
376struct Foo<T> <|>{} 381struct Foo<T> $0{}
377 fn main() { 382 fn main() {
378 let f: Foo::<i32>; 383 let f: Foo::<i32>;
379 f = Foo {}; 384 f = Foo {};
@@ -391,7 +396,7 @@ struct Foo<T> <|>{}
391 fn test_struct_literal_for_tuple() { 396 fn test_struct_literal_for_tuple() {
392 check( 397 check(
393 r#" 398 r#"
394struct Foo<|>(i32); 399struct Foo$0(i32);
395 400
396fn main() { 401fn main() {
397 let f: Foo; 402 let f: Foo;
@@ -410,7 +415,7 @@ fn main() {
410 fn test_enum_after_space() { 415 fn test_enum_after_space() {
411 check( 416 check(
412 r#" 417 r#"
413enum Foo <|>{ 418enum Foo $0{
414 A, 419 A,
415 B, 420 B,
416} 421}
@@ -431,7 +436,7 @@ fn main() {
431 fn test_enum_before_space() { 436 fn test_enum_before_space() {
432 check( 437 check(
433 r#" 438 r#"
434enum Foo<|> { 439enum Foo$0 {
435 A, 440 A,
436 B, 441 B,
437} 442}
@@ -453,7 +458,7 @@ fn main() {
453 fn test_enum_with_generic_type() { 458 fn test_enum_with_generic_type() {
454 check( 459 check(
455 r#" 460 r#"
456enum Foo<T> <|>{ 461enum Foo<T> $0{
457 A(T), 462 A(T),
458 B, 463 B,
459} 464}
@@ -474,7 +479,7 @@ fn main() {
474 fn test_enum_for_tuple() { 479 fn test_enum_for_tuple() {
475 check( 480 check(
476 r#" 481 r#"
477enum Foo<|>{ 482enum Foo$0{
478 A(i8), 483 A(i8),
479 B(i8), 484 B(i8),
480} 485}
@@ -498,7 +503,7 @@ fn main() {
498fn main() { 503fn main() {
499 let mut i = 1; 504 let mut i = 1;
500 let j = 1; 505 let j = 1;
501 i = i<|> + j; 506 i = i$0 + j;
502 507
503 { 508 {
504 i = 0; 509 i = 0;
@@ -522,7 +527,7 @@ fn main() {
522 check( 527 check(
523 r#" 528 r#"
524fn foo() { 529fn foo() {
525 let spam<|> = 92; 530 let spam$0 = 92;
526 spam + spam 531 spam + spam
527} 532}
528fn bar() { 533fn bar() {
@@ -543,7 +548,7 @@ fn bar() {
543 fn test_find_all_refs_for_param_inside() { 548 fn test_find_all_refs_for_param_inside() {
544 check( 549 check(
545 r#" 550 r#"
546fn foo(i : u32) -> u32 { i<|> } 551fn foo(i : u32) -> u32 { i$0 }
547"#, 552"#,
548 expect![[r#" 553 expect![[r#"
549 i ValueParam FileId(0) 7..8 Other 554 i ValueParam FileId(0) 7..8 Other
@@ -557,7 +562,7 @@ fn foo(i : u32) -> u32 { i<|> }
557 fn test_find_all_refs_for_fn_param() { 562 fn test_find_all_refs_for_fn_param() {
558 check( 563 check(
559 r#" 564 r#"
560fn foo(i<|> : u32) -> u32 { i } 565fn foo(i$0 : u32) -> u32 { i }
561"#, 566"#,
562 expect![[r#" 567 expect![[r#"
563 i ValueParam FileId(0) 7..8 Other 568 i ValueParam FileId(0) 7..8 Other
@@ -573,7 +578,7 @@ fn foo(i<|> : u32) -> u32 { i }
573 r#" 578 r#"
574//- /lib.rs 579//- /lib.rs
575struct Foo { 580struct Foo {
576 pub spam<|>: u32, 581 pub spam$0: u32,
577} 582}
578 583
579fn main(s: Foo) { 584fn main(s: Foo) {
@@ -594,7 +599,7 @@ fn main(s: Foo) {
594 r#" 599 r#"
595struct Foo; 600struct Foo;
596impl Foo { 601impl Foo {
597 fn f<|>(&self) { } 602 fn f$0(&self) { }
598} 603}
599"#, 604"#,
600 expect![[r#" 605 expect![[r#"
@@ -610,7 +615,7 @@ impl Foo {
610 r#" 615 r#"
611enum Foo { 616enum Foo {
612 A, 617 A,
613 B<|>, 618 B$0,
614 C, 619 C,
615} 620}
616"#, 621"#,
@@ -627,7 +632,7 @@ enum Foo {
627 r#" 632 r#"
628enum Foo { 633enum Foo {
629 A, 634 A,
630 B { field<|>: u8 }, 635 B { field$0: u8 },
631 C, 636 C,
632} 637}
633"#, 638"#,
@@ -669,7 +674,7 @@ pub struct Bar {
669} 674}
670 675
671fn f() { 676fn f() {
672 let i = foo::Foo<|> { n: 5 }; 677 let i = foo::Foo$0 { n: 5 };
673} 678}
674"#, 679"#,
675 expect![[r#" 680 expect![[r#"
@@ -689,7 +694,7 @@ fn f() {
689 check( 694 check(
690 r#" 695 r#"
691//- /lib.rs 696//- /lib.rs
692mod foo<|>; 697mod foo$0;
693 698
694use foo::Foo; 699use foo::Foo;
695 700
@@ -726,7 +731,7 @@ fn f() {
726} 731}
727 732
728//- /foo/some.rs 733//- /foo/some.rs
729pub(super) struct Foo<|> { 734pub(super) struct Foo$0 {
730 pub n: u32, 735 pub n: u32,
731} 736}
732"#, 737"#,
@@ -746,7 +751,7 @@ pub(super) struct Foo<|> {
746 mod foo; 751 mod foo;
747 mod bar; 752 mod bar;
748 753
749 pub fn quux<|>() {} 754 pub fn quux$0() {}
750 755
751 //- /foo.rs 756 //- /foo.rs
752 fn f() { super::quux(); } 757 fn f() { super::quux(); }
@@ -782,7 +787,7 @@ pub(super) struct Foo<|> {
782 check( 787 check(
783 r#" 788 r#"
784#[macro_export] 789#[macro_export]
785macro_rules! m1<|> { () => (()) } 790macro_rules! m1$0 { () => (()) }
786 791
787fn foo() { 792fn foo() {
788 m1(); 793 m1();
@@ -803,7 +808,7 @@ fn foo() {
803 check( 808 check(
804 r#" 809 r#"
805fn foo() { 810fn foo() {
806 let mut i<|> = 0; 811 let mut i$0 = 0;
807 i = i + 1; 812 i = i + 1;
808} 813}
809"#, 814"#,
@@ -826,7 +831,7 @@ struct S {
826 831
827fn foo() { 832fn foo() {
828 let mut s = S{f: 0}; 833 let mut s = S{f: 0};
829 s.f<|> = 0; 834 s.f$0 = 0;
830} 835}
831"#, 836"#,
832 expect![[r#" 837 expect![[r#"
@@ -843,7 +848,7 @@ fn foo() {
843 check( 848 check(
844 r#" 849 r#"
845fn foo() { 850fn foo() {
846 let i<|>; 851 let i$0;
847 i = 1; 852 i = 1;
848} 853}
849"#, 854"#,
@@ -863,7 +868,7 @@ mod foo {
863 pub struct Foo; 868 pub struct Foo;
864 869
865 impl Foo { 870 impl Foo {
866 pub fn new<|>() -> Foo { Foo } 871 pub fn new$0() -> Foo { Foo }
867 } 872 }
868} 873}
869 874
@@ -886,7 +891,7 @@ fn main() {
886//- /lib.rs 891//- /lib.rs
887mod foo { mod bar; } 892mod foo { mod bar; }
888 893
889fn f<|>() {} 894fn f$0() {}
890 895
891//- /foo/bar.rs 896//- /foo/bar.rs
892use crate::f; 897use crate::f;
@@ -907,7 +912,7 @@ fn g() { f(); }
907 check( 912 check(
908 r#" 913 r#"
909struct S { 914struct S {
910 field<|>: u8, 915 field$0: u8,
911} 916}
912 917
913fn f(s: S) { 918fn f(s: S) {
@@ -930,7 +935,7 @@ fn f(s: S) {
930 r#" 935 r#"
931enum En { 936enum En {
932 Variant { 937 Variant {
933 field<|>: u8, 938 field$0: u8,
934 } 939 }
935} 940}
936 941
@@ -955,7 +960,7 @@ fn f(e: En) {
955mod m { 960mod m {
956 pub enum En { 961 pub enum En {
957 Variant { 962 Variant {
958 field<|>: u8, 963 field$0: u8,
959 } 964 }
960 } 965 }
961} 966}
@@ -980,7 +985,7 @@ struct Foo { bar: i32 }
980 985
981impl Foo { 986impl Foo {
982 fn foo(self) { 987 fn foo(self) {
983 let x = self<|>.bar; 988 let x = self$0.bar;
984 if true { 989 if true {
985 let _ = match () { 990 let _ = match () {
986 () => self, 991 () => self,
@@ -1016,12 +1021,14 @@ impl Foo {
1016 actual += "\n\n"; 1021 actual += "\n\n";
1017 } 1022 }
1018 1023
1019 for r in &refs.references { 1024 for (file_id, references) in refs.references {
1020 format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); 1025 for r in references {
1021 if let Some(access) = r.access { 1026 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind);
1022 format_to!(actual, " {:?}", access); 1027 if let Some(access) = r.access {
1028 format_to!(actual, " {:?}", access);
1029 }
1030 actual += "\n";
1023 } 1031 }
1024 actual += "\n";
1025 } 1032 }
1026 expect.assert_eq(&actual) 1033 expect.assert_eq(&actual)
1027 } 1034 }
@@ -1032,7 +1039,7 @@ impl Foo {
1032 r#" 1039 r#"
1033trait Foo<'a> {} 1040trait Foo<'a> {}
1034impl<'a> Foo<'a> for &'a () {} 1041impl<'a> Foo<'a> for &'a () {}
1035fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> { 1042fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> {
1036 fn bar<'a>(_: &'a ()) {} 1043 fn bar<'a>(_: &'a ()) {}
1037 x 1044 x
1038} 1045}
@@ -1053,7 +1060,7 @@ fn foo<'a, 'b: 'a>(x: &'a<|> ()) -> &'a () where &'a (): Foo<'a> {
1053 fn test_find_lifetimes_type_alias() { 1060 fn test_find_lifetimes_type_alias() {
1054 check( 1061 check(
1055 r#" 1062 r#"
1056type Foo<'a, T> where T: 'a<|> = &'a T; 1063type Foo<'a, T> where T: 'a$0 = &'a T;
1057"#, 1064"#,
1058 expect![[r#" 1065 expect![[r#"
1059 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime 1066 'a LifetimeParam FileId(0) 9..11 9..11 Lifetime
@@ -1072,7 +1079,7 @@ trait Foo<'a> {
1072 fn foo() -> &'a (); 1079 fn foo() -> &'a ();
1073} 1080}
1074impl<'a> Foo<'a> for &'a () { 1081impl<'a> Foo<'a> for &'a () {
1075 fn foo() -> &'a<|> () { 1082 fn foo() -> &'a$0 () {
1076 unimplemented!() 1083 unimplemented!()
1077 } 1084 }
1078} 1085}
@@ -1093,7 +1100,7 @@ impl<'a> Foo<'a> for &'a () {
1093 r#" 1100 r#"
1094macro_rules! foo {($i:ident) => {$i} } 1101macro_rules! foo {($i:ident) => {$i} }
1095fn main() { 1102fn main() {
1096 let a<|> = "test"; 1103 let a$0 = "test";
1097 foo!(a); 1104 foo!(a);
1098} 1105}
1099"#, 1106"#,
@@ -1112,7 +1119,7 @@ fn main() {
1112macro_rules! foo {($i:ident) => {$i} } 1119macro_rules! foo {($i:ident) => {$i} }
1113fn main() { 1120fn main() {
1114 let a = "test"; 1121 let a = "test";
1115 foo!(a<|>); 1122 foo!(a$0);
1116} 1123}
1117"#, 1124"#,
1118 expect![[r#" 1125 expect![[r#"
@@ -1130,7 +1137,7 @@ fn main() {
1130fn foo<'a>() -> &'a () { 1137fn foo<'a>() -> &'a () {
1131 'a: loop { 1138 'a: loop {
1132 'b: loop { 1139 'b: loop {
1133 continue 'a<|>; 1140 continue 'a$0;
1134 } 1141 }
1135 break 'a; 1142 break 'a;
1136 } 1143 }
@@ -1149,7 +1156,7 @@ fn foo<'a>() -> &'a () {
1149 fn test_find_const_param() { 1156 fn test_find_const_param() {
1150 check( 1157 check(
1151 r#" 1158 r#"
1152fn foo<const FOO<|>: usize>() -> usize { 1159fn foo<const FOO$0: usize>() -> usize {
1153 FOO 1160 FOO
1154} 1161}
1155"#, 1162"#,
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 854bf194e..c3ae568c2 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,29 +1,30 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use std::{ 2use std::{
3 convert::TryInto, 3 convert::TryInto,
4 error::Error,
5 fmt::{self, Display}, 4 fmt::{self, Display},
6}; 5};
7 6
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 7use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt};
10use ide_db::{ 8use ide_db::{
9 base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt},
11 defs::{Definition, NameClass, NameRefClass}, 10 defs::{Definition, NameClass, NameRefClass},
11 search::FileReference,
12 RootDatabase, 12 RootDatabase,
13}; 13};
14use syntax::{ 14use syntax::{
15 algo::find_node_at_offset, 15 algo::find_node_at_offset,
16 ast::{self, NameOwner}, 16 ast::{self, NameOwner},
17 lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, 17 lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, T,
18}; 18};
19use test_utils::mark; 19use test_utils::mark;
20use text_edit::TextEdit; 20use text_edit::TextEdit;
21 21
22use crate::{ 22use crate::{
23 references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, 23 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange,
24 SourceChange, SourceFileEdit, TextRange, TextSize, 24 SourceFileEdit, TextRange, TextSize,
25}; 25};
26 26
27type RenameResult<T> = Result<T, RenameError>;
27#[derive(Debug)] 28#[derive(Debug)]
28pub struct RenameError(pub(crate) String); 29pub struct RenameError(pub(crate) String);
29 30
@@ -33,26 +34,30 @@ impl fmt::Display for RenameError {
33 } 34 }
34} 35}
35 36
36impl Error for RenameError {} 37macro_rules! format_err {
38 ($fmt:expr) => {RenameError(format!($fmt))};
39 ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))}
40}
41
42macro_rules! bail {
43 ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))}
44}
37 45
38pub(crate) fn prepare_rename( 46pub(crate) fn prepare_rename(
39 db: &RootDatabase, 47 db: &RootDatabase,
40 position: FilePosition, 48 position: FilePosition,
41) -> Result<RangeInfo<()>, RenameError> { 49) -> RenameResult<RangeInfo<()>> {
42 let sema = Semantics::new(db); 50 let sema = Semantics::new(db);
43 let source_file = sema.parse(position.file_id); 51 let source_file = sema.parse(position.file_id);
44 let syntax = source_file.syntax(); 52 let syntax = source_file.syntax();
45 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 53 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
46 rename_mod(&sema, position, module, "dummy") 54 rename_mod(&sema, position, module, "dummy")
47 } else if let Some(self_token) = 55 } else if let Some(self_token) =
48 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) 56 syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])
49 { 57 {
50 rename_self_to_param(&sema, position, self_token, "dummy") 58 rename_self_to_param(&sema, position, self_token, "dummy")
51 } else { 59 } else {
52 let range = match find_all_refs(&sema, position, None) { 60 let RangeInfo { range, .. } = find_all_refs(&sema, position)?;
53 Some(RangeInfo { range, .. }) => range,
54 None => return Err(RenameError("No references found at position".to_string())),
55 };
56 Ok(RangeInfo::new(range, SourceChange::from(vec![]))) 61 Ok(RangeInfo::new(range, SourceChange::from(vec![])))
57 } 62 }
58 .map(|info| RangeInfo::new(info.range, ())) 63 .map(|info| RangeInfo::new(info.range, ()))
@@ -62,7 +67,7 @@ pub(crate) fn rename(
62 db: &RootDatabase, 67 db: &RootDatabase,
63 position: FilePosition, 68 position: FilePosition,
64 new_name: &str, 69 new_name: &str,
65) -> Result<RangeInfo<SourceChange>, RenameError> { 70) -> RenameResult<RangeInfo<SourceChange>> {
66 let sema = Semantics::new(db); 71 let sema = Semantics::new(db);
67 rename_with_semantics(&sema, position, new_name) 72 rename_with_semantics(&sema, position, new_name)
68} 73}
@@ -71,42 +76,18 @@ pub(crate) fn rename_with_semantics(
71 sema: &Semantics<RootDatabase>, 76 sema: &Semantics<RootDatabase>,
72 position: FilePosition, 77 position: FilePosition,
73 new_name: &str, 78 new_name: &str,
74) -> Result<RangeInfo<SourceChange>, RenameError> { 79) -> RenameResult<RangeInfo<SourceChange>> {
75 let is_lifetime_name = match lex_single_syntax_kind(new_name) {
76 Some(res) => match res {
77 (SyntaxKind::IDENT, _) => false,
78 (SyntaxKind::UNDERSCORE, _) => false,
79 (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position),
80 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => true,
81 (SyntaxKind::LIFETIME_IDENT, _) => {
82 return Err(RenameError(format!(
83 "Invalid name `{0}`: Cannot rename lifetime to {0}",
84 new_name
85 )))
86 }
87 (_, Some(syntax_error)) => {
88 return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error)))
89 }
90 (_, None) => {
91 return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name)))
92 }
93 },
94 None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))),
95 };
96
97 let source_file = sema.parse(position.file_id); 80 let source_file = sema.parse(position.file_id);
98 let syntax = source_file.syntax(); 81 let syntax = source_file.syntax();
99 // this is here to prevent lifetime renames from happening on modules and self 82
100 if is_lifetime_name { 83 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
101 rename_reference(&sema, position, new_name, is_lifetime_name)
102 } else if let Some(module) = find_module_at_offset(&sema, position, syntax) {
103 rename_mod(&sema, position, module, new_name) 84 rename_mod(&sema, position, module, new_name)
104 } else if let Some(self_token) = 85 } else if let Some(self_token) =
105 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) 86 syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])
106 { 87 {
107 rename_self_to_param(&sema, position, self_token, new_name) 88 rename_self_to_param(&sema, position, self_token, new_name)
108 } else { 89 } else {
109 rename_reference(&sema, position, new_name, is_lifetime_name) 90 rename_reference(&sema, position, new_name)
110 } 91 }
111} 92}
112 93
@@ -127,6 +108,33 @@ pub(crate) fn will_rename_file(
127 Some(change) 108 Some(change)
128} 109}
129 110
111#[derive(Debug, PartialEq)]
112enum IdentifierKind {
113 Ident,
114 Lifetime,
115 ToSelf,
116 Underscore,
117}
118
119fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> {
120 match lex_single_syntax_kind(new_name) {
121 Some(res) => match res {
122 (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident),
123 (T![_], _) => Ok(IdentifierKind::Underscore),
124 (T![self], _) => Ok(IdentifierKind::ToSelf),
125 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
126 Ok(IdentifierKind::Lifetime)
127 }
128 (SyntaxKind::LIFETIME_IDENT, _) => {
129 bail!("Invalid name `{0}`: Cannot rename lifetime to {0}", new_name)
130 }
131 (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
132 (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
133 },
134 None => bail!("Invalid name `{}`: not an identifier", new_name),
135 }
136}
137
130fn find_module_at_offset( 138fn find_module_at_offset(
131 sema: &Semantics<RootDatabase>, 139 sema: &Semantics<RootDatabase>,
132 position: FilePosition, 140 position: FilePosition,
@@ -155,39 +163,54 @@ fn find_module_at_offset(
155 Some(module) 163 Some(module)
156} 164}
157 165
158fn source_edit_from_reference( 166fn find_all_refs(
167 sema: &Semantics<RootDatabase>,
168 position: FilePosition,
169) -> RenameResult<RangeInfo<ReferenceSearchResult>> {
170 crate::references::find_all_refs(sema, position, None)
171 .ok_or_else(|| format_err!("No references found at position"))
172}
173
174fn source_edit_from_references(
159 sema: &Semantics<RootDatabase>, 175 sema: &Semantics<RootDatabase>,
160 reference: Reference, 176 file_id: FileId,
177 references: &[FileReference],
161 new_name: &str, 178 new_name: &str,
162) -> SourceFileEdit { 179) -> SourceFileEdit {
163 let mut replacement_text = String::new(); 180 let mut edit = TextEdit::builder();
164 let range = match reference.kind { 181 for reference in references {
165 ReferenceKind::FieldShorthandForField => { 182 let mut replacement_text = String::new();
166 mark::hit!(test_rename_struct_field_for_shorthand); 183 let range = match reference.kind {
167 replacement_text.push_str(new_name); 184 ReferenceKind::FieldShorthandForField => {
168 replacement_text.push_str(": "); 185 mark::hit!(test_rename_struct_field_for_shorthand);
169 TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) 186 replacement_text.push_str(new_name);
170 } 187 replacement_text.push_str(": ");
171 ReferenceKind::FieldShorthandForLocal => { 188 TextRange::new(reference.range.start(), reference.range.start())
172 mark::hit!(test_rename_local_for_field_shorthand); 189 }
173 replacement_text.push_str(": "); 190 ReferenceKind::FieldShorthandForLocal => {
174 replacement_text.push_str(new_name); 191 mark::hit!(test_rename_local_for_field_shorthand);
175 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) 192 replacement_text.push_str(": ");
176 } 193 replacement_text.push_str(new_name);
177 ReferenceKind::RecordFieldExprOrPat => { 194 TextRange::new(reference.range.end(), reference.range.end())
178 mark::hit!(test_rename_field_expr_pat); 195 }
179 replacement_text.push_str(new_name); 196 ReferenceKind::RecordFieldExprOrPat => {
180 edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) 197 mark::hit!(test_rename_field_expr_pat);
181 } 198 replacement_text.push_str(new_name);
182 _ => { 199 edit_text_range_for_record_field_expr_or_pat(
183 replacement_text.push_str(new_name); 200 sema,
184 reference.file_range.range 201 FileRange { file_id, range: reference.range },
185 } 202 new_name,
186 }; 203 )
187 SourceFileEdit { 204 }
188 file_id: reference.file_range.file_id, 205 _ => {
189 edit: TextEdit::replace(range, replacement_text), 206 replacement_text.push_str(new_name);
207 reference.range
208 }
209 };
210 edit.replace(range, replacement_text);
190 } 211 }
212
213 SourceFileEdit { file_id, edit: edit.finish() }
191} 214}
192 215
193fn edit_text_range_for_record_field_expr_or_pat( 216fn edit_text_range_for_record_field_expr_or_pat(
@@ -223,7 +246,10 @@ fn rename_mod(
223 position: FilePosition, 246 position: FilePosition,
224 module: Module, 247 module: Module,
225 new_name: &str, 248 new_name: &str,
226) -> Result<RangeInfo<SourceChange>, RenameError> { 249) -> RenameResult<RangeInfo<SourceChange>> {
250 if IdentifierKind::Ident != check_identifier(new_name)? {
251 bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
252 }
227 let mut source_file_edits = Vec::new(); 253 let mut source_file_edits = Vec::new();
228 let mut file_system_edits = Vec::new(); 254 let mut file_system_edits = Vec::new();
229 255
@@ -254,12 +280,10 @@ fn rename_mod(
254 source_file_edits.push(edit); 280 source_file_edits.push(edit);
255 } 281 }
256 282
257 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) 283 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
258 .ok_or_else(|| RenameError("No references found at position".to_string()))?; 284 let ref_edits = refs.references().iter().map(|(&file_id, references)| {
259 let ref_edits = refs 285 source_edit_from_references(sema, file_id, references, new_name)
260 .references 286 });
261 .into_iter()
262 .map(|reference| source_edit_from_reference(sema, reference, new_name));
263 source_file_edits.extend(ref_edits); 287 source_file_edits.extend(ref_edits);
264 288
265 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 289 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
@@ -274,27 +298,26 @@ fn rename_to_self(
274 298
275 let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) 299 let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset)
276 .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) 300 .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast)))
277 .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; 301 .ok_or_else(|| format_err!("No surrounding method declaration found"))?;
278 let param_range = fn_ast 302 let param_range = fn_ast
279 .param_list() 303 .param_list()
280 .and_then(|p| p.params().next()) 304 .and_then(|p| p.params().next())
281 .ok_or_else(|| RenameError("Method has no parameters".to_string()))? 305 .ok_or_else(|| format_err!("Method has no parameters"))?
282 .syntax() 306 .syntax()
283 .text_range(); 307 .text_range();
284 if !param_range.contains(position.offset) { 308 if !param_range.contains(position.offset) {
285 return Err(RenameError("Only the first parameter can be self".to_string())); 309 bail!("Only the first parameter can be self");
286 } 310 }
287 311
288 let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) 312 let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset)
289 .and_then(|def| sema.to_def(&def)) 313 .and_then(|def| sema.to_def(&def))
290 .ok_or_else(|| RenameError("No impl block found for function".to_string()))?; 314 .ok_or_else(|| format_err!("No impl block found for function"))?;
291 if fn_def.self_param(sema.db).is_some() { 315 if fn_def.self_param(sema.db).is_some() {
292 return Err(RenameError("Method already has a self parameter".to_string())); 316 bail!("Method already has a self parameter");
293 } 317 }
294 318
295 let params = fn_def.assoc_fn_params(sema.db); 319 let params = fn_def.assoc_fn_params(sema.db);
296 let first_param = 320 let first_param = params.first().ok_or_else(|| format_err!("Method has no parameters"))?;
297 params.first().ok_or_else(|| RenameError("Method has no parameters".into()))?;
298 let first_param_ty = first_param.ty(); 321 let first_param_ty = first_param.ty();
299 let impl_ty = impl_block.target_ty(sema.db); 322 let impl_ty = impl_block.target_ty(sema.db);
300 let (ty, self_param) = if impl_ty.remove_ref().is_some() { 323 let (ty, self_param) = if impl_ty.remove_ref().is_some() {
@@ -307,23 +330,17 @@ fn rename_to_self(
307 }; 330 };
308 331
309 if ty != impl_ty { 332 if ty != impl_ty {
310 return Err(RenameError("Parameter type differs from impl block type".to_string())); 333 bail!("Parameter type differs from impl block type");
311 } 334 }
312 335
313 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) 336 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
314 .ok_or_else(|| RenameError("No reference found at position".to_string()))?;
315
316 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
317 .into_iter()
318 .partition(|reference| param_range.intersect(reference.file_range.range).is_some());
319
320 if param_ref.is_empty() {
321 return Err(RenameError("Parameter to rename not found".to_string()));
322 }
323 337
324 let mut edits = usages 338 let mut edits = refs
325 .into_iter() 339 .references()
326 .map(|reference| source_edit_from_reference(sema, reference, "self")) 340 .iter()
341 .map(|(&file_id, references)| {
342 source_edit_from_references(sema, file_id, references, "self")
343 })
327 .collect::<Vec<_>>(); 344 .collect::<Vec<_>>();
328 345
329 edits.push(SourceFileEdit { 346 edits.push(SourceFileEdit {
@@ -367,12 +384,22 @@ fn rename_self_to_param(
367 self_token: SyntaxToken, 384 self_token: SyntaxToken,
368 new_name: &str, 385 new_name: &str,
369) -> Result<RangeInfo<SourceChange>, RenameError> { 386) -> Result<RangeInfo<SourceChange>, RenameError> {
387 let ident_kind = check_identifier(new_name)?;
388 match ident_kind {
389 IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name),
390 IdentifierKind::ToSelf => {
391 // no-op
392 mark::hit!(rename_self_to_self);
393 return Ok(RangeInfo::new(self_token.text_range(), SourceChange::default()));
394 }
395 _ => (),
396 }
370 let source_file = sema.parse(position.file_id); 397 let source_file = sema.parse(position.file_id);
371 let syn = source_file.syntax(); 398 let syn = source_file.syntax();
372 399
373 let text = sema.db.file_text(position.file_id); 400 let text = sema.db.file_text(position.file_id);
374 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) 401 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
375 .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; 402 .ok_or_else(|| format_err!("No surrounding method declaration found"))?;
376 let search_range = fn_def.syntax().text_range(); 403 let search_range = fn_def.syntax().text_range();
377 404
378 let mut edits: Vec<SourceFileEdit> = vec![]; 405 let mut edits: Vec<SourceFileEdit> = vec![];
@@ -382,12 +409,10 @@ fn rename_self_to_param(
382 if !search_range.contains_inclusive(offset) { 409 if !search_range.contains_inclusive(offset) {
383 continue; 410 continue;
384 } 411 }
385 if let Some(ref usage) = 412 if let Some(ref usage) = syn.token_at_offset(offset).find(|t| t.kind() == T![self]) {
386 syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
387 {
388 let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { 413 let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) {
389 text_edit_from_self_param(syn, self_param, new_name) 414 text_edit_from_self_param(syn, self_param, new_name)
390 .ok_or_else(|| RenameError("No target type found".to_string()))? 415 .ok_or_else(|| format_err!("No target type found"))?
391 } else { 416 } else {
392 TextEdit::replace(usage.text_range(), String::from(new_name)) 417 TextEdit::replace(usage.text_range(), String::from(new_name))
393 }; 418 };
@@ -395,6 +420,10 @@ fn rename_self_to_param(
395 } 420 }
396 } 421 }
397 422
423 if edits.len() > 1 && ident_kind == IdentifierKind::Underscore {
424 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
425 }
426
398 let range = ast::SelfParam::cast(self_token.parent()) 427 let range = ast::SelfParam::cast(self_token.parent())
399 .map_or(self_token.text_range(), |p| p.syntax().text_range()); 428 .map_or(self_token.text_range(), |p| p.syntax().text_range());
400 429
@@ -405,35 +434,43 @@ fn rename_reference(
405 sema: &Semantics<RootDatabase>, 434 sema: &Semantics<RootDatabase>,
406 position: FilePosition, 435 position: FilePosition,
407 new_name: &str, 436 new_name: &str,
408 is_lifetime_name: bool,
409) -> Result<RangeInfo<SourceChange>, RenameError> { 437) -> Result<RangeInfo<SourceChange>, RenameError> {
410 let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) { 438 let ident_kind = check_identifier(new_name)?;
411 Some(range_info) => range_info, 439 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
412 None => return Err(RenameError("No references found at position".to_string())), 440
413 }; 441 match (ident_kind, &refs.declaration.kind) {
414 442 (IdentifierKind::ToSelf, ReferenceKind::Lifetime)
415 match (refs.declaration.kind == ReferenceKind::Lifetime, is_lifetime_name) { 443 | (IdentifierKind::Underscore, ReferenceKind::Lifetime)
416 (true, false) => { 444 | (IdentifierKind::Ident, ReferenceKind::Lifetime) => {
417 return Err(RenameError(format!( 445 mark::hit!(rename_not_a_lifetime_ident_ref);
418 "Invalid name `{}`: not a lifetime identifier", 446 bail!("Invalid name `{}`: not a lifetime identifier", new_name)
419 new_name
420 )))
421 } 447 }
422 (false, true) => { 448 (IdentifierKind::Lifetime, ReferenceKind::Lifetime) => mark::hit!(rename_lifetime),
423 return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) 449 (IdentifierKind::Lifetime, _) => {
450 mark::hit!(rename_not_an_ident_ref);
451 bail!("Invalid name `{}`: not an identifier", new_name)
424 } 452 }
425 _ => (), 453 (IdentifierKind::ToSelf, ReferenceKind::SelfKw) => {
454 unreachable!("rename_self_to_param should've been called instead")
455 }
456 (IdentifierKind::ToSelf, _) => {
457 mark::hit!(rename_to_self);
458 return rename_to_self(sema, position);
459 }
460 (IdentifierKind::Underscore, _) if !refs.references.is_empty() => {
461 mark::hit!(rename_underscore_multiple);
462 bail!("Cannot rename reference to `_` as it is being referenced multiple times")
463 }
464 (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident),
426 } 465 }
427 466
428 let edit = refs 467 let edit = refs
429 .into_iter() 468 .into_iter()
430 .map(|reference| source_edit_from_reference(sema, reference, new_name)) 469 .map(|(file_id, references)| {
470 source_edit_from_references(sema, file_id, &references, new_name)
471 })
431 .collect::<Vec<_>>(); 472 .collect::<Vec<_>>();
432 473
433 if edit.is_empty() {
434 return Err(RenameError("No references found at position".to_string()));
435 }
436
437 Ok(RangeInfo::new(range, SourceChange::from(edit))) 474 Ok(RangeInfo::new(range, SourceChange::from(edit)))
438} 475}
439 476
@@ -462,9 +499,11 @@ mod tests {
462 text_edit_builder.replace(indel.delete, indel.insert); 499 text_edit_builder.replace(indel.delete, indel.insert);
463 } 500 }
464 } 501 }
465 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string(); 502 if let Some(file_id) = file_id {
466 text_edit_builder.finish().apply(&mut result); 503 let mut result = analysis.file_text(file_id).unwrap().to_string();
467 assert_eq_text!(ra_fixture_after, &*result); 504 text_edit_builder.finish().apply(&mut result);
505 assert_eq_text!(ra_fixture_after, &*result);
506 }
468 } 507 }
469 Err(err) => { 508 Err(err) => {
470 if ra_fixture_after.starts_with("error:") { 509 if ra_fixture_after.starts_with("error:") {
@@ -493,19 +532,19 @@ mod tests {
493 532
494 #[test] 533 #[test]
495 fn test_rename_to_underscore() { 534 fn test_rename_to_underscore() {
496 check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#); 535 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
497 } 536 }
498 537
499 #[test] 538 #[test]
500 fn test_rename_to_raw_identifier() { 539 fn test_rename_to_raw_identifier() {
501 check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#); 540 check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
502 } 541 }
503 542
504 #[test] 543 #[test]
505 fn test_rename_to_invalid_identifier1() { 544 fn test_rename_to_invalid_identifier1() {
506 check( 545 check(
507 "invalid!", 546 "invalid!",
508 r#"fn main() { let i<|> = 1; }"#, 547 r#"fn main() { let i$0 = 1; }"#,
509 "error: Invalid name `invalid!`: not an identifier", 548 "error: Invalid name `invalid!`: not an identifier",
510 ); 549 );
511 } 550 }
@@ -514,7 +553,7 @@ mod tests {
514 fn test_rename_to_invalid_identifier2() { 553 fn test_rename_to_invalid_identifier2() {
515 check( 554 check(
516 "multiple tokens", 555 "multiple tokens",
517 r#"fn main() { let i<|> = 1; }"#, 556 r#"fn main() { let i$0 = 1; }"#,
518 "error: Invalid name `multiple tokens`: not an identifier", 557 "error: Invalid name `multiple tokens`: not an identifier",
519 ); 558 );
520 } 559 }
@@ -523,38 +562,60 @@ mod tests {
523 fn test_rename_to_invalid_identifier3() { 562 fn test_rename_to_invalid_identifier3() {
524 check( 563 check(
525 "let", 564 "let",
526 r#"fn main() { let i<|> = 1; }"#, 565 r#"fn main() { let i$0 = 1; }"#,
527 "error: Invalid name `let`: not an identifier", 566 "error: Invalid name `let`: not an identifier",
528 ); 567 );
529 } 568 }
530 569
531 #[test] 570 #[test]
532 fn test_rename_to_invalid_identifier_lifetime() { 571 fn test_rename_to_invalid_identifier_lifetime() {
572 mark::check!(rename_not_an_ident_ref);
533 check( 573 check(
534 "'foo", 574 "'foo",
535 r#"fn main() { let i<|> = 1; }"#, 575 r#"fn main() { let i$0 = 1; }"#,
536 "error: Invalid name `'foo`: not an identifier", 576 "error: Invalid name `'foo`: not an identifier",
537 ); 577 );
538 } 578 }
539 579
540 #[test] 580 #[test]
541 fn test_rename_to_invalid_identifier_lifetime2() { 581 fn test_rename_to_invalid_identifier_lifetime2() {
582 mark::check!(rename_not_a_lifetime_ident_ref);
542 check( 583 check(
543 "foo", 584 "foo",
544 r#"fn main<'a>(_: &'a<|> ()) {}"#, 585 r#"fn main<'a>(_: &'a$0 ()) {}"#,
545 "error: Invalid name `foo`: not a lifetime identifier", 586 "error: Invalid name `foo`: not a lifetime identifier",
546 ); 587 );
547 } 588 }
548 589
549 #[test] 590 #[test]
591 fn test_rename_to_underscore_invalid() {
592 mark::check!(rename_underscore_multiple);
593 check(
594 "_",
595 r#"fn main(foo$0: ()) {foo;}"#,
596 "error: Cannot rename reference to `_` as it is being referenced multiple times",
597 );
598 }
599
600 #[test]
601 fn test_rename_mod_invalid() {
602 check(
603 "'foo",
604 r#"mod foo$0 {}"#,
605 "error: Invalid name `'foo`: cannot rename module to 'foo",
606 );
607 }
608
609 #[test]
550 fn test_rename_for_local() { 610 fn test_rename_for_local() {
611 mark::check!(rename_ident);
551 check( 612 check(
552 "k", 613 "k",
553 r#" 614 r#"
554fn main() { 615fn main() {
555 let mut i = 1; 616 let mut i = 1;
556 let j = 1; 617 let j = 1;
557 i = i<|> + j; 618 i = i$0 + j;
558 619
559 { i = 0; } 620 { i = 0; }
560 621
@@ -579,7 +640,7 @@ fn main() {
579 fn test_rename_unresolved_reference() { 640 fn test_rename_unresolved_reference() {
580 check( 641 check(
581 "new_name", 642 "new_name",
582 r#"fn main() { let _ = unresolved_ref<|>; }"#, 643 r#"fn main() { let _ = unresolved_ref$0; }"#,
583 "error: No references found at position", 644 "error: No references found at position",
584 ); 645 );
585 } 646 }
@@ -591,7 +652,7 @@ fn main() {
591 r#" 652 r#"
592macro_rules! foo {($i:ident) => {$i} } 653macro_rules! foo {($i:ident) => {$i} }
593fn main() { 654fn main() {
594 let a<|> = "test"; 655 let a$0 = "test";
595 foo!(a); 656 foo!(a);
596} 657}
597"#, 658"#,
@@ -613,7 +674,7 @@ fn main() {
613macro_rules! foo {($i:ident) => {$i} } 674macro_rules! foo {($i:ident) => {$i} }
614fn main() { 675fn main() {
615 let a = "test"; 676 let a = "test";
616 foo!(a<|>); 677 foo!(a$0);
617} 678}
618"#, 679"#,
619 r#" 680 r#"
@@ -634,7 +695,7 @@ fn main() {
634macro_rules! define_fn {($id:ident) => { fn $id{} }} 695macro_rules! define_fn {($id:ident) => { fn $id{} }}
635define_fn!(foo); 696define_fn!(foo);
636fn main() { 697fn main() {
637 fo<|>o(); 698 fo$0o();
638} 699}
639"#, 700"#,
640 r#" 701 r#"
@@ -653,7 +714,7 @@ fn main() {
653 "bar", 714 "bar",
654 r#" 715 r#"
655macro_rules! define_fn {($id:ident) => { fn $id{} }} 716macro_rules! define_fn {($id:ident) => { fn $id{} }}
656define_fn!(fo<|>o); 717define_fn!(fo$0o);
657fn main() { 718fn main() {
658 foo(); 719 foo();
659} 720}
@@ -670,17 +731,17 @@ fn main() {
670 731
671 #[test] 732 #[test]
672 fn test_rename_for_param_inside() { 733 fn test_rename_for_param_inside() {
673 check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#); 734 check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#);
674 } 735 }
675 736
676 #[test] 737 #[test]
677 fn test_rename_refs_for_fn_param() { 738 fn test_rename_refs_for_fn_param() {
678 check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); 739 check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
679 } 740 }
680 741
681 #[test] 742 #[test]
682 fn test_rename_for_mut_param() { 743 fn test_rename_for_mut_param() {
683 check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); 744 check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
684 } 745 }
685 746
686 #[test] 747 #[test]
@@ -688,7 +749,7 @@ fn main() {
688 check( 749 check(
689 "j", 750 "j",
690 r#" 751 r#"
691struct Foo { i<|>: i32 } 752struct Foo { i$0: i32 }
692 753
693impl Foo { 754impl Foo {
694 fn new(i: i32) -> Self { 755 fn new(i: i32) -> Self {
@@ -714,7 +775,7 @@ impl Foo {
714 check( 775 check(
715 "j", 776 "j",
716 r#" 777 r#"
717struct Foo { i<|>: i32 } 778struct Foo { i$0: i32 }
718 779
719impl Foo { 780impl Foo {
720 fn new(i: i32) -> Self { 781 fn new(i: i32) -> Self {
@@ -743,7 +804,7 @@ impl Foo {
743struct Foo { i: i32 } 804struct Foo { i: i32 }
744 805
745impl Foo { 806impl Foo {
746 fn new(i<|>: i32) -> Self { 807 fn new(i$0: i32) -> Self {
747 Self { i } 808 Self { i }
748 } 809 }
749} 810}
@@ -765,7 +826,7 @@ impl Foo {
765 check( 826 check(
766 "j", 827 "j",
767 r#" 828 r#"
768struct Foo { i<|>: i32 } 829struct Foo { i$0: i32 }
769struct Bar { i: i32 } 830struct Bar { i: i32 }
770 831
771impl Bar { 832impl Bar {
@@ -794,7 +855,7 @@ impl Bar {
794 r#" 855 r#"
795struct Foo { i: i32 } 856struct Foo { i: i32 }
796 857
797fn baz(i<|>: i32) -> Self { 858fn baz(i$0: i32) -> Self {
798 let x = Foo { i }; 859 let x = Foo { i };
799 { 860 {
800 let i = 0; 861 let i = 0;
@@ -825,7 +886,7 @@ fn baz(j: i32) -> Self {
825mod bar; 886mod bar;
826 887
827//- /bar.rs 888//- /bar.rs
828mod foo<|>; 889mod foo$0;
829 890
830//- /bar/foo.rs 891//- /bar/foo.rs
831// empty 892// empty
@@ -883,7 +944,7 @@ fn main() {}
883pub struct FooContent; 944pub struct FooContent;
884 945
885//- /bar.rs 946//- /bar.rs
886use crate::foo<|>::FooContent; 947use crate::foo$0::FooContent;
887"#, 948"#,
888 expect![[r#" 949 expect![[r#"
889 RangeInfo { 950 RangeInfo {
@@ -943,9 +1004,9 @@ use crate::foo<|>::FooContent;
943 "foo2", 1004 "foo2",
944 r#" 1005 r#"
945//- /lib.rs 1006//- /lib.rs
946mod fo<|>o; 1007mod fo$0o;
947//- /foo/mod.rs 1008//- /foo/mod.rs
948// emtpy 1009// empty
949"#, 1010"#,
950 expect![[r#" 1011 expect![[r#"
951 RangeInfo { 1012 RangeInfo {
@@ -992,10 +1053,10 @@ mod fo<|>o;
992 "bar", 1053 "bar",
993 r#" 1054 r#"
994//- /lib.rs 1055//- /lib.rs
995mod outer { mod fo<|>o; } 1056mod outer { mod fo$0o; }
996 1057
997//- /outer/foo.rs 1058//- /outer/foo.rs
998// emtpy 1059// empty
999"#, 1060"#,
1000 expect![[r#" 1061 expect![[r#"
1001 RangeInfo { 1062 RangeInfo {
@@ -1041,7 +1102,7 @@ mod outer { mod fo<|>o; }
1041 check( 1102 check(
1042 "baz", 1103 "baz",
1043 r#" 1104 r#"
1044mod <|>foo { pub fn bar() {} } 1105mod $0foo { pub fn bar() {} }
1045 1106
1046fn main() { foo::bar(); } 1107fn main() { foo::bar(); }
1047"#, 1108"#,
@@ -1065,7 +1126,7 @@ fn f() {
1065} 1126}
1066 1127
1067//- /bar.rs 1128//- /bar.rs
1068pub mod foo<|>; 1129pub mod foo$0;
1069 1130
1070//- /bar/foo.rs 1131//- /bar/foo.rs
1071// pub fn fun() {} 1132// pub fn fun() {}
@@ -1128,7 +1189,7 @@ pub mod foo<|>;
1128 "Baz", 1189 "Baz",
1129 r#" 1190 r#"
1130mod foo { 1191mod foo {
1131 pub enum Foo { Bar<|> } 1192 pub enum Foo { Bar$0 }
1132} 1193}
1133 1194
1134fn func(f: foo::Foo) { 1195fn func(f: foo::Foo) {
@@ -1157,7 +1218,7 @@ fn func(f: foo::Foo) {
1157 "baz", 1218 "baz",
1158 r#" 1219 r#"
1159mod foo { 1220mod foo {
1160 pub struct Foo { pub bar<|>: uint } 1221 pub struct Foo { pub bar$0: uint }
1161} 1222}
1162 1223
1163fn foo(f: foo::Foo) { 1224fn foo(f: foo::Foo) {
@@ -1178,13 +1239,14 @@ fn foo(f: foo::Foo) {
1178 1239
1179 #[test] 1240 #[test]
1180 fn test_parameter_to_self() { 1241 fn test_parameter_to_self() {
1242 mark::check!(rename_to_self);
1181 check( 1243 check(
1182 "self", 1244 "self",
1183 r#" 1245 r#"
1184struct Foo { i: i32 } 1246struct Foo { i: i32 }
1185 1247
1186impl Foo { 1248impl Foo {
1187 fn f(foo<|>: &mut Foo) -> i32 { 1249 fn f(foo$0: &mut Foo) -> i32 {
1188 foo.i 1250 foo.i
1189 } 1251 }
1190} 1252}
@@ -1205,7 +1267,7 @@ impl Foo {
1205struct Foo { i: i32 } 1267struct Foo { i: i32 }
1206 1268
1207impl Foo { 1269impl Foo {
1208 fn f(foo<|>: Foo) -> i32 { 1270 fn f(foo$0: Foo) -> i32 {
1209 foo.i 1271 foo.i
1210 } 1272 }
1211} 1273}
@@ -1229,7 +1291,7 @@ impl Foo {
1229 r#" 1291 r#"
1230struct Foo { i: i32 } 1292struct Foo { i: i32 }
1231 1293
1232fn f(foo<|>: &mut Foo) -> i32 { 1294fn f(foo$0: &mut Foo) -> i32 {
1233 foo.i 1295 foo.i
1234} 1296}
1235"#, 1297"#,
@@ -1242,7 +1304,7 @@ struct Foo { i: i32 }
1242struct Bar; 1304struct Bar;
1243 1305
1244impl Bar { 1306impl Bar {
1245 fn f(foo<|>: &mut Foo) -> i32 { 1307 fn f(foo$0: &mut Foo) -> i32 {
1246 foo.i 1308 foo.i
1247 } 1309 }
1248} 1310}
@@ -1258,7 +1320,7 @@ impl Bar {
1258 r#" 1320 r#"
1259struct Foo { i: i32 } 1321struct Foo { i: i32 }
1260impl Foo { 1322impl Foo {
1261 fn f(x: (), foo<|>: &mut Foo) -> i32 { 1323 fn f(x: (), foo$0: &mut Foo) -> i32 {
1262 foo.i 1324 foo.i
1263 } 1325 }
1264} 1326}
@@ -1274,7 +1336,7 @@ impl Foo {
1274 r#" 1336 r#"
1275struct Foo { i: i32 } 1337struct Foo { i: i32 }
1276impl &Foo { 1338impl &Foo {
1277 fn f(foo<|>: &Foo) -> i32 { 1339 fn f(foo$0: &Foo) -> i32 {
1278 foo.i 1340 foo.i
1279 } 1341 }
1280} 1342}
@@ -1298,7 +1360,7 @@ impl &Foo {
1298struct Foo { i: i32 } 1360struct Foo { i: i32 }
1299 1361
1300impl Foo { 1362impl Foo {
1301 fn f(&mut <|>self) -> i32 { 1363 fn f(&mut $0self) -> i32 {
1302 self.i 1364 self.i
1303 } 1365 }
1304} 1366}
@@ -1323,7 +1385,7 @@ impl Foo {
1323struct Foo { i: i32 } 1385struct Foo { i: i32 }
1324 1386
1325impl Foo { 1387impl Foo {
1326 fn f(<|>self) -> i32 { 1388 fn f($0self) -> i32 {
1327 self.i 1389 self.i
1328 } 1390 }
1329} 1391}
@@ -1350,7 +1412,7 @@ struct Foo { i: i32 }
1350impl Foo { 1412impl Foo {
1351 fn f(&self) -> i32 { 1413 fn f(&self) -> i32 {
1352 let self_var = 1; 1414 let self_var = 1;
1353 self<|>.i 1415 self$0.i
1354 } 1416 }
1355} 1417}
1356"#, 1418"#,
@@ -1373,7 +1435,7 @@ impl Foo {
1373 check( 1435 check(
1374 "bar", 1436 "bar",
1375 r#" 1437 r#"
1376struct Foo { i<|>: i32 } 1438struct Foo { i$0: i32 }
1377 1439
1378fn foo(bar: i32) -> Foo { 1440fn foo(bar: i32) -> Foo {
1379 Foo { i: bar } 1441 Foo { i: bar }
@@ -1394,7 +1456,7 @@ fn foo(bar: i32) -> Foo {
1394 check( 1456 check(
1395 "baz", 1457 "baz",
1396 r#" 1458 r#"
1397struct Foo { i<|>: i32 } 1459struct Foo { i$0: i32 }
1398 1460
1399fn foo(foo: Foo) { 1461fn foo(foo: Foo) {
1400 let Foo { i: baz } = foo; 1462 let Foo { i: baz } = foo;
@@ -1433,7 +1495,7 @@ struct Foo {
1433 1495
1434fn foo(foo: Foo) { 1496fn foo(foo: Foo) {
1435 let Foo { i: b } = foo; 1497 let Foo { i: b } = foo;
1436 let _ = b<|>; 1498 let _ = b$0;
1437} 1499}
1438"#, 1500"#,
1439 expected_fixture, 1501 expected_fixture,
@@ -1447,7 +1509,7 @@ struct Foo {
1447 1509
1448fn foo(foo: Foo) { 1510fn foo(foo: Foo) {
1449 let Foo { i } = foo; 1511 let Foo { i } = foo;
1450 let _ = i<|>; 1512 let _ = i$0;
1451} 1513}
1452"#, 1514"#,
1453 expected_fixture, 1515 expected_fixture,
@@ -1464,7 +1526,7 @@ struct Foo {
1464} 1526}
1465 1527
1466fn foo(Foo { i }: foo) -> i32 { 1528fn foo(Foo { i }: foo) -> i32 {
1467 i<|> 1529 i$0
1468} 1530}
1469"#, 1531"#,
1470 r#" 1532 r#"
@@ -1481,6 +1543,7 @@ fn foo(Foo { i: bar }: foo) -> i32 {
1481 1543
1482 #[test] 1544 #[test]
1483 fn test_rename_lifetimes() { 1545 fn test_rename_lifetimes() {
1546 mark::check!(rename_lifetime);
1484 check( 1547 check(
1485 "'yeeee", 1548 "'yeeee",
1486 r#" 1549 r#"
@@ -1488,7 +1551,7 @@ trait Foo<'a> {
1488 fn foo() -> &'a (); 1551 fn foo() -> &'a ();
1489} 1552}
1490impl<'a> Foo<'a> for &'a () { 1553impl<'a> Foo<'a> for &'a () {
1491 fn foo() -> &'a<|> () { 1554 fn foo() -> &'a$0 () {
1492 unimplemented!() 1555 unimplemented!()
1493 } 1556 }
1494} 1557}
@@ -1520,7 +1583,7 @@ fn main() {
1520 let test_variable = CustomOption::Some(22); 1583 let test_variable = CustomOption::Some(22);
1521 1584
1522 match test_variable { 1585 match test_variable {
1523 CustomOption::Some(foo<|>) if foo == 11 => {} 1586 CustomOption::Some(foo$0) if foo == 11 => {}
1524 _ => (), 1587 _ => (),
1525 } 1588 }
1526}"#, 1589}"#,
@@ -1549,7 +1612,7 @@ fn main() {
1549fn foo<'a>() -> &'a () { 1612fn foo<'a>() -> &'a () {
1550 'a: { 1613 'a: {
1551 'b: loop { 1614 'b: loop {
1552 break 'a<|>; 1615 break 'a$0;
1553 } 1616 }
1554 } 1617 }
1555} 1618}
@@ -1565,4 +1628,24 @@ fn foo<'a>() -> &'a () {
1565"#, 1628"#,
1566 ) 1629 )
1567 } 1630 }
1631
1632 #[test]
1633 fn test_self_to_self() {
1634 mark::check!(rename_self_to_self);
1635 check(
1636 "self",
1637 r#"
1638struct Foo;
1639impl Foo {
1640 fn foo(self$0) {}
1641}
1642"#,
1643 r#"
1644struct Foo;
1645impl Foo {
1646 fn foo(self) {}
1647}
1648"#,
1649 )
1650 }
1568} 1651}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index c893afc7c..f5ee7de86 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -2,11 +2,11 @@ use std::fmt;
2 2
3use assists::utils::test_related_attribute; 3use assists::utils::test_related_attribute;
4use cfg::CfgExpr; 4use cfg::CfgExpr;
5use hir::{AsAssocItem, HasAttrs, InFile, 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, NameOwner}, 9 ast::{self, AstNode, AttrsOwner, ModuleItemOwner},
10 match_ast, SyntaxNode, 10 match_ast, SyntaxNode,
11}; 11};
12 12
@@ -96,41 +96,45 @@ impl Runnable {
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, file_id)).collect() 99 source_file
100} 100 .syntax()
101 101 .descendants()
102pub(crate) fn runnable( 102 .filter_map(|item| {
103 sema: &Semantics<RootDatabase>, 103 let runnable = match_ast! {
104 item: SyntaxNode, 104 match item {
105 file_id: FileId, 105 ast::Fn(func) => {
106) -> Option<Runnable> { 106 let def = sema.to_def(&func)?;
107 let runnable_item = match_ast! { 107 runnable_fn(&sema, def)
108 match (item.clone()) { 108 },
109 ast::Fn(it) => runnable_fn(sema, it, file_id), 109 ast::Module(it) => runnable_mod(&sema, it),
110 ast::Module(it) => runnable_mod(sema, it), 110 _ => None,
111 _ => None, 111 }
112 } 112 };
113 }; 113 runnable.or_else(|| match doc_owner_to_def(&sema, item)? {
114 runnable_item.or_else(|| runnable_doctest(sema, item)) 114 Definition::ModuleDef(def) => module_def_doctest(&sema, def),
115 _ => None,
116 })
117 })
118 .collect()
115} 119}
116 120
117fn runnable_fn(sema: &Semantics<RootDatabase>, func: ast::Fn, file_id: FileId) -> Option<Runnable> { 121pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
118 let def = sema.to_def(&func)?; 122 let func = def.source(sema.db)?;
119 let name_string = func.name()?.text().to_string(); 123 let name_string = def.name(sema.db).to_string();
120 124
121 let kind = if name_string == "main" { 125 let kind = if name_string == "main" {
122 RunnableKind::Bin 126 RunnableKind::Bin
123 } else { 127 } else {
124 let canonical_path = sema.to_def(&func).and_then(|def| { 128 let canonical_path = {
125 let def: hir::ModuleDef = def.into(); 129 let def: hir::ModuleDef = def.into();
126 def.canonical_path(sema.db) 130 def.canonical_path(sema.db)
127 }); 131 };
128 let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string)); 132 let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string));
129 133
130 if test_related_attribute(&func).is_some() { 134 if test_related_attribute(&func.value).is_some() {
131 let attr = TestAttr::from_fn(&func); 135 let attr = TestAttr::from_fn(&func.value);
132 RunnableKind::Test { test_id, attr } 136 RunnableKind::Test { test_id, attr }
133 } else if func.has_atom_attr("bench") { 137 } else if func.value.has_atom_attr("bench") {
134 RunnableKind::Bench { test_id } 138 RunnableKind::Bench { test_id }
135 } else { 139 } else {
136 return None; 140 return None;
@@ -139,27 +143,56 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, func: ast::Fn, file_id: FileId) -
139 143
140 let nav = NavigationTarget::from_named( 144 let nav = NavigationTarget::from_named(
141 sema.db, 145 sema.db,
142 InFile::new(file_id.into(), &func), 146 func.as_ref().map(|it| it as &dyn ast::NameOwner),
143 SymbolKind::Function, 147 SymbolKind::Function,
144 ); 148 );
145 let cfg = def.attrs(sema.db).cfg(); 149 let cfg = def.attrs(sema.db).cfg();
146 Some(Runnable { nav, kind, cfg }) 150 Some(Runnable { nav, kind, cfg })
147} 151}
148 152
149fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { 153pub(crate) fn runnable_mod(
150 match_ast! { 154 sema: &Semantics<RootDatabase>,
155 module: ast::Module,
156) -> Option<Runnable> {
157 if !has_test_function_or_multiple_test_submodules(&module) {
158 return None;
159 }
160 let module_def = sema.to_def(&module)?;
161
162 let path = module_def
163 .path_to_root(sema.db)
164 .into_iter()
165 .rev()
166 .filter_map(|it| it.name(sema.db))
167 .join("::");
168
169 let def = sema.to_def(&module)?;
170 let attrs = def.attrs(sema.db);
171 let cfg = attrs.cfg();
172 let nav = module_def.to_nav(sema.db);
173 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
174}
175
176// FIXME: figure out a proper API here.
177pub(crate) fn doc_owner_to_def(
178 sema: &Semantics<RootDatabase>,
179 item: SyntaxNode,
180) -> Option<Definition> {
181 let res: hir::ModuleDef = match_ast! {
151 match item { 182 match item {
152 ast::Fn(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 183 ast::SourceFile(it) => sema.scope(&item).module()?.into(),
153 ast::Struct(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 184 ast::Fn(it) => sema.to_def(&it)?.into(),
154 ast::Enum(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 185 ast::Struct(it) => sema.to_def(&it)?.into(),
155 ast::Union(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 186 ast::Enum(it) => sema.to_def(&it)?.into(),
156 ast::Trait(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 187 ast::Union(it) => sema.to_def(&it)?.into(),
157 ast::Const(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 188 ast::Trait(it) => sema.to_def(&it)?.into(),
158 ast::Static(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 189 ast::Const(it) => sema.to_def(&it)?.into(),
159 ast::TypeAlias(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), 190 ast::Static(it) => sema.to_def(&it)?.into(),
160 _ => None, 191 ast::TypeAlias(it) => sema.to_def(&it)?.into(),
192 _ => return None,
161 } 193 }
162 } 194 };
195 Some(Definition::ModuleDef(res))
163} 196}
164 197
165fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> { 198fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> {
@@ -254,26 +287,6 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
254 }) 287 })
255} 288}
256 289
257fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
258 if !has_test_function_or_multiple_test_submodules(&module) {
259 return None;
260 }
261 let module_def = sema.to_def(&module)?;
262
263 let path = module_def
264 .path_to_root(sema.db)
265 .into_iter()
266 .rev()
267 .filter_map(|it| it.name(sema.db))
268 .join("::");
269
270 let def = sema.to_def(&module)?;
271 let attrs = def.attrs(sema.db);
272 let cfg = attrs.cfg();
273 let nav = module_def.to_nav(sema.db);
274 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
275}
276
277// We could create runnables for modules with number_of_test_submodules > 0, 290// We could create runnables for modules with number_of_test_submodules > 0,
278// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already 291// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already
279fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { 292fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
@@ -330,7 +343,7 @@ mod tests {
330 check( 343 check(
331 r#" 344 r#"
332//- /lib.rs 345//- /lib.rs
333<|> 346$0
334fn main() {} 347fn main() {}
335 348
336#[test] 349#[test]
@@ -426,7 +439,7 @@ fn bench() {}
426 check( 439 check(
427 r#" 440 r#"
428//- /lib.rs 441//- /lib.rs
429<|> 442$0
430fn main() {} 443fn main() {}
431 444
432/// ``` 445/// ```
@@ -574,7 +587,7 @@ struct StructWithRunnable(String);
574 check( 587 check(
575 r#" 588 r#"
576//- /lib.rs 589//- /lib.rs
577<|> 590$0
578fn main() {} 591fn main() {}
579 592
580struct Data; 593struct Data;
@@ -626,7 +639,7 @@ impl Data {
626 check( 639 check(
627 r#" 640 r#"
628//- /lib.rs 641//- /lib.rs
629<|> 642$0
630mod test_mod { 643mod test_mod {
631 #[test] 644 #[test]
632 fn test_foo1() {} 645 fn test_foo1() {}
@@ -680,7 +693,7 @@ mod test_mod {
680 check( 693 check(
681 r#" 694 r#"
682//- /lib.rs 695//- /lib.rs
683<|> 696$0
684mod root_tests { 697mod root_tests {
685 mod nested_tests_0 { 698 mod nested_tests_0 {
686 mod nested_tests_1 { 699 mod nested_tests_1 {
@@ -820,7 +833,7 @@ mod root_tests {
820 check( 833 check(
821 r#" 834 r#"
822//- /lib.rs crate:foo cfg:feature=foo 835//- /lib.rs crate:foo cfg:feature=foo
823<|> 836$0
824#[test] 837#[test]
825#[cfg(feature = "foo")] 838#[cfg(feature = "foo")]
826fn test_foo1() {} 839fn test_foo1() {}
@@ -865,7 +878,7 @@ fn test_foo1() {}
865 check( 878 check(
866 r#" 879 r#"
867//- /lib.rs crate:foo cfg:feature=foo,feature=bar 880//- /lib.rs crate:foo cfg:feature=foo,feature=bar
868<|> 881$0
869#[test] 882#[test]
870#[cfg(all(feature = "foo", feature = "bar"))] 883#[cfg(all(feature = "foo", feature = "bar"))]
871fn test_foo1() {} 884fn test_foo1() {}
@@ -920,7 +933,7 @@ fn test_foo1() {}
920 check( 933 check(
921 r#" 934 r#"
922//- /lib.rs 935//- /lib.rs
923<|> 936$0
924mod test_mod { 937mod test_mod {
925 fn foo1() {} 938 fn foo1() {}
926} 939}
@@ -939,7 +952,7 @@ mod test_mod {
939//- /lib.rs 952//- /lib.rs
940mod foo; 953mod foo;
941//- /foo.rs 954//- /foo.rs
942struct Foo;<|> 955struct Foo;$0
943impl Foo { 956impl Foo {
944 /// ``` 957 /// ```
945 /// let x = 5; 958 /// let x = 5;
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 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.
420fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool {
421 while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) {
422 if parent.kind() != *kind {
423 return false;
424 }
425
426 // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value
427 // in the same pattern is unstable: rust-lang/rust#68354.
428 node = node.parent().unwrap().into();
429 kinds = rest;
430 }
431
432 // Only true if we matched all expected kinds
433 kinds.len() == 0
434}
435
436fn is_consumed_lvalue(
437 node: NodeOrToken<SyntaxNode, SyntaxToken>,
438 local: &Local,
439 db: &RootDatabase,
440) -> bool {
441 // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming.
442 parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db)
443}
444
445fn highlight_element(
446 sema: &Semantics<RootDatabase>,
447 bindings_shadow_count: &mut FxHashMap<Name, u32>,
448 syntactic_name_ref_highlighting: bool,
449 element: SyntaxElement,
450) -> Option<(Highlight, Option<u64>)> {
451 let db = sema.db;
452 let mut binding_hash = None;
453 let highlight: Highlight = match element.kind() {
454 FN => {
455 bindings_shadow_count.clear();
456 return None;
457 }
458
459 // Highlight definitions depending on the "type" of the definition.
460 NAME => {
461 let name = element.into_node().and_then(ast::Name::cast).unwrap();
462 let name_kind = NameClass::classify(sema, &name);
463
464 if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
465 if let Some(name) = local.name(db) {
466 let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
467 *shadow_count += 1;
468 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
469 }
470 };
471
472 match name_kind {
473 Some(NameClass::ExternCrate(_)) => HighlightTag::Symbol(SymbolKind::Module).into(),
474 Some(NameClass::Definition(def)) => {
475 highlight_def(db, def) | HighlightModifier::Definition
476 }
477 Some(NameClass::ConstReference(def)) => highlight_def(db, def),
478 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
479 let mut h = HighlightTag::Symbol(SymbolKind::Field).into();
480 if let Definition::Field(field) = field_ref {
481 if let VariantDef::Union(_) = field.parent_def(db) {
482 h |= HighlightModifier::Unsafe;
483 }
484 }
485
486 h
487 }
488 None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
489 }
490 }
491
492 // Highlight references like the definitions they resolve to
493 NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => {
494 // even though we track whether we are in an attribute or not we still need this special case
495 // as otherwise we would emit unresolved references for name refs inside attributes
496 Highlight::from(HighlightTag::Symbol(SymbolKind::Function))
497 }
498 NAME_REF => {
499 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
500 highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
501 match NameRefClass::classify(sema, &name_ref) {
502 Some(name_kind) => match name_kind {
503 NameRefClass::ExternCrate(_) => {
504 HighlightTag::Symbol(SymbolKind::Module).into()
505 }
506 NameRefClass::Definition(def) => {
507 if let Definition::Local(local) = &def {
508 if let Some(name) = local.name(db) {
509 let shadow_count =
510 bindings_shadow_count.entry(name.clone()).or_default();
511 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
512 }
513 };
514
515 let mut h = highlight_def(db, def);
516
517 if let Definition::Local(local) = &def {
518 if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) {
519 h |= HighlightModifier::Consuming;
520 }
521 }
522
523 if let Some(parent) = name_ref.syntax().parent() {
524 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
525 if let Definition::Field(field) = def {
526 if let VariantDef::Union(_) = field.parent_def(db) {
527 h |= HighlightModifier::Unsafe;
528 }
529 }
530 }
531 }
532
533 h
534 }
535 NameRefClass::FieldShorthand { .. } => {
536 HighlightTag::Symbol(SymbolKind::Field).into()
537 }
538 },
539 None if syntactic_name_ref_highlighting => {
540 highlight_name_ref_by_syntax(name_ref, sema)
541 }
542 None => HighlightTag::UnresolvedReference.into(),
543 }
544 })
545 }
546
547 // Simple token-based highlighting
548 COMMENT => {
549 let comment = element.into_token().and_then(ast::Comment::cast)?;
550 let h = HighlightTag::Comment;
551 match comment.kind().doc {
552 Some(_) => h | HighlightModifier::Documentation,
553 None => h.into(),
554 }
555 }
556 STRING | BYTE_STRING => HighlightTag::StringLiteral.into(),
557 ATTR => HighlightTag::Attribute.into(),
558 INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(),
559 BYTE => HighlightTag::ByteLiteral.into(),
560 CHAR => HighlightTag::CharLiteral.into(),
561 QUESTION => Highlight::new(HighlightTag::Operator) | HighlightModifier::ControlFlow,
562 LIFETIME => {
563 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
564
565 match NameClass::classify_lifetime(sema, &lifetime) {
566 Some(NameClass::Definition(def)) => {
567 highlight_def(db, def) | HighlightModifier::Definition
568 }
569 None => match NameRefClass::classify_lifetime(sema, &lifetime) {
570 Some(NameRefClass::Definition(def)) => highlight_def(db, def),
571 _ => Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)),
572 },
573 _ => {
574 Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam))
575 | HighlightModifier::Definition
576 }
577 }
578 }
579 p if p.is_punct() => match p {
580 T![&] => {
581 let h = HighlightTag::Operator.into();
582 let is_unsafe = element
583 .parent()
584 .and_then(ast::RefExpr::cast)
585 .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr))
586 .unwrap_or(false);
587 if is_unsafe {
588 h | HighlightModifier::Unsafe
589 } else {
590 h
591 }
592 }
593 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => {
594 HighlightTag::Operator.into()
595 }
596 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
597 HighlightTag::Symbol(SymbolKind::Macro).into()
598 }
599 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
600 HighlightTag::BuiltinType.into()
601 }
602 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
603 HighlightTag::Keyword.into()
604 }
605 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
606 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
607
608 let expr = prefix_expr.expr()?;
609 let ty = sema.type_of_expr(&expr)?;
610 if ty.is_raw_ptr() {
611 HighlightTag::Operator | HighlightModifier::Unsafe
612 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
613 HighlightTag::Operator.into()
614 } else {
615 HighlightTag::Punctuation.into()
616 }
617 }
618 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
619 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
620
621 let expr = prefix_expr.expr()?;
622 match expr {
623 ast::Expr::Literal(_) => HighlightTag::NumericLiteral,
624 _ => HighlightTag::Operator,
625 }
626 .into()
627 }
628 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
629 HighlightTag::Operator.into()
630 }
631 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => {
632 HighlightTag::Operator.into()
633 }
634 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
635 HighlightTag::Operator.into()
636 }
637 _ if element.parent().and_then(ast::RangePat::cast).is_some() => {
638 HighlightTag::Operator.into()
639 }
640 _ if element.parent().and_then(ast::RestPat::cast).is_some() => {
641 HighlightTag::Operator.into()
642 }
643 _ if element.parent().and_then(ast::Attr::cast).is_some() => {
644 HighlightTag::Attribute.into()
645 }
646 _ => HighlightTag::Punctuation.into(),
647 },
648
649 k if k.is_keyword() => {
650 let h = Highlight::new(HighlightTag::Keyword);
651 match k {
652 T![break]
653 | T![continue]
654 | T![else]
655 | T![if]
656 | T![loop]
657 | T![match]
658 | T![return]
659 | T![while]
660 | T![in] => h | HighlightModifier::ControlFlow,
661 T![for] if !is_child_of_impl(&element) => h | HighlightModifier::ControlFlow,
662 T![unsafe] => h | HighlightModifier::Unsafe,
663 T![true] | T![false] => HighlightTag::BoolLiteral.into(),
664 T![self] => {
665 let self_param_is_mut = element
666 .parent()
667 .and_then(ast::SelfParam::cast)
668 .and_then(|p| p.mut_token())
669 .is_some();
670 let self_path = &element
671 .parent()
672 .as_ref()
673 .and_then(SyntaxNode::parent)
674 .and_then(ast::Path::cast)
675 .and_then(|p| sema.resolve_path(&p));
676 let mut h = HighlightTag::Symbol(SymbolKind::SelfParam).into();
677 if self_param_is_mut
678 || matches!(self_path,
679 Some(hir::PathResolution::Local(local))
680 if local.is_self(db)
681 && (local.is_mut(db) || local.ty(db).is_mutable_reference())
682 )
683 {
684 h |= HighlightModifier::Mutable
685 }
686
687 if let Some(hir::PathResolution::Local(local)) = self_path {
688 if is_consumed_lvalue(element, &local, db) {
689 h |= HighlightModifier::Consuming;
690 }
691 }
692
693 h
694 }
695 T![ref] => element
696 .parent()
697 .and_then(ast::IdentPat::cast)
698 .and_then(|ident_pat| {
699 if sema.is_unsafe_ident_pat(&ident_pat) {
700 Some(HighlightModifier::Unsafe)
701 } else {
702 None
703 }
704 })
705 .map(|modifier| h | modifier)
706 .unwrap_or(h),
707 _ => h,
708 }
709 }
710
711 _ => return None,
712 };
713
714 return Some((highlight, binding_hash));
715
716 fn calc_binding_hash(name: &Name, shadow_count: u32) -> u64 {
717 fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
718 use std::{collections::hash_map::DefaultHasher, hash::Hasher};
719
720 let mut hasher = DefaultHasher::new();
721 x.hash(&mut hasher);
722 hasher.finish()
723 }
724
725 hash((name, shadow_count))
726 }
727}
728
729fn is_child_of_impl(element: &SyntaxElement) -> bool {
730 match element.parent() {
731 Some(e) => e.kind() == IMPL,
732 _ => false,
733 }
734}
735
736fn highlight_func_by_name_ref(
737 sema: &Semantics<RootDatabase>,
738 name_ref: &ast::NameRef,
739) -> Option<Highlight> {
740 let method_call = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
741 highlight_method_call(sema, &method_call)
742}
743
744fn highlight_method_call(
745 sema: &Semantics<RootDatabase>,
746 method_call: &ast::MethodCallExpr,
747) -> Option<Highlight> {
748 let func = sema.resolve_method_call(&method_call)?;
749 let mut h = HighlightTag::Symbol(SymbolKind::Function).into();
750 h |= HighlightModifier::Associated;
751 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
752 h |= HighlightModifier::Unsafe;
753 }
754 if let Some(self_param) = func.self_param(sema.db) {
755 match self_param.access(sema.db) {
756 hir::Access::Shared => (),
757 hir::Access::Exclusive => h |= HighlightModifier::Mutable,
758 hir::Access::Owned => {
759 if let Some(receiver_ty) =
760 method_call.receiver().and_then(|it| sema.type_of_expr(&it))
761 {
762 if !receiver_ty.is_copy(sema.db) {
763 h |= HighlightModifier::Consuming
764 }
765 }
766 }
767 }
768 }
769 Some(h)
770}
771
772fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
773 match def {
774 Definition::Macro(_) => HighlightTag::Symbol(SymbolKind::Macro),
775 Definition::Field(_) => HighlightTag::Symbol(SymbolKind::Field),
776 Definition::ModuleDef(def) => match def {
777 hir::ModuleDef::Module(_) => HighlightTag::Symbol(SymbolKind::Module),
778 hir::ModuleDef::Function(func) => {
779 let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Function));
780 if func.as_assoc_item(db).is_some() {
781 h |= HighlightModifier::Associated;
782 if func.self_param(db).is_none() {
783 h |= HighlightModifier::Static
784 }
785 }
786 if func.is_unsafe(db) {
787 h |= HighlightModifier::Unsafe;
788 }
789 return h;
790 }
791 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Symbol(SymbolKind::Struct),
792 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Symbol(SymbolKind::Enum),
793 hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Symbol(SymbolKind::Union),
794 hir::ModuleDef::Variant(_) => HighlightTag::Symbol(SymbolKind::Variant),
795 hir::ModuleDef::Const(konst) => {
796 let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Const));
797 if konst.as_assoc_item(db).is_some() {
798 h |= HighlightModifier::Associated
799 }
800 return h;
801 }
802 hir::ModuleDef::Trait(_) => HighlightTag::Symbol(SymbolKind::Trait),
803 hir::ModuleDef::TypeAlias(type_) => {
804 let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::TypeAlias));
805 if type_.as_assoc_item(db).is_some() {
806 h |= HighlightModifier::Associated
807 }
808 return h;
809 }
810 hir::ModuleDef::BuiltinType(_) => HighlightTag::BuiltinType,
811 hir::ModuleDef::Static(s) => {
812 let mut h = Highlight::new(HighlightTag::Symbol(SymbolKind::Static));
813 if s.is_mut(db) {
814 h |= HighlightModifier::Mutable;
815 h |= HighlightModifier::Unsafe;
816 }
817 return h;
818 }
819 },
820 Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl),
821 Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam),
822 Definition::ConstParam(_) => HighlightTag::Symbol(SymbolKind::ConstParam),
823 Definition::Local(local) => {
824 let tag = if local.is_param(db) {
825 HighlightTag::Symbol(SymbolKind::ValueParam)
826 } else {
827 HighlightTag::Symbol(SymbolKind::Local)
828 };
829 let mut h = Highlight::new(tag);
830 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
831 h |= HighlightModifier::Mutable;
832 }
833 if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) {
834 h |= HighlightModifier::Callable;
835 }
836 return h;
837 }
838 Definition::LifetimeParam(_) => HighlightTag::Symbol(SymbolKind::LifetimeParam),
839 Definition::Label(_) => HighlightTag::Symbol(SymbolKind::Label),
840 }
841 .into()
842}
843
844fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
845 let default = HighlightTag::UnresolvedReference;
846
847 let parent = match name.syntax().parent() {
848 Some(it) => it,
849 _ => return default.into(),
850 };
851
852 let tag = match parent.kind() {
853 STRUCT => HighlightTag::Symbol(SymbolKind::Struct),
854 ENUM => HighlightTag::Symbol(SymbolKind::Enum),
855 VARIANT => HighlightTag::Symbol(SymbolKind::Variant),
856 UNION => HighlightTag::Symbol(SymbolKind::Union),
857 TRAIT => HighlightTag::Symbol(SymbolKind::Trait),
858 TYPE_ALIAS => HighlightTag::Symbol(SymbolKind::TypeAlias),
859 TYPE_PARAM => HighlightTag::Symbol(SymbolKind::TypeParam),
860 RECORD_FIELD => HighlightTag::Symbol(SymbolKind::Field),
861 MODULE => HighlightTag::Symbol(SymbolKind::Module),
862 FN => HighlightTag::Symbol(SymbolKind::Function),
863 CONST => HighlightTag::Symbol(SymbolKind::Const),
864 STATIC => HighlightTag::Symbol(SymbolKind::Static),
865 IDENT_PAT => HighlightTag::Symbol(SymbolKind::Local),
866 _ => default,
867 };
868
869 tag.into()
870}
871
872fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
873 let default = HighlightTag::UnresolvedReference;
874
875 let parent = match name.syntax().parent() {
876 Some(it) => it,
877 _ => return default.into(),
878 };
879
880 match parent.kind() {
881 METHOD_CALL_EXPR => {
882 return ast::MethodCallExpr::cast(parent)
883 .and_then(|method_call| highlight_method_call(sema, &method_call))
884 .unwrap_or_else(|| HighlightTag::Symbol(SymbolKind::Function).into());
885 }
886 FIELD_EXPR => {
887 let h = HighlightTag::Symbol(SymbolKind::Field);
888 let is_union = ast::FieldExpr::cast(parent)
889 .and_then(|field_expr| {
890 let field = sema.resolve_field(&field_expr)?;
891 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
892 true
893 } else {
894 false
895 })
896 })
897 .unwrap_or(false);
898 if is_union {
899 h | HighlightModifier::Unsafe
900 } else {
901 h.into()
902 }
903 }
904 PATH_SEGMENT => {
905 let path = match parent.parent().and_then(ast::Path::cast) {
906 Some(it) => it,
907 _ => return default.into(),
908 };
909 let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) {
910 Some(it) => it,
911 _ => {
912 // within path, decide whether it is module or adt by checking for uppercase name
913 return if name.text().chars().next().unwrap_or_default().is_uppercase() {
914 HighlightTag::Symbol(SymbolKind::Struct)
915 } else {
916 HighlightTag::Symbol(SymbolKind::Module)
917 }
918 .into();
919 }
920 };
921 let parent = match expr.syntax().parent() {
922 Some(it) => it,
923 None => return default.into(),
924 };
925
926 match parent.kind() {
927 CALL_EXPR => HighlightTag::Symbol(SymbolKind::Function).into(),
928 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
929 HighlightTag::Symbol(SymbolKind::Struct)
930 } else {
931 HighlightTag::Symbol(SymbolKind::Const)
932 }
933 .into(),
934 }
935 }
936 _ => default.into(),
937 }
938}
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index 26416022b..a74ca844b 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -1,65 +1,51 @@
1//! Syntax highlighting for format macro strings. 1//! Syntax highlighting for format macro strings.
2use syntax::{ 2use syntax::{
3 ast::{self, FormatSpecifier, HasFormatSpecifier}, 3 ast::{self, FormatSpecifier, HasFormatSpecifier},
4 AstNode, AstToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, 4 AstNode, AstToken, TextRange,
5}; 5};
6 6
7use crate::{ 7use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag, SymbolKind};
8 syntax_highlighting::HighlightedRangeStack, HighlightTag, HighlightedRange, SymbolKind,
9};
10
11#[derive(Default)]
12pub(super) struct FormatStringHighlighter {
13 format_string: Option<SyntaxElement>,
14}
15 8
16impl FormatStringHighlighter { 9pub(super) fn highlight_format_string(
17 pub(super) fn check_for_format_string(&mut self, parent: &SyntaxNode) { 10 stack: &mut Highlights,
18 // Check if macro takes a format string and remember it for highlighting later. 11 string: &ast::String,
19 // The macros that accept a format string expand to a compiler builtin macros 12 range: TextRange,
20 // `format_args` and `format_args_nl`. 13) {
21 if let Some(name) = parent 14 if is_format_string(string).is_none() {
22 .parent() 15 return;
23 .and_then(ast::MacroCall::cast)
24 .and_then(|mc| mc.path())
25 .and_then(|p| p.segment())
26 .and_then(|s| s.name_ref())
27 {
28 match name.text().as_str() {
29 "format_args" | "format_args_nl" => {
30 self.format_string = parent
31 .children_with_tokens()
32 .filter(|t| t.kind() != SyntaxKind::WHITESPACE)
33 .nth(1)
34 .filter(|e| ast::String::can_cast(e.kind()))
35 }
36 _ => {}
37 }
38 }
39 } 16 }
40 pub(super) fn highlight_format_string( 17
41 &self, 18 string.lex_format_specifier(|piece_range, kind| {
42 range_stack: &mut HighlightedRangeStack, 19 if let Some(highlight) = highlight_format_specifier(kind) {
43 string: &impl HasFormatSpecifier, 20 stack.add(HlRange {
44 range: TextRange, 21 range: piece_range + range.start(),
45 ) { 22 highlight: highlight.into(),
46 if self.format_string.as_ref() == Some(&SyntaxElement::from(string.syntax().clone())) { 23 binding_hash: None,
47 range_stack.push();
48 string.lex_format_specifier(|piece_range, kind| {
49 if let Some(highlight) = highlight_format_specifier(kind) {
50 range_stack.add(HighlightedRange {
51 range: piece_range + range.start(),
52 highlight: highlight.into(),
53 binding_hash: None,
54 });
55 }
56 }); 24 });
57 range_stack.pop();
58 } 25 }
26 });
27}
28
29fn is_format_string(string: &ast::String) -> Option<()> {
30 let parent = string.syntax().parent();
31
32 let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?;
33 if !matches!(name.text().as_str(), "format_args" | "format_args_nl") {
34 return None;
35 }
36
37 let first_literal = parent
38 .children_with_tokens()
39 .filter_map(|it| it.as_token().cloned().and_then(ast::String::cast))
40 .next()?;
41 if &first_literal != string {
42 return None;
59 } 43 }
44
45 Some(())
60} 46}
61 47
62fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> { 48fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> {
63 Some(match kind { 49 Some(match kind {
64 FormatSpecifier::Open 50 FormatSpecifier::Open
65 | FormatSpecifier::Close 51 | FormatSpecifier::Close
@@ -71,8 +57,10 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> {
71 | FormatSpecifier::DollarSign 57 | FormatSpecifier::DollarSign
72 | FormatSpecifier::Dot 58 | FormatSpecifier::Dot
73 | FormatSpecifier::Asterisk 59 | FormatSpecifier::Asterisk
74 | FormatSpecifier::QuestionMark => HighlightTag::FormatSpecifier, 60 | FormatSpecifier::QuestionMark => HlTag::FormatSpecifier,
75 FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral, 61
76 FormatSpecifier::Identifier => HighlightTag::Symbol(SymbolKind::Local), 62 FormatSpecifier::Integer | FormatSpecifier::Zero => HlTag::NumericLiteral,
63
64 FormatSpecifier::Identifier => HlTag::Symbol(SymbolKind::Local),
77 }) 65 })
78} 66}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
new file mode 100644
index 000000000..34bae49a8
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -0,0 +1,530 @@
1//! Computes color for a single element.
2
3use hir::{AsAssocItem, Semantics, VariantDef};
4use ide_db::{
5 defs::{Definition, NameClass, NameRefClass},
6 RootDatabase,
7};
8use rustc_hash::FxHashMap;
9use syntax::{
10 ast, AstNode, AstToken, NodeOrToken, SyntaxElement,
11 SyntaxKind::{self, *},
12 SyntaxNode, SyntaxToken, T,
13};
14
15use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag, SymbolKind};
16
17pub(super) fn element(
18 sema: &Semantics<RootDatabase>,
19 bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
20 syntactic_name_ref_highlighting: bool,
21 element: SyntaxElement,
22) -> Option<(Highlight, Option<u64>)> {
23 let db = sema.db;
24 let mut binding_hash = None;
25 let highlight: Highlight = match element.kind() {
26 FN => {
27 bindings_shadow_count.clear();
28 return None;
29 }
30
31 // Highlight definitions depending on the "type" of the definition.
32 NAME => {
33 let name = element.into_node().and_then(ast::Name::cast).unwrap();
34 let name_kind = NameClass::classify(sema, &name);
35
36 if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
37 if let Some(name) = local.name(db) {
38 let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
39 *shadow_count += 1;
40 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
41 }
42 };
43
44 match name_kind {
45 Some(NameClass::ExternCrate(_)) => HlTag::Symbol(SymbolKind::Module).into(),
46 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
47 Some(NameClass::ConstReference(def)) => highlight_def(db, def),
48 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
49 let mut h = HlTag::Symbol(SymbolKind::Field).into();
50 if let Definition::Field(field) = field_ref {
51 if let VariantDef::Union(_) = field.parent_def(db) {
52 h |= HlMod::Unsafe;
53 }
54 }
55
56 h
57 }
58 None => highlight_name_by_syntax(name) | HlMod::Definition,
59 }
60 }
61
62 // Highlight references like the definitions they resolve to
63 NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => {
64 // even though we track whether we are in an attribute or not we still need this special case
65 // as otherwise we would emit unresolved references for name refs inside attributes
66 Highlight::from(HlTag::Symbol(SymbolKind::Function))
67 }
68 NAME_REF => {
69 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
70 highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
71 match NameRefClass::classify(sema, &name_ref) {
72 Some(name_kind) => match name_kind {
73 NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(),
74 NameRefClass::Definition(def) => {
75 if let Definition::Local(local) = &def {
76 if let Some(name) = local.name(db) {
77 let shadow_count =
78 bindings_shadow_count.entry(name.clone()).or_default();
79 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
80 }
81 };
82
83 let mut h = highlight_def(db, def);
84
85 if let Definition::Local(local) = &def {
86 if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) {
87 h |= HlMod::Consuming;
88 }
89 }
90
91 if let Some(parent) = name_ref.syntax().parent() {
92 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
93 if let Definition::Field(field) = def {
94 if let VariantDef::Union(_) = field.parent_def(db) {
95 h |= HlMod::Unsafe;
96 }
97 }
98 }
99 }
100
101 h
102 }
103 NameRefClass::FieldShorthand { .. } => {
104 HlTag::Symbol(SymbolKind::Field).into()
105 }
106 },
107 None if syntactic_name_ref_highlighting => {
108 highlight_name_ref_by_syntax(name_ref, sema)
109 }
110 None => HlTag::UnresolvedReference.into(),
111 }
112 })
113 }
114
115 // Simple token-based highlighting
116 COMMENT => {
117 let comment = element.into_token().and_then(ast::Comment::cast)?;
118 let h = HlTag::Comment;
119 match comment.kind().doc {
120 Some(_) => h | HlMod::Documentation,
121 None => h.into(),
122 }
123 }
124 STRING | BYTE_STRING => HlTag::StringLiteral.into(),
125 ATTR => HlTag::Attribute.into(),
126 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
127 BYTE => HlTag::ByteLiteral.into(),
128 CHAR => HlTag::CharLiteral.into(),
129 QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow,
130 LIFETIME => {
131 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
132
133 match NameClass::classify_lifetime(sema, &lifetime) {
134 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
135 None => match NameRefClass::classify_lifetime(sema, &lifetime) {
136 Some(NameRefClass::Definition(def)) => highlight_def(db, def),
137 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)),
138 },
139 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | HlMod::Definition,
140 }
141 }
142 p if p.is_punct() => match p {
143 T![&] => {
144 let h = HlTag::Operator.into();
145 let is_unsafe = element
146 .parent()
147 .and_then(ast::RefExpr::cast)
148 .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr))
149 .unwrap_or(false);
150 if is_unsafe {
151 h | HlMod::Unsafe
152 } else {
153 h
154 }
155 }
156 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(),
157 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
158 HlTag::Symbol(SymbolKind::Macro).into()
159 }
160 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
161 HlTag::BuiltinType.into()
162 }
163 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
164 HlTag::Keyword.into()
165 }
166 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
167 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
168
169 let expr = prefix_expr.expr()?;
170 let ty = sema.type_of_expr(&expr)?;
171 if ty.is_raw_ptr() {
172 HlTag::Operator | HlMod::Unsafe
173 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
174 HlTag::Operator.into()
175 } else {
176 HlTag::Punctuation(HlPunct::Other).into()
177 }
178 }
179 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
180 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
181
182 let expr = prefix_expr.expr()?;
183 match expr {
184 ast::Expr::Literal(_) => HlTag::NumericLiteral,
185 _ => HlTag::Operator,
186 }
187 .into()
188 }
189 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
190 HlTag::Operator.into()
191 }
192 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(),
193 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
194 HlTag::Operator.into()
195 }
196 _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(),
197 _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(),
198 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(),
199 kind => HlTag::Punctuation(match kind {
200 T!['['] | T![']'] => HlPunct::Bracket,
201 T!['{'] | T!['}'] => HlPunct::Brace,
202 T!['('] | T![')'] => HlPunct::Parenthesis,
203 T![<] | T![>] => HlPunct::Angle,
204 T![,] => HlPunct::Comma,
205 T![:] => HlPunct::Colon,
206 T![;] => HlPunct::Semi,
207 T![.] => HlPunct::Dot,
208 _ => HlPunct::Other,
209 })
210 .into(),
211 },
212
213 k if k.is_keyword() => {
214 let h = Highlight::new(HlTag::Keyword);
215 match k {
216 T![break]
217 | T![continue]
218 | T![else]
219 | T![if]
220 | T![loop]
221 | T![match]
222 | T![return]
223 | T![while]
224 | T![in] => h | HlMod::ControlFlow,
225 T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow,
226 T![unsafe] => h | HlMod::Unsafe,
227 T![true] | T![false] => HlTag::BoolLiteral.into(),
228 T![self] => {
229 let self_param_is_mut = element
230 .parent()
231 .and_then(ast::SelfParam::cast)
232 .and_then(|p| p.mut_token())
233 .is_some();
234 let self_path = &element
235 .parent()
236 .as_ref()
237 .and_then(SyntaxNode::parent)
238 .and_then(ast::Path::cast)
239 .and_then(|p| sema.resolve_path(&p));
240 let mut h = HlTag::Symbol(SymbolKind::SelfParam).into();
241 if self_param_is_mut
242 || matches!(self_path,
243 Some(hir::PathResolution::Local(local))
244 if local.is_self(db)
245 && (local.is_mut(db) || local.ty(db).is_mutable_reference())
246 )
247 {
248 h |= HlMod::Mutable
249 }
250
251 if let Some(hir::PathResolution::Local(local)) = self_path {
252 if is_consumed_lvalue(element, &local, db) {
253 h |= HlMod::Consuming;
254 }
255 }
256
257 h
258 }
259 T![ref] => element
260 .parent()
261 .and_then(ast::IdentPat::cast)
262 .and_then(|ident_pat| {
263 if sema.is_unsafe_ident_pat(&ident_pat) {
264 Some(HlMod::Unsafe)
265 } else {
266 None
267 }
268 })
269 .map(|modifier| h | modifier)
270 .unwrap_or(h),
271 _ => h,
272 }
273 }
274
275 _ => return None,
276 };
277
278 return Some((highlight, binding_hash));
279
280 fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
281 fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
282 use std::{collections::hash_map::DefaultHasher, hash::Hasher};
283
284 let mut hasher = DefaultHasher::new();
285 x.hash(&mut hasher);
286 hasher.finish()
287 }
288
289 hash((name, shadow_count))
290 }
291}
292
293fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
294 match def {
295 Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro),
296 Definition::Field(_) => HlTag::Symbol(SymbolKind::Field),
297 Definition::ModuleDef(def) => match def {
298 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module),
299 hir::ModuleDef::Function(func) => {
300 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
301 if func.as_assoc_item(db).is_some() {
302 h |= HlMod::Associated;
303 if func.self_param(db).is_none() {
304 h |= HlMod::Static
305 }
306 }
307 if func.is_unsafe(db) {
308 h |= HlMod::Unsafe;
309 }
310 return h;
311 }
312 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct),
313 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum),
314 hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union),
315 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant),
316 hir::ModuleDef::Const(konst) => {
317 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
318 if konst.as_assoc_item(db).is_some() {
319 h |= HlMod::Associated
320 }
321 return h;
322 }
323 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
324 hir::ModuleDef::TypeAlias(type_) => {
325 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
326 if type_.as_assoc_item(db).is_some() {
327 h |= HlMod::Associated
328 }
329 return h;
330 }
331 hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType,
332 hir::ModuleDef::Static(s) => {
333 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
334 if s.is_mut(db) {
335 h |= HlMod::Mutable;
336 h |= HlMod::Unsafe;
337 }
338 return h;
339 }
340 },
341 Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl),
342 Definition::GenericParam(it) => match it {
343 hir::GenericParam::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam),
344 hir::GenericParam::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam),
345 hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam),
346 },
347 Definition::Local(local) => {
348 let tag = if local.is_param(db) {
349 HlTag::Symbol(SymbolKind::ValueParam)
350 } else {
351 HlTag::Symbol(SymbolKind::Local)
352 };
353 let mut h = Highlight::new(tag);
354 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
355 h |= HlMod::Mutable;
356 }
357 if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) {
358 h |= HlMod::Callable;
359 }
360 return h;
361 }
362 Definition::Label(_) => HlTag::Symbol(SymbolKind::Label),
363 }
364 .into()
365}
366
367fn highlight_func_by_name_ref(
368 sema: &Semantics<RootDatabase>,
369 name_ref: &ast::NameRef,
370) -> Option<Highlight> {
371 let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
372 highlight_method_call(sema, &mc)
373}
374
375fn highlight_method_call(
376 sema: &Semantics<RootDatabase>,
377 method_call: &ast::MethodCallExpr,
378) -> Option<Highlight> {
379 let func = sema.resolve_method_call(&method_call)?;
380 let mut h = HlTag::Symbol(SymbolKind::Function).into();
381 h |= HlMod::Associated;
382 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
383 h |= HlMod::Unsafe;
384 }
385 if let Some(self_param) = func.self_param(sema.db) {
386 match self_param.access(sema.db) {
387 hir::Access::Shared => (),
388 hir::Access::Exclusive => h |= HlMod::Mutable,
389 hir::Access::Owned => {
390 if let Some(receiver_ty) =
391 method_call.receiver().and_then(|it| sema.type_of_expr(&it))
392 {
393 if !receiver_ty.is_copy(sema.db) {
394 h |= HlMod::Consuming
395 }
396 }
397 }
398 }
399 }
400 Some(h)
401}
402
403fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
404 let default = HlTag::UnresolvedReference;
405
406 let parent = match name.syntax().parent() {
407 Some(it) => it,
408 _ => return default.into(),
409 };
410
411 let tag = match parent.kind() {
412 STRUCT => HlTag::Symbol(SymbolKind::Struct),
413 ENUM => HlTag::Symbol(SymbolKind::Enum),
414 VARIANT => HlTag::Symbol(SymbolKind::Variant),
415 UNION => HlTag::Symbol(SymbolKind::Union),
416 TRAIT => HlTag::Symbol(SymbolKind::Trait),
417 TYPE_ALIAS => HlTag::Symbol(SymbolKind::TypeAlias),
418 TYPE_PARAM => HlTag::Symbol(SymbolKind::TypeParam),
419 RECORD_FIELD => HlTag::Symbol(SymbolKind::Field),
420 MODULE => HlTag::Symbol(SymbolKind::Module),
421 FN => HlTag::Symbol(SymbolKind::Function),
422 CONST => HlTag::Symbol(SymbolKind::Const),
423 STATIC => HlTag::Symbol(SymbolKind::Static),
424 IDENT_PAT => HlTag::Symbol(SymbolKind::Local),
425 _ => default,
426 };
427
428 tag.into()
429}
430
431fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
432 let default = HlTag::UnresolvedReference;
433
434 let parent = match name.syntax().parent() {
435 Some(it) => it,
436 _ => return default.into(),
437 };
438
439 match parent.kind() {
440 METHOD_CALL_EXPR => {
441 return ast::MethodCallExpr::cast(parent)
442 .and_then(|it| highlight_method_call(sema, &it))
443 .unwrap_or_else(|| HlTag::Symbol(SymbolKind::Function).into());
444 }
445 FIELD_EXPR => {
446 let h = HlTag::Symbol(SymbolKind::Field);
447 let is_union = ast::FieldExpr::cast(parent)
448 .and_then(|field_expr| {
449 let field = sema.resolve_field(&field_expr)?;
450 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
451 true
452 } else {
453 false
454 })
455 })
456 .unwrap_or(false);
457 if is_union {
458 h | HlMod::Unsafe
459 } else {
460 h.into()
461 }
462 }
463 PATH_SEGMENT => {
464 let path = match parent.parent().and_then(ast::Path::cast) {
465 Some(it) => it,
466 _ => return default.into(),
467 };
468 let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) {
469 Some(it) => it,
470 _ => {
471 // within path, decide whether it is module or adt by checking for uppercase name
472 return if name.text().chars().next().unwrap_or_default().is_uppercase() {
473 HlTag::Symbol(SymbolKind::Struct)
474 } else {
475 HlTag::Symbol(SymbolKind::Module)
476 }
477 .into();
478 }
479 };
480 let parent = match expr.syntax().parent() {
481 Some(it) => it,
482 None => return default.into(),
483 };
484
485 match parent.kind() {
486 CALL_EXPR => HlTag::Symbol(SymbolKind::Function).into(),
487 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
488 HlTag::Symbol(SymbolKind::Struct)
489 } else {
490 HlTag::Symbol(SymbolKind::Const)
491 }
492 .into(),
493 }
494 }
495 _ => default.into(),
496 }
497}
498
499fn is_consumed_lvalue(
500 node: NodeOrToken<SyntaxNode, SyntaxToken>,
501 local: &hir::Local,
502 db: &RootDatabase,
503) -> bool {
504 // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming.
505 parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db)
506}
507
508/// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly.
509fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool {
510 while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) {
511 if parent.kind() != *kind {
512 return false;
513 }
514
515 // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value
516 // in the same pattern is unstable: rust-lang/rust#68354.
517 node = node.parent().unwrap().into();
518 kinds = rest;
519 }
520
521 // Only true if we matched all expected kinds
522 kinds.len() == 0
523}
524
525fn is_child_of_impl(element: &SyntaxElement) -> bool {
526 match element.parent() {
527 Some(e) => e.kind() == IMPL,
528 _ => false,
529 }
530}
diff --git a/crates/ide/src/syntax_highlighting/highlights.rs b/crates/ide/src/syntax_highlighting/highlights.rs
new file mode 100644
index 000000000..c6f0417ec
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/highlights.rs
@@ -0,0 +1,102 @@
1//! Collects a tree of highlighted ranges and flattens it.
2use std::{cmp::Ordering, iter};
3
4use stdx::equal_range_by;
5use syntax::TextRange;
6
7use crate::{HlRange, HlTag};
8
9pub(super) struct Highlights {
10 root: Node,
11}
12
13struct Node {
14 hl_range: HlRange,
15 nested: Vec<Node>,
16}
17
18impl Highlights {
19 pub(super) fn new(range: TextRange) -> Highlights {
20 Highlights {
21 root: Node::new(HlRange { range, highlight: HlTag::None.into(), binding_hash: None }),
22 }
23 }
24
25 pub(super) fn add(&mut self, hl_range: HlRange) {
26 self.root.add(hl_range);
27 }
28
29 pub(super) fn to_vec(self) -> Vec<HlRange> {
30 let mut res = Vec::new();
31 self.root.flatten(&mut res);
32 res
33 }
34}
35
36impl Node {
37 fn new(hl_range: HlRange) -> Node {
38 Node { hl_range, nested: Vec::new() }
39 }
40
41 fn add(&mut self, hl_range: HlRange) {
42 assert!(self.hl_range.range.contains_range(hl_range.range));
43
44 // Fast path
45 if let Some(last) = self.nested.last_mut() {
46 if last.hl_range.range.contains_range(hl_range.range) {
47 return last.add(hl_range);
48 }
49 if last.hl_range.range.end() <= hl_range.range.start() {
50 return self.nested.push(Node::new(hl_range));
51 }
52 }
53
54 let overlapping =
55 equal_range_by(&self.nested, |n| ordering(n.hl_range.range, hl_range.range));
56
57 if overlapping.len() == 1
58 && self.nested[overlapping.start].hl_range.range.contains_range(hl_range.range)
59 {
60 return self.nested[overlapping.start].add(hl_range);
61 }
62
63 let nested = self
64 .nested
65 .splice(overlapping.clone(), iter::once(Node::new(hl_range)))
66 .collect::<Vec<_>>();
67 self.nested[overlapping.start].nested = nested;
68 }
69
70 fn flatten(&self, acc: &mut Vec<HlRange>) {
71 let mut start = self.hl_range.range.start();
72 let mut nested = self.nested.iter();
73 loop {
74 let next = nested.next();
75 let end = next.map_or(self.hl_range.range.end(), |it| it.hl_range.range.start());
76 if start < end {
77 acc.push(HlRange {
78 range: TextRange::new(start, end),
79 highlight: self.hl_range.highlight,
80 binding_hash: self.hl_range.binding_hash,
81 });
82 }
83 start = match next {
84 Some(child) => {
85 child.flatten(acc);
86 child.hl_range.range.end()
87 }
88 None => break,
89 }
90 }
91 }
92}
93
94pub(super) fn ordering(r1: TextRange, r2: TextRange) -> Ordering {
95 if r1.end() <= r2.start() {
96 Ordering::Less
97 } else if r2.end() <= r1.start() {
98 Ordering::Greater
99 } else {
100 Ordering::Equal
101 }
102}
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 99ba3a59d..0ee7bc96e 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -3,7 +3,7 @@
3use ide_db::base_db::SourceDatabase; 3use ide_db::base_db::SourceDatabase;
4use oorandom::Rand32; 4use oorandom::Rand32;
5use stdx::format_to; 5use stdx::format_to;
6use syntax::{AstNode, TextRange, TextSize}; 6use syntax::AstNode;
7 7
8use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; 8use crate::{syntax_highlighting::highlight, FileId, RootDatabase};
9 9
@@ -20,35 +20,27 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
20 ) 20 )
21 } 21 }
22 22
23 let ranges = highlight(db, file_id, None, false); 23 let hl_ranges = highlight(db, file_id, None, false);
24 let text = parse.tree().syntax().to_string(); 24 let text = parse.tree().syntax().to_string();
25 let mut prev_pos = TextSize::from(0);
26 let mut buf = String::new(); 25 let mut buf = String::new();
27 buf.push_str(&STYLE); 26 buf.push_str(&STYLE);
28 buf.push_str("<pre><code>"); 27 buf.push_str("<pre><code>");
29 for range in &ranges { 28 for r in &hl_ranges {
30 if range.range.start() > prev_pos { 29 let chunk = html_escape(&text[r.range]);
31 let curr = &text[TextRange::new(prev_pos, range.range.start())]; 30 if r.highlight.is_empty() {
32 let text = html_escape(curr); 31 format_to!(buf, "{}", chunk);
33 buf.push_str(&text); 32 continue;
34 } 33 }
35 let curr = &text[TextRange::new(range.range.start(), range.range.end())];
36 34
37 let class = range.highlight.to_string().replace('.', " "); 35 let class = r.highlight.to_string().replace('.', " ");
38 let color = match (rainbow, range.binding_hash) { 36 let color = match (rainbow, r.binding_hash) {
39 (true, Some(hash)) => { 37 (true, Some(hash)) => {
40 format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash)) 38 format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash))
41 } 39 }
42 _ => "".into(), 40 _ => "".into(),
43 }; 41 };
44 format_to!(buf, "<span class=\"{}\"{}>{}</span>", class, color, html_escape(curr)); 42 format_to!(buf, "<span class=\"{}\"{}>{}</span>", class, color, chunk);
45
46 prev_pos = range.range.end();
47 } 43 }
48 // Add the remaining (non-highlighted) text
49 let curr = &text[TextRange::new(prev_pos, TextSize::of(&text))];
50 let text = html_escape(curr);
51 buf.push_str(&text);
52 buf.push_str("</code></pre>"); 44 buf.push_str("</code></pre>");
53 buf 45 buf
54} 46}
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
new file mode 100644
index 000000000..281461493
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -0,0 +1,158 @@
1//! "Recursive" Syntax highlighting for code in doctests and fixtures.
2
3use hir::Semantics;
4use ide_db::call_info::ActiveParameter;
5use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
6
7use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase};
8
9use super::{highlights::Highlights, injector::Injector};
10
11pub(super) fn ra_fixture(
12 hl: &mut Highlights,
13 sema: &Semantics<RootDatabase>,
14 literal: ast::String,
15 expanded: SyntaxToken,
16) -> Option<()> {
17 let active_parameter = ActiveParameter::at_token(&sema, expanded)?;
18 if !active_parameter.name.starts_with("ra_fixture") {
19 return None;
20 }
21 let value = literal.value()?;
22
23 if let Some(range) = literal.open_quote_text_range() {
24 hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
25 }
26
27 let mut inj = Injector::default();
28
29 let mut text = &*value;
30 let mut offset: TextSize = 0.into();
31
32 while !text.is_empty() {
33 let marker = "$0";
34 let idx = text.find(marker).unwrap_or(text.len());
35 let (chunk, next) = text.split_at(idx);
36 inj.add(chunk, TextRange::at(offset, TextSize::of(chunk)));
37
38 text = next;
39 offset += TextSize::of(chunk);
40
41 if let Some(next) = text.strip_prefix(marker) {
42 if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) {
43 hl.add(HlRange { range, highlight: HlTag::Keyword.into(), binding_hash: None });
44 }
45
46 text = next;
47
48 let marker_len = TextSize::of(marker);
49 offset += marker_len;
50 }
51 }
52
53 let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string());
54
55 for mut hl_range in analysis.highlight(tmp_file_id).unwrap() {
56 for range in inj.map_range_up(hl_range.range) {
57 if let Some(range) = literal.map_range_up(range) {
58 hl_range.range = range;
59 hl.add(hl_range.clone());
60 }
61 }
62 }
63
64 if let Some(range) = literal.close_quote_text_range() {
65 hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
66 }
67
68 Some(())
69}
70
71const RUSTDOC_FENCE: &'static str = "```";
72const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
73 "",
74 "rust",
75 "should_panic",
76 "ignore",
77 "no_run",
78 "compile_fail",
79 "edition2015",
80 "edition2018",
81 "edition2021",
82];
83
84/// Injection of syntax highlighting of doctests.
85pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) {
86 let doc_comments = node
87 .children_with_tokens()
88 .filter_map(|it| it.into_token().and_then(ast::Comment::cast))
89 .filter(|it| it.kind().doc.is_some());
90
91 if !doc_comments.clone().any(|it| it.text().contains(RUSTDOC_FENCE)) {
92 return;
93 }
94
95 let mut inj = Injector::default();
96 inj.add_unmapped("fn doctest() {\n");
97
98 let mut is_codeblock = false;
99 let mut is_doctest = false;
100
101 // Replace the original, line-spanning comment ranges by new, only comment-prefix
102 // spanning comment ranges.
103 let mut new_comments = Vec::new();
104 for comment in doc_comments {
105 match comment.text().find(RUSTDOC_FENCE) {
106 Some(idx) => {
107 is_codeblock = !is_codeblock;
108 // Check whether code is rust by inspecting fence guards
109 let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..];
110 let is_rust =
111 guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
112 is_doctest = is_codeblock && is_rust;
113 continue;
114 }
115 None if !is_doctest => continue,
116 None => (),
117 }
118
119 let line: &str = comment.text().as_str();
120 let range = comment.syntax().text_range();
121
122 let mut pos = TextSize::of(comment.prefix());
123 // whitespace after comment is ignored
124 if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) {
125 pos += TextSize::of(ws);
126 }
127 // lines marked with `#` should be ignored in output, we skip the `#` char
128 if let Some(ws) = line[pos.into()..].chars().next().filter(|&c| c == '#') {
129 pos += TextSize::of(ws);
130 }
131
132 new_comments.push(TextRange::at(range.start(), pos));
133
134 inj.add(&line[pos.into()..], TextRange::new(range.start() + pos, range.end()));
135 inj.add_unmapped("\n");
136 }
137 inj.add_unmapped("\n}");
138
139 let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string());
140
141 for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() {
142 for r in inj.map_range_up(h.range) {
143 hl.add(HlRange {
144 range: r,
145 highlight: h.highlight | HlMod::Injected,
146 binding_hash: h.binding_hash,
147 });
148 }
149 }
150
151 for range in new_comments {
152 hl.add(HlRange {
153 range,
154 highlight: HlTag::Comment | HlMod::Documentation,
155 binding_hash: None,
156 });
157 }
158}
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs
deleted file mode 100644
index 6cbd683c6..000000000
--- a/crates/ide/src/syntax_highlighting/injection.rs
+++ /dev/null
@@ -1,192 +0,0 @@
1//! Syntax highlighting injections such as highlighting of documentation tests.
2
3use std::{collections::BTreeMap, convert::TryFrom};
4
5use hir::Semantics;
6use ide_db::call_info::ActiveParameter;
7use itertools::Itertools;
8use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
9
10use crate::{Analysis, Highlight, HighlightModifier, HighlightTag, HighlightedRange, RootDatabase};
11
12use super::HighlightedRangeStack;
13
14pub(super) fn highlight_injection(
15 acc: &mut HighlightedRangeStack,
16 sema: &Semantics<RootDatabase>,
17 literal: ast::String,
18 expanded: SyntaxToken,
19) -> Option<()> {
20 let active_parameter = ActiveParameter::at_token(&sema, expanded)?;
21 if !active_parameter.name.starts_with("ra_fixture") {
22 return None;
23 }
24 let value = literal.value()?;
25 let (analysis, tmp_file_id) = Analysis::from_single_file(value.into_owned());
26
27 if let Some(range) = literal.open_quote_text_range() {
28 acc.add(HighlightedRange {
29 range,
30 highlight: HighlightTag::StringLiteral.into(),
31 binding_hash: None,
32 })
33 }
34
35 for mut h in analysis.highlight(tmp_file_id).unwrap() {
36 if let Some(r) = literal.map_range_up(h.range) {
37 h.range = r;
38 acc.add(h)
39 }
40 }
41
42 if let Some(range) = literal.close_quote_text_range() {
43 acc.add(HighlightedRange {
44 range,
45 highlight: HighlightTag::StringLiteral.into(),
46 binding_hash: None,
47 })
48 }
49
50 Some(())
51}
52
53/// Mapping from extracted documentation code to original code
54type RangesMap = BTreeMap<TextSize, TextSize>;
55
56const RUSTDOC_FENCE: &'static str = "```";
57const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
58 "",
59 "rust",
60 "should_panic",
61 "ignore",
62 "no_run",
63 "compile_fail",
64 "edition2015",
65 "edition2018",
66 "edition2021",
67];
68
69/// Extracts Rust code from documentation comments as well as a mapping from
70/// the extracted source code back to the original source ranges.
71/// Lastly, a vector of new comment highlight ranges (spanning only the
72/// comment prefix) is returned which is used in the syntax highlighting
73/// injection to replace the previous (line-spanning) comment ranges.
74pub(super) fn extract_doc_comments(
75 node: &SyntaxNode,
76) -> Option<(String, RangesMap, Vec<HighlightedRange>)> {
77 // wrap the doctest into function body to get correct syntax highlighting
78 let prefix = "fn doctest() {\n";
79 let suffix = "}\n";
80 // Mapping from extracted documentation code to original code
81 let mut range_mapping: RangesMap = BTreeMap::new();
82 let mut line_start = TextSize::try_from(prefix.len()).unwrap();
83 let mut is_codeblock = false;
84 let mut is_doctest = false;
85 // Replace the original, line-spanning comment ranges by new, only comment-prefix
86 // spanning comment ranges.
87 let mut new_comments = Vec::new();
88 let doctest = node
89 .children_with_tokens()
90 .filter_map(|el| el.into_token().and_then(ast::Comment::cast))
91 .filter(|comment| comment.kind().doc.is_some())
92 .filter(|comment| {
93 if let Some(idx) = comment.text().find(RUSTDOC_FENCE) {
94 is_codeblock = !is_codeblock;
95 // Check whether code is rust by inspecting fence guards
96 let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..];
97 let is_rust =
98 guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
99 is_doctest = is_codeblock && is_rust;
100 false
101 } else {
102 is_doctest
103 }
104 })
105 .map(|comment| {
106 let prefix_len = comment.prefix().len();
107 let line: &str = comment.text().as_str();
108 let range = comment.syntax().text_range();
109
110 // whitespace after comment is ignored
111 let pos = if let Some(ws) = line.chars().nth(prefix_len).filter(|c| c.is_whitespace()) {
112 prefix_len + ws.len_utf8()
113 } else {
114 prefix_len
115 };
116
117 // lines marked with `#` should be ignored in output, we skip the `#` char
118 let pos = if let Some(ws) = line.chars().nth(pos).filter(|&c| c == '#') {
119 pos + ws.len_utf8()
120 } else {
121 pos
122 };
123
124 range_mapping.insert(line_start, range.start() + TextSize::try_from(pos).unwrap());
125 new_comments.push(HighlightedRange {
126 range: TextRange::new(
127 range.start(),
128 range.start() + TextSize::try_from(pos).unwrap(),
129 ),
130 highlight: HighlightTag::Comment | HighlightModifier::Documentation,
131 binding_hash: None,
132 });
133 line_start += range.len() - TextSize::try_from(pos).unwrap();
134 line_start += TextSize::try_from('\n'.len_utf8()).unwrap();
135
136 line[pos..].to_owned()
137 })
138 .join("\n");
139
140 if doctest.is_empty() {
141 return None;
142 }
143
144 let doctest = format!("{}{}{}", prefix, doctest, suffix);
145 Some((doctest, range_mapping, new_comments))
146}
147
148/// Injection of syntax highlighting of doctests.
149pub(super) fn highlight_doc_comment(
150 text: String,
151 range_mapping: RangesMap,
152 new_comments: Vec<HighlightedRange>,
153 stack: &mut HighlightedRangeStack,
154) {
155 let (analysis, tmp_file_id) = Analysis::from_single_file(text);
156
157 stack.push();
158 for mut h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() {
159 // Determine start offset and end offset in case of multi-line ranges
160 let mut start_offset = None;
161 let mut end_offset = None;
162 for (line_start, orig_line_start) in range_mapping.range(..h.range.end()).rev() {
163 // It's possible for orig_line_start - line_start to be negative. Add h.range.start()
164 // here and remove it from the end range after the loop below so that the values are
165 // always non-negative.
166 let offset = h.range.start() + orig_line_start - line_start;
167 if line_start <= &h.range.start() {
168 start_offset.get_or_insert(offset);
169 break;
170 } else {
171 end_offset.get_or_insert(offset);
172 }
173 }
174 if let Some(start_offset) = start_offset {
175 h.range = TextRange::new(
176 start_offset,
177 h.range.end() + end_offset.unwrap_or(start_offset) - h.range.start(),
178 );
179
180 h.highlight |= HighlightModifier::Injected;
181 stack.add(h);
182 }
183 }
184
185 // Inject the comment prefix highlight ranges
186 stack.push();
187 for comment in new_comments {
188 stack.add(comment);
189 }
190 stack.pop_and_inject(None);
191 stack.pop_and_inject(Some(Highlight::from(HighlightTag::Dummy) | HighlightModifier::Injected));
192}
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs
new file mode 100644
index 000000000..fd4025694
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/injector.rs
@@ -0,0 +1,80 @@
1//! Extracts a subsequence of a text document, remembering the mapping of ranges
2//! between original and extracted texts.
3use std::ops::{self, Sub};
4
5use stdx::equal_range_by;
6use syntax::{TextRange, TextSize};
7
8use super::highlights::ordering;
9
10#[derive(Default)]
11pub(super) struct Injector {
12 buf: String,
13 ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
14}
15
16impl Injector {
17 pub(super) fn add(&mut self, text: &str, source_range: TextRange) {
18 let len = TextSize::of(text);
19 assert_eq!(len, source_range.len());
20 self.add_impl(text, Some(source_range.start()));
21 }
22 pub(super) fn add_unmapped(&mut self, text: &str) {
23 self.add_impl(text, None);
24 }
25 fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
26 let len = TextSize::of(text);
27 let target_range = TextRange::at(TextSize::of(&self.buf), len);
28 self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it))));
29 self.buf.push_str(text);
30 }
31
32 pub(super) fn text(&self) -> &str {
33 &self.buf
34 }
35 pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
36 equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)).filter_map(move |i| {
37 let (target_range, delta) = self.ranges[i];
38 let intersection = target_range.intersect(range).unwrap();
39 Some(intersection + delta?)
40 })
41 }
42}
43
44#[derive(Clone, Copy)]
45enum Delta<T> {
46 Add(T),
47 Sub(T),
48}
49
50impl<T> Delta<T> {
51 fn new(from: T, to: T) -> Delta<T>
52 where
53 T: Ord + Sub<Output = T>,
54 {
55 if to >= from {
56 Delta::Add(to - from)
57 } else {
58 Delta::Sub(from - to)
59 }
60 }
61}
62
63impl ops::Add<Delta<TextSize>> for TextSize {
64 type Output = TextSize;
65
66 fn add(self, rhs: Delta<TextSize>) -> TextSize {
67 match rhs {
68 Delta::Add(it) => self + it,
69 Delta::Sub(it) => self - it,
70 }
71 }
72}
73
74impl ops::Add<Delta<TextSize>> for TextRange {
75 type Output = TextRange;
76
77 fn add(self, rhs: Delta<TextSize>) -> TextRange {
78 TextRange::at(self.start() + rhs, self.len())
79 }
80}
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_rules.rs
index 4462af47e..44620e912 100644
--- a/crates/ide/src/syntax_highlighting/macro_rules.rs
+++ b/crates/ide/src/syntax_highlighting/macro_rules.rs
@@ -1,7 +1,7 @@
1//! Syntax highlighting for macro_rules!. 1//! Syntax highlighting for macro_rules!.
2use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T}; 2use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T};
3 3
4use crate::{HighlightTag, HighlightedRange}; 4use crate::{HlRange, HlTag};
5 5
6#[derive(Default)] 6#[derive(Default)]
7pub(super) struct MacroRulesHighlighter { 7pub(super) struct MacroRulesHighlighter {
@@ -19,13 +19,13 @@ impl MacroRulesHighlighter {
19 } 19 }
20 } 20 }
21 21
22 pub(super) fn highlight(&self, element: SyntaxElement) -> Option<HighlightedRange> { 22 pub(super) fn highlight(&self, element: SyntaxElement) -> Option<HlRange> {
23 if let Some(state) = self.state.as_ref() { 23 if let Some(state) = self.state.as_ref() {
24 if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) { 24 if matches!(state.rule_state, RuleState::Matcher | RuleState::Expander) {
25 if let Some(range) = is_metavariable(element) { 25 if let Some(range) = is_metavariable(element) {
26 return Some(HighlightedRange { 26 return Some(HlRange {
27 range, 27 range,
28 highlight: HighlightTag::UnresolvedReference.into(), 28 highlight: HlTag::UnresolvedReference.into(),
29 binding_hash: None, 29 binding_hash: None,
30 }); 30 });
31 } 31 }
@@ -119,7 +119,7 @@ fn is_metavariable(element: SyntaxElement) -> Option<TextRange> {
119 let tok = element.as_token()?; 119 let tok = element.as_token()?;
120 match tok.kind() { 120 match tok.kind() {
121 kind if kind == SyntaxKind::IDENT || kind.is_keyword() => { 121 kind if kind == SyntaxKind::IDENT || kind.is_keyword() => {
122 if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == SyntaxKind::DOLLAR) { 122 if let Some(_dollar) = tok.prev_token().filter(|t| t.kind() == T![$]) {
123 return Some(tok.text_range()); 123 return Some(tok.text_range());
124 } 124 }
125 } 125 }
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 8b8867079..8dd05ac52 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -7,15 +7,15 @@ use crate::SymbolKind;
7 7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub struct Highlight { 9pub struct Highlight {
10 pub tag: HighlightTag, 10 pub tag: HlTag,
11 pub modifiers: HighlightModifiers, 11 pub mods: HlMods,
12} 12}
13 13
14#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 14#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
15pub struct HighlightModifiers(u32); 15pub struct HlMods(u32);
16 16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18pub enum HighlightTag { 18pub enum HlTag {
19 Symbol(SymbolKind), 19 Symbol(SymbolKind),
20 20
21 BoolLiteral, 21 BoolLiteral,
@@ -29,17 +29,17 @@ pub enum HighlightTag {
29 EscapeSequence, 29 EscapeSequence,
30 FormatSpecifier, 30 FormatSpecifier,
31 Keyword, 31 Keyword,
32 Punctuation, 32 Punctuation(HlPunct),
33 Operator, 33 Operator,
34 UnresolvedReference, 34 UnresolvedReference,
35 35
36 // For things which don't have proper Tag, but want to use modifiers. 36 // For things which don't have a specific highlight.
37 Dummy, 37 None,
38} 38}
39 39
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
41#[repr(u8)] 41#[repr(u8)]
42pub enum HighlightModifier { 42pub enum HlMod {
43 /// Used to differentiate individual elements within attributes. 43 /// Used to differentiate individual elements within attributes.
44 Attribute = 0, 44 Attribute = 0,
45 /// Used with keywords like `if` and `break`. 45 /// Used with keywords like `if` and `break`.
@@ -61,10 +61,32 @@ pub enum HighlightModifier {
61 Unsafe, 61 Unsafe,
62} 62}
63 63
64impl HighlightTag { 64#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
65pub enum HlPunct {
66 /// []
67 Bracket,
68 /// {}
69 Brace,
70 /// ()
71 Parenthesis,
72 /// <>
73 Angle,
74 /// ,
75 Comma,
76 /// .
77 Dot,
78 /// :
79 Colon,
80 /// ;
81 Semi,
82 ///
83 Other,
84}
85
86impl HlTag {
65 fn as_str(self) -> &'static str { 87 fn as_str(self) -> &'static str {
66 match self { 88 match self {
67 HighlightTag::Symbol(symbol) => match symbol { 89 HlTag::Symbol(symbol) => match symbol {
68 SymbolKind::Const => "constant", 90 SymbolKind::Const => "constant",
69 SymbolKind::Static => "static", 91 SymbolKind::Static => "static",
70 SymbolKind::Enum => "enum", 92 SymbolKind::Enum => "enum",
@@ -86,59 +108,69 @@ impl HighlightTag {
86 SymbolKind::SelfParam => "self_keyword", 108 SymbolKind::SelfParam => "self_keyword",
87 SymbolKind::Impl => "self_type", 109 SymbolKind::Impl => "self_type",
88 }, 110 },
89 HighlightTag::Attribute => "attribute", 111 HlTag::Attribute => "attribute",
90 HighlightTag::BoolLiteral => "bool_literal", 112 HlTag::BoolLiteral => "bool_literal",
91 HighlightTag::BuiltinType => "builtin_type", 113 HlTag::BuiltinType => "builtin_type",
92 HighlightTag::ByteLiteral => "byte_literal", 114 HlTag::ByteLiteral => "byte_literal",
93 HighlightTag::CharLiteral => "char_literal", 115 HlTag::CharLiteral => "char_literal",
94 HighlightTag::Comment => "comment", 116 HlTag::Comment => "comment",
95 HighlightTag::EscapeSequence => "escape_sequence", 117 HlTag::EscapeSequence => "escape_sequence",
96 HighlightTag::FormatSpecifier => "format_specifier", 118 HlTag::FormatSpecifier => "format_specifier",
97 HighlightTag::Dummy => "dummy", 119 HlTag::Keyword => "keyword",
98 HighlightTag::Keyword => "keyword", 120 HlTag::Punctuation(punct) => match punct {
99 HighlightTag::Punctuation => "punctuation", 121 HlPunct::Bracket => "bracket",
100 HighlightTag::NumericLiteral => "numeric_literal", 122 HlPunct::Brace => "brace",
101 HighlightTag::Operator => "operator", 123 HlPunct::Parenthesis => "parenthesis",
102 HighlightTag::StringLiteral => "string_literal", 124 HlPunct::Angle => "angle",
103 HighlightTag::UnresolvedReference => "unresolved_reference", 125 HlPunct::Comma => "comma",
126 HlPunct::Dot => "dot",
127 HlPunct::Colon => "colon",
128 HlPunct::Semi => "semicolon",
129 HlPunct::Other => "punctuation",
130 },
131 HlTag::NumericLiteral => "numeric_literal",
132 HlTag::Operator => "operator",
133 HlTag::StringLiteral => "string_literal",
134 HlTag::UnresolvedReference => "unresolved_reference",
135 HlTag::None => "none",
104 } 136 }
105 } 137 }
106} 138}
107 139
108impl fmt::Display for HighlightTag { 140impl fmt::Display for HlTag {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 fmt::Display::fmt(self.as_str(), f) 142 fmt::Display::fmt(self.as_str(), f)
111 } 143 }
112} 144}
113 145
114impl HighlightModifier { 146impl HlMod {
115 const ALL: &'static [HighlightModifier; HighlightModifier::Unsafe as u8 as usize + 1] = &[ 147 const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[
116 HighlightModifier::Attribute, 148 HlMod::Attribute,
117 HighlightModifier::ControlFlow, 149 HlMod::ControlFlow,
118 HighlightModifier::Definition, 150 HlMod::Definition,
119 HighlightModifier::Documentation, 151 HlMod::Documentation,
120 HighlightModifier::Injected, 152 HlMod::Injected,
121 HighlightModifier::Mutable, 153 HlMod::Mutable,
122 HighlightModifier::Consuming, 154 HlMod::Consuming,
123 HighlightModifier::Callable, 155 HlMod::Callable,
124 HighlightModifier::Static, 156 HlMod::Static,
125 HighlightModifier::Associated, 157 HlMod::Associated,
126 HighlightModifier::Unsafe, 158 HlMod::Unsafe,
127 ]; 159 ];
128 160
129 fn as_str(self) -> &'static str { 161 fn as_str(self) -> &'static str {
130 match self { 162 match self {
131 HighlightModifier::Attribute => "attribute", 163 HlMod::Attribute => "attribute",
132 HighlightModifier::ControlFlow => "control", 164 HlMod::ControlFlow => "control",
133 HighlightModifier::Definition => "declaration", 165 HlMod::Definition => "declaration",
134 HighlightModifier::Documentation => "documentation", 166 HlMod::Documentation => "documentation",
135 HighlightModifier::Injected => "injected", 167 HlMod::Injected => "injected",
136 HighlightModifier::Mutable => "mutable", 168 HlMod::Mutable => "mutable",
137 HighlightModifier::Consuming => "consuming", 169 HlMod::Consuming => "consuming",
138 HighlightModifier::Unsafe => "unsafe", 170 HlMod::Unsafe => "unsafe",
139 HighlightModifier::Callable => "callable", 171 HlMod::Callable => "callable",
140 HighlightModifier::Static => "static", 172 HlMod::Static => "static",
141 HighlightModifier::Associated => "associated", 173 HlMod::Associated => "associated",
142 } 174 }
143 } 175 }
144 176
@@ -147,7 +179,7 @@ impl HighlightModifier {
147 } 179 }
148} 180}
149 181
150impl fmt::Display for HighlightModifier { 182impl fmt::Display for HlMod {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 fmt::Display::fmt(self.as_str(), f) 184 fmt::Display::fmt(self.as_str(), f)
153 } 185 }
@@ -156,60 +188,63 @@ impl fmt::Display for HighlightModifier {
156impl fmt::Display for Highlight { 188impl fmt::Display for Highlight {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 write!(f, "{}", self.tag)?; 190 write!(f, "{}", self.tag)?;
159 for modifier in self.modifiers.iter() { 191 for modifier in self.mods.iter() {
160 write!(f, ".{}", modifier)? 192 write!(f, ".{}", modifier)?
161 } 193 }
162 Ok(()) 194 Ok(())
163 } 195 }
164} 196}
165 197
166impl From<HighlightTag> for Highlight { 198impl From<HlTag> for Highlight {
167 fn from(tag: HighlightTag) -> Highlight { 199 fn from(tag: HlTag) -> Highlight {
168 Highlight::new(tag) 200 Highlight::new(tag)
169 } 201 }
170} 202}
171 203
172impl Highlight { 204impl Highlight {
173 pub(crate) fn new(tag: HighlightTag) -> Highlight { 205 pub(crate) fn new(tag: HlTag) -> Highlight {
174 Highlight { tag, modifiers: HighlightModifiers::default() } 206 Highlight { tag, mods: HlMods::default() }
207 }
208 pub fn is_empty(&self) -> bool {
209 self.tag == HlTag::None && self.mods == HlMods::default()
175 } 210 }
176} 211}
177 212
178impl ops::BitOr<HighlightModifier> for HighlightTag { 213impl ops::BitOr<HlMod> for HlTag {
179 type Output = Highlight; 214 type Output = Highlight;
180 215
181 fn bitor(self, rhs: HighlightModifier) -> Highlight { 216 fn bitor(self, rhs: HlMod) -> Highlight {
182 Highlight::new(self) | rhs 217 Highlight::new(self) | rhs
183 } 218 }
184} 219}
185 220
186impl ops::BitOrAssign<HighlightModifier> for HighlightModifiers { 221impl ops::BitOrAssign<HlMod> for HlMods {
187 fn bitor_assign(&mut self, rhs: HighlightModifier) { 222 fn bitor_assign(&mut self, rhs: HlMod) {
188 self.0 |= rhs.mask(); 223 self.0 |= rhs.mask();
189 } 224 }
190} 225}
191 226
192impl ops::BitOrAssign<HighlightModifier> for Highlight { 227impl ops::BitOrAssign<HlMod> for Highlight {
193 fn bitor_assign(&mut self, rhs: HighlightModifier) { 228 fn bitor_assign(&mut self, rhs: HlMod) {
194 self.modifiers |= rhs; 229 self.mods |= rhs;
195 } 230 }
196} 231}
197 232
198impl ops::BitOr<HighlightModifier> for Highlight { 233impl ops::BitOr<HlMod> for Highlight {
199 type Output = Highlight; 234 type Output = Highlight;
200 235
201 fn bitor(mut self, rhs: HighlightModifier) -> Highlight { 236 fn bitor(mut self, rhs: HlMod) -> Highlight {
202 self |= rhs; 237 self |= rhs;
203 self 238 self
204 } 239 }
205} 240}
206 241
207impl HighlightModifiers { 242impl HlMods {
208 pub fn contains(self, m: HighlightModifier) -> bool { 243 pub fn contains(self, m: HlMod) -> bool {
209 self.0 & m.mask() == m.mask() 244 self.0 & m.mask() == m.mask()
210 } 245 }
211 246
212 pub fn iter(self) -> impl Iterator<Item = HighlightModifier> { 247 pub fn iter(self) -> impl Iterator<Item = HlMod> {
213 HighlightModifier::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask()) 248 HlMod::ALL.iter().copied().filter(move |it| self.0 & it.mask() == it.mask())
214 } 249 }
215} 250}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 506ebe60e..e36e6fc3f 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -36,22 +36,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 39<pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40 40
41<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="punctuation">{</span><span class="punctuation">}</span> 41<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="brace">{</span><span class="brace">}</span>
42 42
43<span class="keyword">impl</span> <span class="struct">foo</span> <span class="punctuation">{</span> 43<span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span>
44 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 44 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
46<span class="punctuation">}</span> 46<span class="brace">}</span>
47 47
48<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="punctuation">{</span> 48<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
49 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 49 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
50 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 50 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51<span class="punctuation">}</span> 51<span class="brace">}</span>
52 52
53<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="punctuation">{</span> 53<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
54 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 54 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
56<span class="punctuation">}</span> 56<span class="brace">}</span>
57 </code></pre> \ No newline at end of file 57 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 4dd7413ba..6dadda1c1 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -37,67 +37,72 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="comment documentation">/// ```</span> 39<pre><code><span class="comment documentation">/// ```</span>
40<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="punctuation injected">_</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="punctuation injected">;</span><span class="punctuation injected"> 40<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="semicolon injected">;</span>
41</span><span class="comment documentation">/// ```</span> 41<span class="comment documentation">/// ```</span>
42<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> 42<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span>
43 <span class="field declaration">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span><span class="punctuation">,</span> 43 <span class="field declaration">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span><span class="comma">,</span>
44<span class="punctuation">}</span> 44<span class="brace">}</span>
45 45
46<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 46<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span>
47 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="punctuation">;</span> 47 <span class="comment documentation">/// ```</span>
48 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Call me</span>
49 <span class="comment">// KILLER WHALE</span>
50 <span class="comment documentation">/// </span><span class="string_literal injected"> Ishmael."</span><span class="semicolon injected">;</span>
51 <span class="comment documentation">/// ```</span>
52 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span>
48 53
49 <span class="comment documentation">/// Constructs a new `Foo`.</span> 54 <span class="comment documentation">/// Constructs a new `Foo`.</span>
50 <span class="comment documentation">///</span> 55 <span class="comment documentation">///</span>
51 <span class="comment documentation">/// # Examples</span> 56 <span class="comment documentation">/// # Examples</span>
52 <span class="comment documentation">///</span> 57 <span class="comment documentation">///</span>
53 <span class="comment documentation">/// ```</span> 58 <span class="comment documentation">/// ```</span>
54 <span class="comment documentation">/// #</span><span class="dummy injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="punctuation attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="punctuation attribute injected">)</span><span class="attribute attribute injected">]</span> 59 <span class="comment documentation">/// #</span><span class="none injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute attribute injected">]</span>
55 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="keyword injected">mut</span><span class="dummy injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> 60 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
56</span> <span class="comment documentation">/// ```</span> 61 <span class="comment documentation">/// ```</span>
57 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 62 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
58 <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">bar</span><span class="punctuation">:</span> <span class="bool_literal">true</span> <span class="punctuation">}</span> 63 <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">bar</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span>
59 <span class="punctuation">}</span> 64 <span class="brace">}</span>
60 65
61 <span class="comment documentation">/// `bar` method on `Foo`.</span> 66 <span class="comment documentation">/// `bar` method on `Foo`.</span>
62 <span class="comment documentation">///</span> 67 <span class="comment documentation">///</span>
63 <span class="comment documentation">/// # Examples</span> 68 <span class="comment documentation">/// # Examples</span>
64 <span class="comment documentation">///</span> 69 <span class="comment documentation">///</span>
65 <span class="comment documentation">/// ```</span> 70 <span class="comment documentation">/// ```</span>
66 <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="dummy injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="punctuation injected">;</span> 71 <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="none injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="semicolon injected">;</span>
67 <span class="comment documentation">///</span> 72 <span class="comment documentation">///</span>
68 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">foo</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> 73 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
69 <span class="comment documentation">///</span> 74 <span class="comment documentation">///</span>
70 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> 75 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span>
71 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="punctuation injected">(</span><span class="dummy injected">foo</span><span class="operator injected">.</span><span class="dummy injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span> 76 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
72 <span class="comment documentation">///</span> 77 <span class="comment documentation">///</span>
73 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">bar</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="dummy injected"> </span><span class="operator injected">||</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="punctuation injected">;</span> 78 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span>
74 <span class="comment documentation">///</span> 79 <span class="comment documentation">///</span>
75 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line 80 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span>
76 </span><span class="comment documentation">/// </span><span class="comment injected"> comment */</span> 81 <span class="comment documentation">/// </span><span class="comment injected"> comment */</span>
77 <span class="comment documentation">///</span> 82 <span class="comment documentation">///</span>
78 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="string_literal injected">"Foo 83 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span>
79 </span><span class="comment documentation">/// </span><span class="string_literal injected"> bar 84 <span class="comment documentation">/// </span><span class="string_literal injected"> bar</span>
80 </span><span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="punctuation injected">;</span> 85 <span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="semicolon injected">;</span>
81 <span class="comment documentation">///</span> 86 <span class="comment documentation">///</span>
82 <span class="comment documentation">/// ```</span> 87 <span class="comment documentation">/// ```</span>
83 <span class="comment documentation">///</span> 88 <span class="comment documentation">///</span>
84 <span class="comment documentation">/// ```rust,no_run</span> 89 <span class="comment documentation">/// ```rust,no_run</span>
85 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="dummy injected"> </span><span class="variable declaration injected">foobar</span><span class="dummy injected"> </span><span class="operator injected">=</span><span class="dummy injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> 90 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
86</span> <span class="comment documentation">/// ```</span> 91 <span class="comment documentation">/// ```</span>
87 <span class="comment documentation">///</span> 92 <span class="comment documentation">///</span>
88 <span class="comment documentation">/// ```sh</span> 93 <span class="comment documentation">/// ```sh</span>
89 <span class="comment documentation">/// echo 1</span> 94 <span class="comment documentation">/// echo 1</span>
90 <span class="comment documentation">/// ```</span> 95 <span class="comment documentation">/// ```</span>
91 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="punctuation">{</span> 96 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
92 <span class="bool_literal">true</span> 97 <span class="bool_literal">true</span>
93 <span class="punctuation">}</span> 98 <span class="brace">}</span>
94<span class="punctuation">}</span> 99<span class="brace">}</span>
95 100
96<span class="comment documentation">/// ```</span> 101<span class="comment documentation">/// ```</span>
97<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected"> 102<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
98</span><span class="comment documentation">/// ```</span> 103<span class="comment documentation">/// ```</span>
99<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> 104<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
100 <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 105 <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
101 <span class="punctuation">$</span>expr 106 <span class="punctuation">$</span>expr
102 <span class="punctuation">}</span> 107 <span class="brace">}</span>
103<span class="punctuation">}</span></code></pre> \ No newline at end of file 108<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index ed452586a..6f7a7ffff 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -36,6 +36,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span> 39<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="semicolon">;</span>
40<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span> 40<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="semicolon">;</span>
41</code></pre> \ No newline at end of file 41</code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 92e7dc3e4..753b535b5 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -36,14 +36,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 39<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40 40
41<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 41<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
42 <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span> 42 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
43 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span> 43 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span>
44 <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 44 <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
45 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> 45 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span>
46 <span class="punctuation">}</span> 46 <span class="brace">}</span>
47 <span class="punctuation">}</span><span class="string_literal">"#</span> 47 <span class="brace">}</span><span class="string_literal">"#</span>
48 <span class="punctuation">)</span><span class="punctuation">;</span> 48 <span class="parenthesis">)</span><span class="semicolon">;</span>
49<span class="punctuation">}</span></code></pre> \ No newline at end of file 49<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 31dad5d42..66d80c4b6 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -36,64 +36,64 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span> 39<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
40 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">{</span> 40 <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="brace">{</span>
41 <span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> 41 <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
42 <span class="punctuation">}</span><span class="punctuation">)</span> 42 <span class="brace">}</span><span class="parenthesis">)</span>
43<span class="punctuation">}</span> 43<span class="brace">}</span>
44<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> 44<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
45<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span> 45<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span>
46 <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> 46 <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span>
47 <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span> 47 <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>args<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">{</span> <span class="comment">/* compiler built-in */</span> <span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span>
48<span class="punctuation">}</span> 48<span class="brace">}</span>
49 49
50<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 50<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
51 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> 51 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
52 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "Hello"</span> 52 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "Hello"</span>
53 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "Hello, world!"</span> 53 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "Hello, world!"</span>
54 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "The number is 1"</span> 54 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "The number is 1"</span>
55 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="numeric_literal">3</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "(3, 4)"</span> 55 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="parenthesis">(</span><span class="numeric_literal">3</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "(3, 4)"</span>
56 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "4"</span> 56 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "4"</span>
57 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "1 2"</span> 57 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "1 2"</span>
58 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">42</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "0042" with leading zerosV</span> 58 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">42</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "0042" with leading zerosV</span>
59 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "2 1 1 2"</span> 59 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "2 1 1 2"</span>
60 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "test"</span> 60 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "test"</span>
61 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "2 1"</span> 61 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">1</span><span class="comma">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "2 1"</span>
62 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="punctuation">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="punctuation">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "a 3 b"</span> 62 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="comma">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="comma">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "a 3 b"</span>
63 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "{2}"</span> 63 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="comma">,</span> <span class="numeric_literal">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "{2}"</span>
64 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 64 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
65 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 65 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
66 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 66 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
67 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 67 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
68 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 68 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
69 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 69 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
70 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 70 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
71 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span> 71 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
72 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 72 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
73 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> 73 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span>
74 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 74 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
75 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span> 75 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
76 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span> 76 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="numeric_literal">27</span><span class="parenthesis">)</span><span class="semicolon">;</span>
77 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 77 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
78 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 78 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
79 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 79 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
80 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 80 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
81 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 81 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> <span class="numeric_literal">5</span><span class="comma">,</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
82 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span> 82 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> <span class="string_literal">"x"</span><span class="comma">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="comma">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
83 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="punctuation">)</span><span class="punctuation">;</span> 83 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="parenthesis">)</span><span class="semicolon">;</span>
84 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> 84 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
85 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span> 85 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="comma">,</span> <span class="string_literal">"Hello"</span><span class="comma">,</span> <span class="numeric_literal">3</span><span class="comma">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
86 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello {{}}"</span><span class="punctuation">)</span><span class="punctuation">;</span> 86 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello {{}}"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
87 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{ Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> 87 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"{{ Hello"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
88 88
89 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> 89 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="comma">,</span> <span class="string_literal">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
90 90
91 <span class="comment">// escape sequences</span> 91 <span class="comment">// escape sequences</span>
92 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="punctuation">)</span><span class="punctuation">;</span> 92 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
93 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="punctuation">)</span><span class="punctuation">;</span> 93 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
94 94
95 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> 95 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
96 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> 96 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="comma">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
97 97
98 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="punctuation">,</span> thingy<span class="punctuation">,</span> n2<span class="punctuation">)</span><span class="punctuation">;</span> 98 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> "</span><span class="comma">,</span> thingy<span class="comma">,</span> n2<span class="parenthesis">)</span><span class="semicolon">;</span>
99<span class="punctuation">}</span></code></pre> \ No newline at end of file 99<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index e3a0aa317..9d4d6d4a0 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -36,65 +36,65 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 39<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40 40
41<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span> 41<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="brace">{</span>
42 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> 42 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
43 <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span> 43 <span class="field declaration">b</span><span class="colon">:</span> <span class="builtin_type">f32</span><span class="comma">,</span>
44<span class="punctuation">}</span> 44<span class="brace">}</span>
45 45
46<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> 46<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span>
47 47
48<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> 48<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span>
49 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 49 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
50<span class="punctuation">}</span> 50<span class="brace">}</span>
51 51
52<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span> 52<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span>
53 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u8</span> 53 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u8</span>
54<span class="punctuation">}</span> 54<span class="brace">}</span>
55 55
56<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="punctuation">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> 56<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="colon">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
57 57
58<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="punctuation attribute">(</span><span class="attribute attribute">packed</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> 58<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">repr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
59<span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="punctuation">{</span> 59<span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span>
60 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u16</span><span class="punctuation">,</span> 60 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
61<span class="punctuation">}</span> 61<span class="brace">}</span>
62 62
63<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span> 63<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
64 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span><span class="punctuation">;</span> 64 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
65<span class="punctuation">}</span> 65<span class="brace">}</span>
66 66
67<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="punctuation">{</span> 67<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
68 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 68 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
69<span class="punctuation">}</span> 69<span class="brace">}</span>
70 70
71<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 71<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
72 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> 72 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
73 <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> 73 <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
74 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> 74 <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
75 <span class="comment">// unsafe fn and method calls</span> 75 <span class="comment">// unsafe fn and method calls</span>
76 <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 76 <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
77 <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="punctuation">;</span> 77 <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span>
78 <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span> 78 <span class="keyword control">match</span> <span class="variable">u</span> <span class="brace">{</span>
79 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> 79 <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
80 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> 80 <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">a</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
81 <span class="punctuation">}</span> 81 <span class="brace">}</span>
82 <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 82 <span class="struct">HasUnsafeFn</span><span class="operator">.</span><span class="function associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
83 83
84 <span class="comment">// unsafe deref</span> 84 <span class="comment">// unsafe deref</span>
85 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="punctuation">;</span> 85 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span>
86 86
87 <span class="comment">// unsafe access to a static mut</span> 87 <span class="comment">// unsafe access to a static mut</span>
88 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> 88 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
89 89
90 <span class="comment">// unsafe ref of packed fields</span> 90 <span class="comment">// unsafe ref of packed fields</span>
91 <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> 91 <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
92 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> 92 <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
93 <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="punctuation">;</span> 93 <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
94 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> 94 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
95 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> 95 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
96 96
97 <span class="comment">// unsafe auto ref of packed field</span> 97 <span class="comment">// unsafe auto ref of packed field</span>
98 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 98 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
99 <span class="punctuation">}</span> 99 <span class="brace">}</span>
100<span class="punctuation">}</span></code></pre> \ No newline at end of file 100<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 02270b077..6b7447c46 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -36,187 +36,187 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="punctuation">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="punctuation">}</span><span class="punctuation">;</span> 39<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
40<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="punctuation">{</span><span class="punctuation">}</span> 40<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
41 41
42<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> 42<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
43<span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> 43<span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
44 44
45<span class="comment">// Needed for function consuming vs normal</span> 45<span class="comment">// Needed for function consuming vs normal</span>
46<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="punctuation">{</span> 46<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span>
47 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span> 47 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span>
48 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> 48 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
49<span class="punctuation">}</span> 49<span class="brace">}</span>
50 50
51<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="punctuation">{</span> 51<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">ops</span> <span class="brace">{</span>
52 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span> 52 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span>
53 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="punctuation">&lt;</span><span class="type_param declaration">Args</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">}</span> 53 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
54 54
55 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span> 55 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn_mut"</span><span class="attribute attribute">]</span>
56 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="punctuation">&lt;</span><span class="type_param declaration">Args</span><span class="punctuation">&gt;</span><span class="punctuation">:</span> <span class="trait">FnOnce</span><span class="punctuation">&lt;</span><span class="type_param">Args</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">}</span> 56 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">FnMut</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait">FnOnce</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
57 57
58 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span> 58 <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"fn"</span><span class="attribute attribute">]</span>
59 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="punctuation">&lt;</span><span class="type_param declaration">Args</span><span class="punctuation">&gt;</span><span class="punctuation">:</span> <span class="trait">FnMut</span><span class="punctuation">&lt;</span><span class="type_param">Args</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">}</span> 59 <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration">Fn</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait">FnMut</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
60<span class="punctuation">}</span> 60<span class="brace">}</span>
61 61
62 62
63<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span> 63<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="brace">{</span>
64 <span class="keyword">pub</span> <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> 64 <span class="keyword">pub</span> <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span>
65 <span class="keyword">pub</span> <span class="field declaration">y</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span> 65 <span class="keyword">pub</span> <span class="field declaration">y</span><span class="colon">:</span> <span class="builtin_type">i32</span><span class="comma">,</span>
66<span class="punctuation">}</span> 66<span class="brace">}</span>
67 67
68<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span> 68<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
69 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="punctuation">;</span> 69 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
70<span class="punctuation">}</span> 70<span class="brace">}</span>
71 71
72<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 72<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
73 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> 73 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
74 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 74 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
75 <span class="punctuation">}</span> 75 <span class="brace">}</span>
76<span class="punctuation">}</span> 76<span class="brace">}</span>
77 77
78<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 78<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span>
79 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">Foo</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> 79 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
80 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="self_keyword mutable consuming">self</span><span class="punctuation">)</span> 80 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="self_keyword mutable consuming">self</span><span class="parenthesis">)</span>
81 <span class="punctuation">}</span> 81 <span class="brace">}</span>
82 82
83 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> 83 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
84 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 84 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
85 <span class="punctuation">}</span> 85 <span class="brace">}</span>
86 86
87 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> 87 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
88 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 88 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
89 <span class="punctuation">}</span> 89 <span class="brace">}</span>
90<span class="punctuation">}</span> 90<span class="brace">}</span>
91 91
92<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="punctuation attribute">(</span><span class="attribute attribute">Copy</span><span class="punctuation attribute">)</span><span class="attribute attribute">]</span> 92<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">derive</span><span class="parenthesis attribute">(</span><span class="attribute attribute">Copy</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
93<span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="punctuation">{</span> 93<span class="keyword">struct</span> <span class="struct declaration">FooCopy</span> <span class="brace">{</span>
94 <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> 94 <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
95<span class="punctuation">}</span> 95<span class="brace">}</span>
96 96
97<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> 97<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span>
98 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">FooCopy</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> 98 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
99 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span> 99 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span>
100 <span class="punctuation">}</span> 100 <span class="brace">}</span>
101 101
102 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> 102 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
103 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 103 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
104 <span class="punctuation">}</span> 104 <span class="brace">}</span>
105 105
106 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> 106 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
107 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 107 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
108 <span class="punctuation">}</span> 108 <span class="brace">}</span>
109<span class="punctuation">}</span> 109<span class="brace">}</span>
110 110
111<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> 111<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="colon">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
112 112
113<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">&lt;</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="type_param">T</span> <span class="punctuation">{</span> 113<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="angle">&lt;</span><span class="lifetime declaration">'a</span><span class="comma">,</span> <span class="type_param declaration">T</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="type_param">T</span> <span class="brace">{</span>
114 <span class="function">foo</span><span class="operator">::</span><span class="punctuation">&lt;</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> 114 <span class="function">foo</span><span class="operator">::</span><span class="angle">&lt;</span><span class="lifetime">'a</span><span class="comma">,</span> <span class="builtin_type">i32</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
115<span class="punctuation">}</span> 115<span class="brace">}</span>
116 116
117<span class="keyword">fn</span> <span class="function declaration">never</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="punctuation">{</span> 117<span class="keyword">fn</span> <span class="function declaration">never</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="brace">{</span>
118 <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> 118 <span class="keyword control">loop</span> <span class="brace">{</span><span class="brace">}</span>
119<span class="punctuation">}</span> 119<span class="brace">}</span>
120 120
121<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="punctuation">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="punctuation">:</span> <span class="builtin_type">usize</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="punctuation">{</span> 121<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
122 <span class="const_param">FOO</span> 122 <span class="const_param">FOO</span>
123<span class="punctuation">}</span> 123<span class="brace">}</span>
124 124
125<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> 125<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="semicolon">;</span>
126<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">&lt;</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> 126<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle">&lt;</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="value_param declaration callable">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span>
127 <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> 127 <span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
128<span class="punctuation">}</span> 128<span class="brace">}</span>
129 129
130<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span> 130<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="brace">{</span><span class="brace">}</span>
131 131
132<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 132<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
133 <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 133 <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
134<span class="punctuation">}</span> 134<span class="brace">}</span>
135 135
136<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span> 136<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span>
137 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span> 137 <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span>
138<span class="punctuation">}</span> 138<span class="brace">}</span>
139 139
140<span class="macro">def_fn!</span> <span class="punctuation">{</span> 140<span class="macro">def_fn!</span> <span class="brace">{</span>
141 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-</span><span class="operator">&gt;</span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> 141 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-</span><span class="operator">&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
142 <span class="numeric_literal">100</span> 142 <span class="numeric_literal">100</span>
143 <span class="punctuation">}</span> 143 <span class="brace">}</span>
144<span class="punctuation">}</span> 144<span class="brace">}</span>
145 145
146<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span> 146<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
147 <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 147 <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
148 <span class="punctuation">$</span>expr 148 <span class="punctuation">$</span>expr
149 <span class="punctuation">}</span> 149 <span class="brace">}</span>
150<span class="punctuation">}</span> 150<span class="brace">}</span>
151 151
152<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span> 152<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span>
153 <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span> 153 <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span>
154<span class="punctuation">}</span> 154<span class="brace">}</span>
155 155
156<span class="comment">// comment</span> 156<span class="comment">// comment</span>
157<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 157<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
158 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> 158 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
159 159
160 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 160 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
161 <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="punctuation">{</span> 161 <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="brace">{</span>
162 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">;</span> 162 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="semicolon">;</span>
163 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="punctuation">(</span><span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="numeric_literal">1</span> <span class="punctuation">}</span><span class="punctuation">)</span><span class="punctuation">;</span> 163 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">push</span><span class="parenthesis">(</span><span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="numeric_literal">1</span> <span class="brace">}</span><span class="parenthesis">)</span><span class="semicolon">;</span>
164 <span class="punctuation">}</span> 164 <span class="brace">}</span>
165 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> 165 <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
166 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span> 166 <span class="variable mutable">vec</span><span class="operator">.</span><span class="unresolved_reference">set_len</span><span class="parenthesis">(</span><span class="numeric_literal">0</span><span class="parenthesis">)</span><span class="semicolon">;</span>
167 <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span> 167 <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
168 <span class="punctuation">}</span> 168 <span class="brace">}</span>
169 169
170 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span> 170 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="brace">{</span>
171 <span class="comment">// Do nothing</span> 171 <span class="comment">// Do nothing</span>
172 <span class="punctuation">}</span> 172 <span class="brace">}</span>
173 173
174 <span class="macro">noop!</span><span class="punctuation">(</span><span class="macro">noop</span><span class="macro">!</span><span class="punctuation">(</span><span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> 174 <span class="macro">noop!</span><span class="parenthesis">(</span><span class="macro">noop</span><span class="macro">!</span><span class="parenthesis">(</span><span class="numeric_literal">1</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
175 175
176 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="punctuation">;</span> 176 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="semicolon">;</span>
177 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="punctuation">;</span> 177 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="semicolon">;</span>
178 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="punctuation">;</span> 178 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="semicolon">;</span>
179 179
180 <span class="keyword">let</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable declaration">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span><span class="punctuation">;</span> 180 <span class="keyword">let</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable declaration">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="colon">:</span> <span class="variable">z</span><span class="comma">,</span> <span class="field">y</span> <span class="brace">}</span><span class="semicolon">;</span>
181 181
182 <span class="variable">y</span><span class="punctuation">;</span> 182 <span class="variable">y</span><span class="semicolon">;</span>
183 183
184 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> 184 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
185 <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> 185 <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
186 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 186 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
187 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 187 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
188 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="punctuation">(</span><span class="variable consuming">foo2</span><span class="punctuation">)</span><span class="punctuation">;</span> 188 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span>
189 189
190 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> <span class="field">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> 190 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="brace">{</span> <span class="field">x</span> <span class="brace">}</span><span class="semicolon">;</span>
191 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 191 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
192 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 192 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
193 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="punctuation">(</span><span class="variable mutable">copy</span><span class="punctuation">)</span><span class="punctuation">;</span> 193 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span>
194 194
195 <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="punctuation">;</span> 195 <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span>
196 <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="punctuation">;</span> 196 <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span>
197 197
198 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="punctuation">;</span> 198 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span>
199 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span> 199 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span>
200 200
201 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="punctuation">;</span> 201 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
202 202
203 <span class="label declaration">'foo</span><span class="punctuation">:</span> <span class="keyword control">loop</span> <span class="punctuation">{</span> 203 <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span>
204 <span class="keyword control">break</span> <span class="label">'foo</span><span class="punctuation">;</span> 204 <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span>
205 <span class="keyword control">continue</span> <span class="label">'foo</span><span class="punctuation">;</span> 205 <span class="keyword control">continue</span> <span class="label">'foo</span><span class="semicolon">;</span>
206 <span class="punctuation">}</span> 206 <span class="brace">}</span>
207<span class="punctuation">}</span> 207<span class="brace">}</span>
208 208
209<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 209<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="brace">{</span>
210 <span class="enum_variant declaration">Some</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">)</span><span class="punctuation">,</span> 210 <span class="enum_variant declaration">Some</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="parenthesis">)</span><span class="comma">,</span>
211 <span class="enum_variant declaration">None</span><span class="punctuation">,</span> 211 <span class="enum_variant declaration">None</span><span class="comma">,</span>
212<span class="punctuation">}</span> 212<span class="brace">}</span>
213<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="punctuation">;</span> 213<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
214 214
215<span class="keyword">impl</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="type_param">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 215<span class="keyword">impl</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">T</span><span class="angle">&gt;</span> <span class="brace">{</span>
216 <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="punctuation">&lt;</span><span class="type_param declaration">U</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">other</span><span class="punctuation">:</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="type_param">U</span><span class="punctuation">&gt;</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">,</span> <span class="type_param">U</span><span class="punctuation">)</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 216 <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span>
217 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="punctuation">{</span> 217 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span>
218 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> 218 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
219 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="punctuation">,</span> 219 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span>
220 <span class="punctuation">}</span> 220 <span class="brace">}</span>
221 <span class="punctuation">}</span> 221 <span class="brace">}</span>
222<span class="punctuation">}</span></code></pre> \ No newline at end of file 222<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html
new file mode 100644
index 000000000..78dfec951
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/injection.html
@@ -0,0 +1,48 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.label { color: #DFAF8F; font-style: italic; }
8.comment { color: #7F9F7F; }
9.documentation { color: #629755; }
10.injected { opacity: 0.65 ; }
11.struct, .enum { color: #7CB8BB; }
12.enum_variant { color: #BDE0F3; }
13.string_literal { color: #CC9393; }
14.field { color: #94BFF3; }
15.function { color: #93E0E3; }
16.function.unsafe { color: #BC8383; }
17.operator.unsafe { color: #BC8383; }
18.parameter { color: #94BFF3; }
19.text { color: #DCDCCC; }
20.type { color: #7CB8BB; }
21.builtin_type { color: #8CD0D3; }
22.type_param { color: #DFAF8F; }
23.attribute { color: #94BFF3; }
24.numeric_literal { color: #BFEBBF; }
25.bool_literal { color: #BFE6EB; }
26.macro { color: #94BFF3; }
27.module { color: #AFD8AF; }
28.value_param { color: #DCDCCC; }
29.variable { color: #DCDCCC; }
30.format_specifier { color: #CC696B; }
31.mutable { text-decoration: underline; }
32.escape_sequence { color: #94BFF3; }
33.keyword { color: #F0DFAF; font-weight: bold; }
34.keyword.unsafe { color: #BC8383; font-weight: bold; }
35.control { font-style: italic; }
36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">f</span><span class="parenthesis">(</span><span class="value_param declaration">ra_fixture</span><span class="colon">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
40<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
41 <span class="function">f</span><span class="parenthesis">(</span><span class="string_literal">r"</span>
42<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
43 <span class="function">foo</span><span class="parenthesis">(</span><span class="keyword">$0</span><span class="brace">{</span>
44 <span class="numeric_literal">92</span>
45 <span class="brace">}</span><span class="keyword">$0</span><span class="parenthesis">)</span>
46<span class="brace">}</span><span class="string_literal">"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
47<span class="brace">}</span>
48 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
index 8b3dfa69f..e64f2e5e9 100644
--- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
@@ -36,15 +36,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
36 36
37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; } 37.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
38</style> 38</style>
39<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 39<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
40 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> 40 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
41 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 41 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
42 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 42 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
43 43
44 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="punctuation">;</span> 44 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span>
45 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 45 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
46<span class="punctuation">}</span> 46<span class="brace">}</span>
47 47
48<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 48<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
49 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span> 49 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
50<span class="punctuation">}</span></code></pre> \ No newline at end of file 50<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 30b5b648e..a62704c39 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -446,6 +446,11 @@ struct Foo {
446} 446}
447 447
448impl Foo { 448impl Foo {
449 /// ```
450 /// let _ = "Call me
451 // KILLER WHALE
452 /// Ishmael.";
453 /// ```
449 pub const bar: bool = true; 454 pub const bar: bool = true;
450 455
451 /// Constructs a new `Foo`. 456 /// Constructs a new `Foo`.
@@ -555,6 +560,25 @@ impl t for foo {
555 ) 560 )
556} 561}
557 562
563#[test]
564fn test_injection() {
565 check_highlighting(
566 r##"
567fn f(ra_fixture: &str) {}
568fn main() {
569 f(r"
570fn foo() {
571 foo(\$0{
572 92
573 }\$0)
574}");
575}
576 "##,
577 expect_file!["./test_data/injection.html"],
578 false,
579 );
580}
581
558/// Highlights the code given by the `ra_fixture` argument, renders the 582/// Highlights the code given by the `ra_fixture` argument, renders the
559/// result as HTML, and compares it with the HTML file given as `snapshot`. 583/// result as HTML, and compares it with the HTML file given as `snapshot`.
560/// Note that the `snapshot` file is overwritten by the rendered HTML. 584/// Note that the `snapshot` file is overwritten by the rendered HTML.
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs
index 6dd05c05d..1f26f8043 100644
--- a/crates/ide/src/syntax_tree.rs
+++ b/crates/ide/src/syntax_tree.rs
@@ -85,7 +85,7 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<St
85 .trim_end_matches('"') 85 .trim_end_matches('"')
86 .trim() 86 .trim()
87 // Remove custom markers 87 // Remove custom markers
88 .replace("<|>", ""); 88 .replace("$0", "");
89 89
90 let parsed = SourceFile::parse(&text); 90 let parsed = SourceFile::parse(&text);
91 91
@@ -182,7 +182,7 @@ [email protected]
182 182
183 #[test] 183 #[test]
184 fn test_syntax_tree_with_range() { 184 fn test_syntax_tree_with_range() {
185 let (analysis, range) = fixture::range(r#"<|>fn foo() {}<|>"#.trim()); 185 let (analysis, range) = fixture::range(r#"$0fn foo() {}$0"#.trim());
186 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 186 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
187 187
188 assert_eq_text!( 188 assert_eq_text!(
@@ -206,10 +206,10 @@ [email protected]
206 206
207 let (analysis, range) = fixture::range( 207 let (analysis, range) = fixture::range(
208 r#"fn test() { 208 r#"fn test() {
209 <|>assert!(" 209 $0assert!("
210 fn foo() { 210 fn foo() {
211 } 211 }
212 ", "");<|> 212 ", "");$0
213}"# 213}"#
214 .trim(), 214 .trim(),
215 ); 215 );
@@ -243,8 +243,8 @@ [email protected]
243 let (analysis, range) = fixture::range( 243 let (analysis, range) = fixture::range(
244 r#"fn test() { 244 r#"fn test() {
245 assert!(" 245 assert!("
246<|>fn foo() { 246$0fn foo() {
247}<|> 247}$0
248fn bar() { 248fn bar() {
249} 249}
250 ", ""); 250 ", "");
@@ -277,8 +277,8 @@ [email protected]
277 let (analysis, range) = fixture::range( 277 let (analysis, range) = fixture::range(
278 r###"fn test() { 278 r###"fn test() {
279 assert!(r#" 279 assert!(r#"
280<|>fn foo() { 280$0fn foo() {
281}<|> 281}$0
282fn bar() { 282fn bar() {
283} 283}
284 "#, ""); 284 "#, "");
@@ -310,11 +310,11 @@ [email protected]
310 // With a raw string 310 // With a raw string
311 let (analysis, range) = fixture::range( 311 let (analysis, range) = fixture::range(
312 r###"fn test() { 312 r###"fn test() {
313 assert!(r<|>#" 313 assert!(r$0#"
314fn foo() { 314fn foo() {
315} 315}
316fn bar() { 316fn bar() {
317}"<|>#, ""); 317}"$0#, "");
318}"### 318}"###
319 .trim(), 319 .trim(),
320 ); 320 );
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 43458a3a2..88c905003 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -170,7 +170,7 @@ mod tests {
170 fn test_on_eq_typed() { 170 fn test_on_eq_typed() {
171 // do_check(r" 171 // do_check(r"
172 // fn foo() { 172 // fn foo() {
173 // let foo =<|> 173 // let foo =$0
174 // } 174 // }
175 // ", r" 175 // ", r"
176 // fn foo() { 176 // fn foo() {
@@ -181,7 +181,7 @@ mod tests {
181 '=', 181 '=',
182 r" 182 r"
183fn foo() { 183fn foo() {
184 let foo <|> 1 + 1 184 let foo $0 1 + 1
185} 185}
186", 186",
187 r" 187 r"
@@ -192,7 +192,7 @@ fn foo() {
192 ); 192 );
193 // do_check(r" 193 // do_check(r"
194 // fn foo() { 194 // fn foo() {
195 // let foo =<|> 195 // let foo =$0
196 // let bar = 1; 196 // let bar = 1;
197 // } 197 // }
198 // ", r" 198 // ", r"
@@ -210,7 +210,7 @@ fn foo() {
210 r" 210 r"
211 fn main() { 211 fn main() {
212 xs.foo() 212 xs.foo()
213 <|> 213 $0
214 } 214 }
215 ", 215 ",
216 r" 216 r"
@@ -225,7 +225,7 @@ fn foo() {
225 r" 225 r"
226 fn main() { 226 fn main() {
227 xs.foo() 227 xs.foo()
228 <|> 228 $0
229 } 229 }
230 ", 230 ",
231 ) 231 )
@@ -238,7 +238,7 @@ fn foo() {
238 r" 238 r"
239 fn main() { 239 fn main() {
240 xs.foo() 240 xs.foo()
241 <|>; 241 $0;
242 } 242 }
243 ", 243 ",
244 r" 244 r"
@@ -253,7 +253,7 @@ fn foo() {
253 r" 253 r"
254 fn main() { 254 fn main() {
255 xs.foo() 255 xs.foo()
256 <|>; 256 $0;
257 } 257 }
258 ", 258 ",
259 ) 259 )
@@ -266,7 +266,7 @@ fn foo() {
266 r#" 266 r#"
267fn main() { 267fn main() {
268 let _ = foo 268 let _ = foo
269 <|> 269 $0
270 bar() 270 bar()
271} 271}
272"#, 272"#,
@@ -288,7 +288,7 @@ fn main() {
288 fn main() { 288 fn main() {
289 xs.foo() 289 xs.foo()
290 .first() 290 .first()
291 <|> 291 $0
292 } 292 }
293 ", 293 ",
294 r" 294 r"
@@ -305,7 +305,7 @@ fn main() {
305 fn main() { 305 fn main() {
306 xs.foo() 306 xs.foo()
307 .first() 307 .first()
308 <|> 308 $0
309 } 309 }
310 ", 310 ",
311 ); 311 );
@@ -318,7 +318,7 @@ fn main() {
318 r" 318 r"
319 fn source_impl() { 319 fn source_impl() {
320 let var = enum_defvariant_list().unwrap() 320 let var = enum_defvariant_list().unwrap()
321 <|> 321 $0
322 .nth(92) 322 .nth(92)
323 .unwrap(); 323 .unwrap();
324 } 324 }
@@ -337,7 +337,7 @@ fn main() {
337 r" 337 r"
338 fn source_impl() { 338 fn source_impl() {
339 let var = enum_defvariant_list().unwrap() 339 let var = enum_defvariant_list().unwrap()
340 <|> 340 $0
341 .nth(92) 341 .nth(92)
342 .unwrap(); 342 .unwrap();
343 } 343 }
@@ -351,7 +351,7 @@ fn main() {
351 '.', 351 '.',
352 r" 352 r"
353 fn main() { 353 fn main() {
354 <|> 354 $0
355 } 355 }
356 ", 356 ",
357 ); 357 );
@@ -359,7 +359,7 @@ fn main() {
359 '.', 359 '.',
360 r" 360 r"
361 fn main() { 361 fn main() {
362 <|> 362 $0
363 } 363 }
364 ", 364 ",
365 ); 365 );
@@ -367,6 +367,6 @@ fn main() {
367 367
368 #[test] 368 #[test]
369 fn adds_space_after_return_type() { 369 fn adds_space_after_return_type() {
370 type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -> { 92 }") 370 type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }")
371 } 371 }
372} 372}
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index f4ea30352..63cd51b69 100644
--- a/crates/ide/src/typing/on_enter.rs
+++ b/crates/ide/src/typing/on_enter.rs
@@ -136,7 +136,7 @@ mod tests {
136 fn continues_doc_comment() { 136 fn continues_doc_comment() {
137 do_check( 137 do_check(
138 r" 138 r"
139/// Some docs<|> 139/// Some docs$0
140fn foo() { 140fn foo() {
141} 141}
142", 142",
@@ -151,7 +151,7 @@ fn foo() {
151 do_check( 151 do_check(
152 r" 152 r"
153impl S { 153impl S {
154 /// Some<|> docs. 154 /// Some$0 docs.
155 fn foo() {} 155 fn foo() {}
156} 156}
157", 157",
@@ -166,7 +166,7 @@ impl S {
166 166
167 do_check( 167 do_check(
168 r" 168 r"
169///<|> Some docs 169///$0 Some docs
170fn foo() { 170fn foo() {
171} 171}
172", 172",
@@ -181,7 +181,7 @@ fn foo() {
181 181
182 #[test] 182 #[test]
183 fn does_not_continue_before_doc_comment() { 183 fn does_not_continue_before_doc_comment() {
184 do_check_noop(r"<|>//! docz"); 184 do_check_noop(r"$0//! docz");
185 } 185 }
186 186
187 #[test] 187 #[test]
@@ -189,7 +189,7 @@ fn foo() {
189 do_check( 189 do_check(
190 r" 190 r"
191fn main() { 191fn main() {
192 // Fix<|> me 192 // Fix$0 me
193 let x = 1 + 1; 193 let x = 1 + 1;
194} 194}
195", 195",
@@ -208,7 +208,7 @@ fn main() {
208 do_check( 208 do_check(
209 r" 209 r"
210fn main() { 210fn main() {
211 // Fix<|> 211 // Fix$0
212 // me 212 // me
213 let x = 1 + 1; 213 let x = 1 + 1;
214} 214}
@@ -229,7 +229,7 @@ fn main() {
229 do_check_noop( 229 do_check_noop(
230 r" 230 r"
231fn main() { 231fn main() {
232 // Fix me<|> 232 // Fix me$0
233 let x = 1 + 1; 233 let x = 1 + 1;
234} 234}
235", 235",
@@ -242,7 +242,7 @@ fn main() {
242 do_check( 242 do_check(
243 r#" 243 r#"
244fn main() { 244fn main() {
245 // Fix me <|> 245 // Fix me $0
246 let x = 1 + 1; 246 let x = 1 + 1;
247} 247}
248"#, 248"#,
@@ -261,7 +261,7 @@ fn main() {
261 do_check( 261 do_check(
262 " 262 "
263fn main() { 263fn main() {
264 // Fix me \t\t <|> 264 // Fix me \t\t $0
265 let x = 1 + 1; 265 let x = 1 + 1;
266} 266}
267", 267",