diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/annotations.rs | 100 | ||||
-rw-r--r-- | crates/ide/src/diagnostics.rs | 67 | ||||
-rw-r--r-- | crates/ide/src/fixture.rs | 17 | ||||
-rwxr-xr-x | crates/ide/src/folding_ranges.rs | 17 | ||||
-rw-r--r-- | crates/ide/src/goto_implementation.rs | 70 | ||||
-rw-r--r-- | crates/ide/src/goto_type_definition.rs | 32 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting.rs | 101 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/highlight.rs | 107 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/tags.rs | 6 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/test_data/highlighting.html | 18 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/tests.rs | 44 |
13 files changed, 459 insertions, 124 deletions
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 5ebe7fd0e..8d68dce05 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs | |||
@@ -5,7 +5,7 @@ use ide_db::{ | |||
5 | helpers::visit_file_defs, | 5 | helpers::visit_file_defs, |
6 | RootDatabase, | 6 | RootDatabase, |
7 | }; | 7 | }; |
8 | use syntax::{ast::NameOwner, AstNode, TextRange, TextSize}; | 8 | use syntax::{ast::NameOwner, AstNode, TextRange}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | fn_references::find_all_methods, | 11 | fn_references::find_all_methods, |
@@ -58,7 +58,7 @@ pub(crate) fn annotations( | |||
58 | } | 58 | } |
59 | 59 | ||
60 | let action = runnable.action(); | 60 | let action = runnable.action(); |
61 | let range = runnable.nav.full_range; | 61 | let range = runnable.nav.focus_or_full_range(); |
62 | 62 | ||
63 | if config.run { | 63 | if config.run { |
64 | annotations.push(Annotation { | 64 | annotations.push(Annotation { |
@@ -80,26 +80,26 @@ pub(crate) fn annotations( | |||
80 | 80 | ||
81 | visit_file_defs(&Semantics::new(db), file_id, &mut |def| match def { | 81 | visit_file_defs(&Semantics::new(db), file_id, &mut |def| match def { |
82 | Either::Left(def) => { | 82 | Either::Left(def) => { |
83 | let node = match def { | 83 | let range = match def { |
84 | hir::ModuleDef::Const(konst) => { | 84 | hir::ModuleDef::Const(konst) => { |
85 | konst.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 85 | konst.source(db).and_then(|node| name_range(&node, file_id)) |
86 | } | 86 | } |
87 | hir::ModuleDef::Trait(trait_) => { | 87 | hir::ModuleDef::Trait(trait_) => { |
88 | trait_.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 88 | trait_.source(db).and_then(|node| name_range(&node, file_id)) |
89 | } | 89 | } |
90 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { | 90 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { |
91 | strukt.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 91 | strukt.source(db).and_then(|node| name_range(&node, file_id)) |
92 | } | 92 | } |
93 | hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => { | 93 | hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => { |
94 | enum_.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 94 | enum_.source(db).and_then(|node| name_range(&node, file_id)) |
95 | } | 95 | } |
96 | hir::ModuleDef::Adt(hir::Adt::Union(union)) => { | 96 | hir::ModuleDef::Adt(hir::Adt::Union(union)) => { |
97 | union.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 97 | union.source(db).and_then(|node| name_range(&node, file_id)) |
98 | } | 98 | } |
99 | _ => None, | 99 | _ => None, |
100 | }; | 100 | }; |
101 | let (offset, range) = match node { | 101 | let (range, offset) = match range { |
102 | Some(node) => node, | 102 | Some(range) => (range, range.start()), |
103 | None => return, | 103 | None => return, |
104 | }; | 104 | }; |
105 | 105 | ||
@@ -122,18 +122,12 @@ pub(crate) fn annotations( | |||
122 | }); | 122 | }); |
123 | } | 123 | } |
124 | 124 | ||
125 | fn range_and_position_of<T: NameOwner>( | 125 | fn name_range<T: NameOwner>(node: &InFile<T>, file_id: FileId) -> Option<TextRange> { |
126 | node: &InFile<T>, | 126 | if node.file_id == file_id.into() { |
127 | file_id: FileId, | 127 | node.value.name().map(|it| it.syntax().text_range()) |
128 | ) -> Option<(TextSize, TextRange)> { | 128 | } else { |
129 | if node.file_id != file_id.into() { | ||
130 | // Node is outside the file we are adding annotations to (e.g. macros). | 129 | // Node is outside the file we are adding annotations to (e.g. macros). |
131 | None | 130 | None |
132 | } else { | ||
133 | Some(( | ||
134 | node.value.name()?.syntax().text_range().start(), | ||
135 | node.value.syntax().text_range(), | ||
136 | )) | ||
137 | } | 131 | } |
138 | } | 132 | } |
139 | } | 133 | } |
@@ -141,13 +135,15 @@ pub(crate) fn annotations( | |||
141 | }); | 135 | }); |
142 | 136 | ||
143 | if config.annotate_method_references { | 137 | if config.annotate_method_references { |
144 | annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation { | 138 | annotations.extend(find_all_methods(db, file_id).into_iter().map( |
145 | range: method.range, | 139 | |FileRange { file_id, range }| Annotation { |
146 | kind: AnnotationKind::HasReferences { | 140 | range, |
147 | position: FilePosition { file_id, offset: method.range.start() }, | 141 | kind: AnnotationKind::HasReferences { |
148 | data: None, | 142 | position: FilePosition { file_id, offset: range.start() }, |
143 | data: None, | ||
144 | }, | ||
149 | }, | 145 | }, |
150 | })); | 146 | )); |
151 | } | 147 | } |
152 | 148 | ||
153 | annotations | 149 | annotations |
@@ -228,7 +224,7 @@ fn main() { | |||
228 | expect![[r#" | 224 | expect![[r#" |
229 | [ | 225 | [ |
230 | Annotation { | 226 | Annotation { |
231 | range: 50..85, | 227 | range: 53..57, |
232 | kind: Runnable { | 228 | kind: Runnable { |
233 | debug: false, | 229 | debug: false, |
234 | runnable: Runnable { | 230 | runnable: Runnable { |
@@ -247,7 +243,7 @@ fn main() { | |||
247 | }, | 243 | }, |
248 | }, | 244 | }, |
249 | Annotation { | 245 | Annotation { |
250 | range: 50..85, | 246 | range: 53..57, |
251 | kind: Runnable { | 247 | kind: Runnable { |
252 | debug: true, | 248 | debug: true, |
253 | runnable: Runnable { | 249 | runnable: Runnable { |
@@ -266,7 +262,7 @@ fn main() { | |||
266 | }, | 262 | }, |
267 | }, | 263 | }, |
268 | Annotation { | 264 | Annotation { |
269 | range: 0..22, | 265 | range: 6..10, |
270 | kind: HasReferences { | 266 | kind: HasReferences { |
271 | position: FilePosition { | 267 | position: FilePosition { |
272 | file_id: FileId( | 268 | file_id: FileId( |
@@ -287,7 +283,7 @@ fn main() { | |||
287 | }, | 283 | }, |
288 | }, | 284 | }, |
289 | Annotation { | 285 | Annotation { |
290 | range: 24..48, | 286 | range: 30..36, |
291 | kind: HasReferences { | 287 | kind: HasReferences { |
292 | position: FilePosition { | 288 | position: FilePosition { |
293 | file_id: FileId( | 289 | file_id: FileId( |
@@ -332,7 +328,7 @@ fn main() { | |||
332 | expect![[r#" | 328 | expect![[r#" |
333 | [ | 329 | [ |
334 | Annotation { | 330 | Annotation { |
335 | range: 14..48, | 331 | range: 17..21, |
336 | kind: Runnable { | 332 | kind: Runnable { |
337 | debug: false, | 333 | debug: false, |
338 | runnable: Runnable { | 334 | runnable: Runnable { |
@@ -351,7 +347,7 @@ fn main() { | |||
351 | }, | 347 | }, |
352 | }, | 348 | }, |
353 | Annotation { | 349 | Annotation { |
354 | range: 14..48, | 350 | range: 17..21, |
355 | kind: Runnable { | 351 | kind: Runnable { |
356 | debug: true, | 352 | debug: true, |
357 | runnable: Runnable { | 353 | runnable: Runnable { |
@@ -370,7 +366,7 @@ fn main() { | |||
370 | }, | 366 | }, |
371 | }, | 367 | }, |
372 | Annotation { | 368 | Annotation { |
373 | range: 0..12, | 369 | range: 7..11, |
374 | kind: HasImpls { | 370 | kind: HasImpls { |
375 | position: FilePosition { | 371 | position: FilePosition { |
376 | file_id: FileId( | 372 | file_id: FileId( |
@@ -384,7 +380,7 @@ fn main() { | |||
384 | }, | 380 | }, |
385 | }, | 381 | }, |
386 | Annotation { | 382 | Annotation { |
387 | range: 0..12, | 383 | range: 7..11, |
388 | kind: HasReferences { | 384 | kind: HasReferences { |
389 | position: FilePosition { | 385 | position: FilePosition { |
390 | file_id: FileId( | 386 | file_id: FileId( |
@@ -440,7 +436,7 @@ fn main() { | |||
440 | expect![[r#" | 436 | expect![[r#" |
441 | [ | 437 | [ |
442 | Annotation { | 438 | Annotation { |
443 | range: 66..100, | 439 | range: 69..73, |
444 | kind: Runnable { | 440 | kind: Runnable { |
445 | debug: false, | 441 | debug: false, |
446 | runnable: Runnable { | 442 | runnable: Runnable { |
@@ -459,7 +455,7 @@ fn main() { | |||
459 | }, | 455 | }, |
460 | }, | 456 | }, |
461 | Annotation { | 457 | Annotation { |
462 | range: 66..100, | 458 | range: 69..73, |
463 | kind: Runnable { | 459 | kind: Runnable { |
464 | debug: true, | 460 | debug: true, |
465 | runnable: Runnable { | 461 | runnable: Runnable { |
@@ -478,7 +474,7 @@ fn main() { | |||
478 | }, | 474 | }, |
479 | }, | 475 | }, |
480 | Annotation { | 476 | Annotation { |
481 | range: 0..12, | 477 | range: 7..11, |
482 | kind: HasImpls { | 478 | kind: HasImpls { |
483 | position: FilePosition { | 479 | position: FilePosition { |
484 | file_id: FileId( | 480 | file_id: FileId( |
@@ -502,7 +498,7 @@ fn main() { | |||
502 | }, | 498 | }, |
503 | }, | 499 | }, |
504 | Annotation { | 500 | Annotation { |
505 | range: 0..12, | 501 | range: 7..11, |
506 | kind: HasReferences { | 502 | kind: HasReferences { |
507 | position: FilePosition { | 503 | position: FilePosition { |
508 | file_id: FileId( | 504 | file_id: FileId( |
@@ -529,7 +525,7 @@ fn main() { | |||
529 | }, | 525 | }, |
530 | }, | 526 | }, |
531 | Annotation { | 527 | Annotation { |
532 | range: 14..34, | 528 | range: 20..31, |
533 | kind: HasImpls { | 529 | kind: HasImpls { |
534 | position: FilePosition { | 530 | position: FilePosition { |
535 | file_id: FileId( | 531 | file_id: FileId( |
@@ -553,7 +549,7 @@ fn main() { | |||
553 | }, | 549 | }, |
554 | }, | 550 | }, |
555 | Annotation { | 551 | Annotation { |
556 | range: 14..34, | 552 | range: 20..31, |
557 | kind: HasReferences { | 553 | kind: HasReferences { |
558 | position: FilePosition { | 554 | position: FilePosition { |
559 | file_id: FileId( | 555 | file_id: FileId( |
@@ -601,7 +597,7 @@ fn main() {} | |||
601 | expect![[r#" | 597 | expect![[r#" |
602 | [ | 598 | [ |
603 | Annotation { | 599 | Annotation { |
604 | range: 0..12, | 600 | range: 3..7, |
605 | kind: Runnable { | 601 | kind: Runnable { |
606 | debug: false, | 602 | debug: false, |
607 | runnable: Runnable { | 603 | runnable: Runnable { |
@@ -620,7 +616,7 @@ fn main() {} | |||
620 | }, | 616 | }, |
621 | }, | 617 | }, |
622 | Annotation { | 618 | Annotation { |
623 | range: 0..12, | 619 | range: 3..7, |
624 | kind: Runnable { | 620 | kind: Runnable { |
625 | debug: true, | 621 | debug: true, |
626 | runnable: Runnable { | 622 | runnable: Runnable { |
@@ -674,7 +670,7 @@ fn main() { | |||
674 | expect![[r#" | 670 | expect![[r#" |
675 | [ | 671 | [ |
676 | Annotation { | 672 | Annotation { |
677 | range: 58..95, | 673 | range: 61..65, |
678 | kind: Runnable { | 674 | kind: Runnable { |
679 | debug: false, | 675 | debug: false, |
680 | runnable: Runnable { | 676 | runnable: Runnable { |
@@ -693,7 +689,7 @@ fn main() { | |||
693 | }, | 689 | }, |
694 | }, | 690 | }, |
695 | Annotation { | 691 | Annotation { |
696 | range: 58..95, | 692 | range: 61..65, |
697 | kind: Runnable { | 693 | kind: Runnable { |
698 | debug: true, | 694 | debug: true, |
699 | runnable: Runnable { | 695 | runnable: Runnable { |
@@ -712,7 +708,7 @@ fn main() { | |||
712 | }, | 708 | }, |
713 | }, | 709 | }, |
714 | Annotation { | 710 | Annotation { |
715 | range: 0..12, | 711 | range: 7..11, |
716 | kind: HasImpls { | 712 | kind: HasImpls { |
717 | position: FilePosition { | 713 | position: FilePosition { |
718 | file_id: FileId( | 714 | file_id: FileId( |
@@ -736,7 +732,7 @@ fn main() { | |||
736 | }, | 732 | }, |
737 | }, | 733 | }, |
738 | Annotation { | 734 | Annotation { |
739 | range: 0..12, | 735 | range: 7..11, |
740 | kind: HasReferences { | 736 | kind: HasReferences { |
741 | position: FilePosition { | 737 | position: FilePosition { |
742 | file_id: FileId( | 738 | file_id: FileId( |
@@ -816,7 +812,7 @@ mod tests { | |||
816 | expect![[r#" | 812 | expect![[r#" |
817 | [ | 813 | [ |
818 | Annotation { | 814 | Annotation { |
819 | range: 0..12, | 815 | range: 3..7, |
820 | kind: Runnable { | 816 | kind: Runnable { |
821 | debug: false, | 817 | debug: false, |
822 | runnable: Runnable { | 818 | runnable: Runnable { |
@@ -835,7 +831,7 @@ mod tests { | |||
835 | }, | 831 | }, |
836 | }, | 832 | }, |
837 | Annotation { | 833 | Annotation { |
838 | range: 0..12, | 834 | range: 3..7, |
839 | kind: Runnable { | 835 | kind: Runnable { |
840 | debug: true, | 836 | debug: true, |
841 | runnable: Runnable { | 837 | runnable: Runnable { |
@@ -854,7 +850,7 @@ mod tests { | |||
854 | }, | 850 | }, |
855 | }, | 851 | }, |
856 | Annotation { | 852 | Annotation { |
857 | range: 14..64, | 853 | range: 18..23, |
858 | kind: Runnable { | 854 | kind: Runnable { |
859 | debug: false, | 855 | debug: false, |
860 | runnable: Runnable { | 856 | runnable: Runnable { |
@@ -875,7 +871,7 @@ mod tests { | |||
875 | }, | 871 | }, |
876 | }, | 872 | }, |
877 | Annotation { | 873 | Annotation { |
878 | range: 14..64, | 874 | range: 18..23, |
879 | kind: Runnable { | 875 | kind: Runnable { |
880 | debug: true, | 876 | debug: true, |
881 | runnable: Runnable { | 877 | runnable: Runnable { |
@@ -896,7 +892,7 @@ mod tests { | |||
896 | }, | 892 | }, |
897 | }, | 893 | }, |
898 | Annotation { | 894 | Annotation { |
899 | range: 30..62, | 895 | range: 45..57, |
900 | kind: Runnable { | 896 | kind: Runnable { |
901 | debug: false, | 897 | debug: false, |
902 | runnable: Runnable { | 898 | runnable: Runnable { |
@@ -922,7 +918,7 @@ mod tests { | |||
922 | }, | 918 | }, |
923 | }, | 919 | }, |
924 | Annotation { | 920 | Annotation { |
925 | range: 30..62, | 921 | range: 45..57, |
926 | kind: Runnable { | 922 | kind: Runnable { |
927 | debug: true, | 923 | debug: true, |
928 | runnable: Runnable { | 924 | runnable: Runnable { |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 27d347dbd..6cf5810fa 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -299,10 +299,10 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | |||
299 | 299 | ||
300 | #[cfg(test)] | 300 | #[cfg(test)] |
301 | mod tests { | 301 | mod tests { |
302 | use expect_test::{expect, Expect}; | 302 | use expect_test::Expect; |
303 | use ide_assists::AssistResolveStrategy; | 303 | use ide_assists::AssistResolveStrategy; |
304 | use stdx::trim_indent; | 304 | use stdx::trim_indent; |
305 | use test_utils::assert_eq_text; | 305 | use test_utils::{assert_eq_text, extract_annotations}; |
306 | 306 | ||
307 | use crate::{fixture, DiagnosticsConfig}; | 307 | use crate::{fixture, DiagnosticsConfig}; |
308 | 308 | ||
@@ -311,6 +311,7 @@ mod tests { | |||
311 | /// * a diagnostic is produced | 311 | /// * a diagnostic is produced |
312 | /// * the first diagnostic fix trigger range touches the input cursor position | 312 | /// * the first diagnostic fix trigger range touches the input cursor position |
313 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | 313 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied |
314 | #[track_caller] | ||
314 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | 315 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { |
315 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); | 316 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); |
316 | } | 317 | } |
@@ -325,6 +326,7 @@ mod tests { | |||
325 | } | 326 | } |
326 | } | 327 | } |
327 | 328 | ||
329 | #[track_caller] | ||
328 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { | 330 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { |
329 | let after = trim_indent(ra_fixture_after); | 331 | let after = trim_indent(ra_fixture_after); |
330 | 332 | ||
@@ -396,26 +398,51 @@ mod tests { | |||
396 | expect.assert_debug_eq(&diagnostics) | 398 | expect.assert_debug_eq(&diagnostics) |
397 | } | 399 | } |
398 | 400 | ||
401 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
402 | let (analysis, file_id) = fixture::file(ra_fixture); | ||
403 | let diagnostics = analysis | ||
404 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) | ||
405 | .unwrap(); | ||
406 | |||
407 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | ||
408 | let actual = diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); | ||
409 | assert_eq!(expected, actual); | ||
410 | } | ||
411 | |||
399 | #[test] | 412 | #[test] |
400 | fn test_unresolved_macro_range() { | 413 | fn test_unresolved_macro_range() { |
401 | check_expect( | 414 | check_diagnostics( |
402 | r#"foo::bar!(92);"#, | 415 | r#" |
403 | expect![[r#" | 416 | foo::bar!(92); |
404 | [ | 417 | //^^^ unresolved macro `foo::bar!` |
405 | Diagnostic { | 418 | "#, |
406 | message: "unresolved macro `foo::bar!`", | 419 | ); |
407 | range: 5..8, | 420 | } |
408 | severity: Error, | 421 | |
409 | fixes: None, | 422 | #[test] |
410 | unused: false, | 423 | fn unresolved_import_in_use_tree() { |
411 | code: Some( | 424 | // Only the relevant part of a nested `use` item should be highlighted. |
412 | DiagnosticCode( | 425 | check_diagnostics( |
413 | "unresolved-macro-call", | 426 | r#" |
414 | ), | 427 | use does_exist::{Exists, DoesntExist}; |
415 | ), | 428 | //^^^^^^^^^^^ unresolved import |
416 | }, | 429 | |
417 | ] | 430 | use {does_not_exist::*, does_exist}; |
418 | "#]], | 431 | //^^^^^^^^^^^^^^^^^ unresolved import |
432 | |||
433 | use does_not_exist::{ | ||
434 | a, | ||
435 | //^ unresolved import | ||
436 | b, | ||
437 | //^ unresolved import | ||
438 | c, | ||
439 | //^ unresolved import | ||
440 | }; | ||
441 | |||
442 | mod does_exist { | ||
443 | pub struct Exists; | ||
444 | } | ||
445 | "#, | ||
419 | ); | 446 | ); |
420 | } | 447 | } |
421 | 448 | ||
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs index cc6641ba1..6780af617 100644 --- a/crates/ide/src/fixture.rs +++ b/crates/ide/src/fixture.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Utilities for creating `Analysis` instances for tests. | 1 | //! Utilities for creating `Analysis` instances for tests. |
2 | use ide_db::base_db::fixture::ChangeFixture; | 2 | use ide_db::base_db::fixture::ChangeFixture; |
3 | use syntax::{TextRange, TextSize}; | 3 | use syntax::{TextRange, TextSize}; |
4 | use test_utils::{extract_annotations, RangeOrOffset}; | 4 | use test_utils::extract_annotations; |
5 | 5 | ||
6 | use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; | 6 | use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; |
7 | 7 | ||
@@ -27,10 +27,7 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { | |||
27 | let change_fixture = ChangeFixture::parse(ra_fixture); | 27 | let change_fixture = ChangeFixture::parse(ra_fixture); |
28 | host.db.apply_change(change_fixture.change); | 28 | host.db.apply_change(change_fixture.change); |
29 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); | 29 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
30 | let offset = match range_or_offset { | 30 | let offset = range_or_offset.expect_offset(); |
31 | RangeOrOffset::Range(_) => panic!(), | ||
32 | RangeOrOffset::Offset(it) => it, | ||
33 | }; | ||
34 | (host.analysis(), FilePosition { file_id, offset }) | 31 | (host.analysis(), FilePosition { file_id, offset }) |
35 | } | 32 | } |
36 | 33 | ||
@@ -40,10 +37,7 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { | |||
40 | let change_fixture = ChangeFixture::parse(ra_fixture); | 37 | let change_fixture = ChangeFixture::parse(ra_fixture); |
41 | host.db.apply_change(change_fixture.change); | 38 | host.db.apply_change(change_fixture.change); |
42 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); | 39 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
43 | let range = match range_or_offset { | 40 | let range = range_or_offset.expect_range(); |
44 | RangeOrOffset::Range(it) => it, | ||
45 | RangeOrOffset::Offset(_) => panic!(), | ||
46 | }; | ||
47 | (host.analysis(), FileRange { file_id, range }) | 41 | (host.analysis(), FileRange { file_id, range }) |
48 | } | 42 | } |
49 | 43 | ||
@@ -53,10 +47,7 @@ pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(Fil | |||
53 | let change_fixture = ChangeFixture::parse(ra_fixture); | 47 | let change_fixture = ChangeFixture::parse(ra_fixture); |
54 | host.db.apply_change(change_fixture.change); | 48 | host.db.apply_change(change_fixture.change); |
55 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); | 49 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); |
56 | let offset = match range_or_offset { | 50 | let offset = range_or_offset.expect_offset(); |
57 | RangeOrOffset::Range(_) => panic!(), | ||
58 | RangeOrOffset::Offset(it) => it, | ||
59 | }; | ||
60 | 51 | ||
61 | let annotations = change_fixture | 52 | let annotations = change_fixture |
62 | .files | 53 | .files |
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs index b893c1c54..c5015a345 100755 --- a/crates/ide/src/folding_ranges.rs +++ b/crates/ide/src/folding_ranges.rs | |||
@@ -19,6 +19,7 @@ pub enum FoldKind { | |||
19 | Statics, | 19 | Statics, |
20 | Array, | 20 | Array, |
21 | WhereClause, | 21 | WhereClause, |
22 | ReturnType, | ||
22 | } | 23 | } |
23 | 24 | ||
24 | #[derive(Debug)] | 25 | #[derive(Debug)] |
@@ -131,6 +132,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { | |||
131 | COMMENT => Some(FoldKind::Comment), | 132 | COMMENT => Some(FoldKind::Comment), |
132 | ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), | 133 | ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), |
133 | ARRAY_EXPR => Some(FoldKind::Array), | 134 | ARRAY_EXPR => Some(FoldKind::Array), |
135 | RET_TYPE => Some(FoldKind::ReturnType), | ||
134 | ASSOC_ITEM_LIST | 136 | ASSOC_ITEM_LIST |
135 | | RECORD_FIELD_LIST | 137 | | RECORD_FIELD_LIST |
136 | | RECORD_PAT_FIELD_LIST | 138 | | RECORD_PAT_FIELD_LIST |
@@ -300,6 +302,7 @@ mod tests { | |||
300 | FoldKind::Statics => "statics", | 302 | FoldKind::Statics => "statics", |
301 | FoldKind::Array => "array", | 303 | FoldKind::Array => "array", |
302 | FoldKind::WhereClause => "whereclause", | 304 | FoldKind::WhereClause => "whereclause", |
305 | FoldKind::ReturnType => "returntype", | ||
303 | }; | 306 | }; |
304 | assert_eq!(kind, &attr.unwrap()); | 307 | assert_eq!(kind, &attr.unwrap()); |
305 | } | 308 | } |
@@ -560,4 +563,18 @@ where | |||
560 | "#, | 563 | "#, |
561 | ) | 564 | ) |
562 | } | 565 | } |
566 | |||
567 | #[test] | ||
568 | fn fold_return_type() { | ||
569 | check( | ||
570 | r#" | ||
571 | fn foo()<fold returntype>-> ( | ||
572 | bool, | ||
573 | bool, | ||
574 | )</fold> { (true, true) } | ||
575 | |||
576 | fn bar() -> (bool, bool) { (true, true) } | ||
577 | "#, | ||
578 | ) | ||
579 | } | ||
563 | } | 580 | } |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 05130a237..43356a94e 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::{Impl, Semantics}; | 1 | use hir::{AsAssocItem, Impl, Semantics}; |
2 | use ide_db::{ | 2 | use ide_db::{ |
3 | defs::{Definition, NameClass, NameRefClass}, | 3 | defs::{Definition, NameClass, NameRefClass}, |
4 | RootDatabase, | 4 | RootDatabase, |
@@ -36,6 +36,7 @@ pub(crate) fn goto_implementation( | |||
36 | } | 36 | } |
37 | ast::NameLike::Lifetime(_) => None, | 37 | ast::NameLike::Lifetime(_) => None, |
38 | }?; | 38 | }?; |
39 | |||
39 | let def = match def { | 40 | let def = match def { |
40 | Definition::ModuleDef(def) => def, | 41 | Definition::ModuleDef(def) => def, |
41 | _ => return None, | 42 | _ => return None, |
@@ -48,6 +49,18 @@ pub(crate) fn goto_implementation( | |||
48 | let module = sema.to_module_def(position.file_id)?; | 49 | let module = sema.to_module_def(position.file_id)?; |
49 | impls_for_ty(&sema, builtin.ty(sema.db, module)) | 50 | impls_for_ty(&sema, builtin.ty(sema.db, module)) |
50 | } | 51 | } |
52 | hir::ModuleDef::Function(f) => { | ||
53 | let assoc = f.as_assoc_item(sema.db)?; | ||
54 | let name = assoc.name(sema.db)?; | ||
55 | let trait_ = assoc.containing_trait(sema.db)?; | ||
56 | impls_for_trait_item(&sema, trait_, name) | ||
57 | } | ||
58 | hir::ModuleDef::Const(c) => { | ||
59 | let assoc = c.as_assoc_item(sema.db)?; | ||
60 | let name = assoc.name(sema.db)?; | ||
61 | let trait_ = assoc.containing_trait(sema.db)?; | ||
62 | impls_for_trait_item(&sema, trait_, name) | ||
63 | } | ||
51 | _ => return None, | 64 | _ => return None, |
52 | }; | 65 | }; |
53 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) | 66 | Some(RangeInfo { range: node.syntax().text_range(), info: navs }) |
@@ -64,6 +77,23 @@ fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<Na | |||
64 | .collect() | 77 | .collect() |
65 | } | 78 | } |
66 | 79 | ||
80 | fn impls_for_trait_item( | ||
81 | sema: &Semantics<RootDatabase>, | ||
82 | trait_: hir::Trait, | ||
83 | fun_name: hir::Name, | ||
84 | ) -> Vec<NavigationTarget> { | ||
85 | Impl::all_for_trait(sema.db, trait_) | ||
86 | .into_iter() | ||
87 | .filter_map(|imp| { | ||
88 | let item = imp.items(sema.db).iter().find_map(|itm| { | ||
89 | let itm_name = itm.name(sema.db)?; | ||
90 | (itm_name == fun_name).then(|| itm.clone()) | ||
91 | })?; | ||
92 | item.try_to_nav(sema.db) | ||
93 | }) | ||
94 | .collect() | ||
95 | } | ||
96 | |||
67 | #[cfg(test)] | 97 | #[cfg(test)] |
68 | mod tests { | 98 | mod tests { |
69 | use ide_db::base_db::FileRange; | 99 | use ide_db::base_db::FileRange; |
@@ -262,4 +292,42 @@ impl bool {} | |||
262 | "#, | 292 | "#, |
263 | ); | 293 | ); |
264 | } | 294 | } |
295 | |||
296 | #[test] | ||
297 | fn goto_implementation_trait_functions() { | ||
298 | check( | ||
299 | r#" | ||
300 | trait Tr { | ||
301 | fn f$0(); | ||
302 | } | ||
303 | |||
304 | struct S; | ||
305 | |||
306 | impl Tr for S { | ||
307 | fn f() { | ||
308 | //^ | ||
309 | println!("Hello, world!"); | ||
310 | } | ||
311 | } | ||
312 | "#, | ||
313 | ); | ||
314 | } | ||
315 | |||
316 | #[test] | ||
317 | fn goto_implementation_trait_assoc_const() { | ||
318 | check( | ||
319 | r#" | ||
320 | trait Tr { | ||
321 | const C$0: usize; | ||
322 | } | ||
323 | |||
324 | struct S; | ||
325 | |||
326 | impl Tr for S { | ||
327 | const C: usize = 4; | ||
328 | //^ | ||
329 | } | ||
330 | "#, | ||
331 | ); | ||
332 | } | ||
265 | } | 333 | } |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index f3284bb96..004d9cb68 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use ide_db::base_db::Upcast; | ||
1 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 3 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 4 | ||
@@ -31,6 +32,7 @@ pub(crate) fn goto_type_definition( | |||
31 | ast::Pat(it) => sema.type_of_pat(&it)?, | 32 | ast::Pat(it) => sema.type_of_pat(&it)?, |
32 | ast::SelfParam(it) => sema.type_of_self(&it)?, | 33 | ast::SelfParam(it) => sema.type_of_self(&it)?, |
33 | ast::Type(it) => sema.resolve_type(&it)?, | 34 | ast::Type(it) => sema.resolve_type(&it)?, |
35 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, | ||
34 | _ => return None, | 36 | _ => return None, |
35 | } | 37 | } |
36 | }; | 38 | }; |
@@ -161,4 +163,34 @@ impl Foo$0 {} | |||
161 | "#, | 163 | "#, |
162 | ) | 164 | ) |
163 | } | 165 | } |
166 | |||
167 | #[test] | ||
168 | fn goto_def_for_struct_field() { | ||
169 | check( | ||
170 | r#" | ||
171 | struct Bar; | ||
172 | //^^^ | ||
173 | |||
174 | struct Foo { | ||
175 | bar$0: Bar, | ||
176 | } | ||
177 | "#, | ||
178 | ); | ||
179 | } | ||
180 | |||
181 | #[test] | ||
182 | fn goto_def_for_enum_struct_field() { | ||
183 | check( | ||
184 | r#" | ||
185 | struct Bar; | ||
186 | //^^^ | ||
187 | |||
188 | enum Foo { | ||
189 | Bar { | ||
190 | bar$0: Bar | ||
191 | }, | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
164 | } | 196 | } |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 8f490e922..85f887737 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -219,7 +219,7 @@ fn hint_iterator( | |||
219 | ) -> Option<SmolStr> { | 219 | ) -> Option<SmolStr> { |
220 | let db = sema.db; | 220 | let db = sema.db; |
221 | let strukt = ty.strip_references().as_adt()?; | 221 | let strukt = ty.strip_references().as_adt()?; |
222 | let krate = strukt.krate(db); | 222 | let krate = strukt.module(db).krate(); |
223 | if krate != famous_defs.core()? { | 223 | if krate != famous_defs.core()? { |
224 | return None; | 224 | return None; |
225 | } | 225 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index f76715d84..ce1c76f37 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -227,7 +227,7 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> | |||
227 | let func = def.source(sema.db)?; | 227 | let func = def.source(sema.db)?; |
228 | let name_string = def.name(sema.db).to_string(); | 228 | let name_string = def.name(sema.db).to_string(); |
229 | 229 | ||
230 | let root = def.krate(sema.db)?.root_module(sema.db); | 230 | let root = def.module(sema.db).krate().root_module(sema.db); |
231 | 231 | ||
232 | let kind = if name_string == "main" && def.module(sema.db) == root { | 232 | let kind = if name_string == "main" && def.module(sema.db) == root { |
233 | RunnableKind::Bin | 233 | RunnableKind::Bin |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 9df8d21af..79c2f4a1e 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -42,13 +42,107 @@ pub struct HlRange { | |||
42 | // Feature: Semantic Syntax Highlighting | 42 | // Feature: Semantic Syntax Highlighting |
43 | // | 43 | // |
44 | // rust-analyzer highlights the code semantically. | 44 | // rust-analyzer highlights the code semantically. |
45 | // For example, `bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. | 45 | // For example, `Bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. |
46 | // rust-analyzer does not specify colors directly, instead it assigns tag (like `struct`) and a set of modifiers (like `declaration`) to each token. | 46 | // rust-analyzer does not specify colors directly, instead it assigns a tag (like `struct`) and a set of modifiers (like `declaration`) to each token. |
47 | // It's up to the client to map those to specific colors. | 47 | // It's up to the client to map those to specific colors. |
48 | // | 48 | // |
49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. | 49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. |
50 | // We also give special modifier for `mut` and `&mut` local variables. | 50 | // We also give special modifier for `mut` and `&mut` local variables. |
51 | // | 51 | // |
52 | // | ||
53 | // .Token Tags | ||
54 | // | ||
55 | // Rust-analyzer currently emits the following token tags: | ||
56 | // | ||
57 | // - For items: | ||
58 | // + | ||
59 | // [horizontal] | ||
60 | // enum:: Emitted for enums. | ||
61 | // function:: Emitted for free-standing functions. | ||
62 | // macro:: Emitted for macros. | ||
63 | // method:: Emitted for associated functions, also knowns as methods. | ||
64 | // namespace:: Emitted for modules. | ||
65 | // struct:: Emitted for structs. | ||
66 | // trait:: Emitted for traits. | ||
67 | // typeAlias:: Emitted for type aliases and `Self` in `impl`s. | ||
68 | // union:: Emitted for unions. | ||
69 | // | ||
70 | // - For literals: | ||
71 | // + | ||
72 | // [horizontal] | ||
73 | // boolean:: Emitted for the boolean literals `true` and `false`. | ||
74 | // character:: Emitted for character literals. | ||
75 | // number:: Emitted for numeric literals. | ||
76 | // string:: Emitted for string literals. | ||
77 | // escapeSequence:: Emitted for escaped sequences inside strings like `\n`. | ||
78 | // formatSpecifier:: Emitted for format specifiers `{:?}` in `format!`-like macros. | ||
79 | // | ||
80 | // - For operators: | ||
81 | // + | ||
82 | // [horizontal] | ||
83 | // operator:: Emitted for general operators. | ||
84 | // arithmetic:: Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`. | ||
85 | // bitwise:: Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`. | ||
86 | // comparison:: Emitted for the comparison operators `>`, `<`, `==`, `>=`, `<=`, `!=`. | ||
87 | // logical:: Emitted for the logical operators `||`, `&&`, `!`. | ||
88 | // | ||
89 | // - For punctuation: | ||
90 | // + | ||
91 | // [horizontal] | ||
92 | // punctuation:: Emitted for general punctuation. | ||
93 | // angle:: Emitted for `<>` angle brackets. | ||
94 | // brace:: Emitted for `{}` braces. | ||
95 | // bracket:: Emitted for `[]` brackets. | ||
96 | // parenthesis:: Emitted for `()` parentheses. | ||
97 | // colon:: Emitted for the `:` token. | ||
98 | // comma:: Emitted for the `,` token. | ||
99 | // dot:: Emitted for the `.` token. | ||
100 | // Semi:: Emitted for the `;` token. | ||
101 | // | ||
102 | // //- | ||
103 | // | ||
104 | // [horizontal] | ||
105 | // attribute:: Emitted for attributes. | ||
106 | // builtinType:: Emitted for builtin types like `u32`, `str` and `f32`. | ||
107 | // comment:: Emitted for comments. | ||
108 | // constParameter:: Emitted for const parameters. | ||
109 | // enumMember:: Emitted for enum variants. | ||
110 | // generic:: Emitted for generic tokens that have no mapping. | ||
111 | // keyword:: Emitted for keywords. | ||
112 | // label:: Emitted for labels. | ||
113 | // lifetime:: Emitted for lifetimes. | ||
114 | // parameter:: Emitted for non-self function parameters. | ||
115 | // property:: Emitted for struct and union fields. | ||
116 | // selfKeyword:: Emitted for the self function parameter and self path-specifier. | ||
117 | // typeParameter:: Emitted for type parameters. | ||
118 | // unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of. | ||
119 | // variable:: Emitted for locals, constants and statics. | ||
120 | // | ||
121 | // | ||
122 | // .Token Modifiers | ||
123 | // | ||
124 | // Token modifiers allow to style some elements in the source code more precisely. | ||
125 | // | ||
126 | // Rust-analyzer currently emits the following token modifiers: | ||
127 | // | ||
128 | // [horizontal] | ||
129 | // async:: Emitted for async functions and the `async` and `await` keywords. | ||
130 | // attribute:: Emitted for tokens inside attributes. | ||
131 | // callable:: Emitted for locals whose types implements one of the `Fn*` traits. | ||
132 | // constant:: Emitted for consts. | ||
133 | // consuming:: Emitted for locals that are being consumed when use in a function call. | ||
134 | // controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator. | ||
135 | // declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`. | ||
136 | // documentation:: Emitted for documentation comments. | ||
137 | // injected:: Emitted for doc-string injected highlighting like rust source blocks in documentation. | ||
138 | // intraDocLink:: Emitted for intra doc links in doc-strings. | ||
139 | // library:: Emitted for items that are defined outside of the current crate. | ||
140 | // mutable:: Emitted for mutable locals and statics. | ||
141 | // static:: Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts. | ||
142 | // trait:: Emitted for associated trait items. | ||
143 | // unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token. | ||
144 | // | ||
145 | // | ||
52 | // image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[] | 146 | // image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[] |
53 | // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] | 147 | // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] |
54 | pub(crate) fn highlight( | 148 | pub(crate) fn highlight( |
@@ -80,6 +174,7 @@ pub(crate) fn highlight( | |||
80 | &mut hl, | 174 | &mut hl, |
81 | &sema, | 175 | &sema, |
82 | InFile::new(file_id.into(), &root), | 176 | InFile::new(file_id.into(), &root), |
177 | sema.scope(&root).krate(), | ||
83 | range_to_highlight, | 178 | range_to_highlight, |
84 | syntactic_name_ref_highlighting, | 179 | syntactic_name_ref_highlighting, |
85 | ); | 180 | ); |
@@ -90,6 +185,7 @@ fn traverse( | |||
90 | hl: &mut Highlights, | 185 | hl: &mut Highlights, |
91 | sema: &Semantics<RootDatabase>, | 186 | sema: &Semantics<RootDatabase>, |
92 | root: InFile<&SyntaxNode>, | 187 | root: InFile<&SyntaxNode>, |
188 | krate: Option<hir::Crate>, | ||
93 | range_to_highlight: TextRange, | 189 | range_to_highlight: TextRange, |
94 | syntactic_name_ref_highlighting: bool, | 190 | syntactic_name_ref_highlighting: bool, |
95 | ) { | 191 | ) { |
@@ -209,6 +305,7 @@ fn traverse( | |||
209 | 305 | ||
210 | if let Some((mut highlight, binding_hash)) = highlight::element( | 306 | if let Some((mut highlight, binding_hash)) = highlight::element( |
211 | &sema, | 307 | &sema, |
308 | krate, | ||
212 | &mut bindings_shadow_count, | 309 | &mut bindings_shadow_count, |
213 | syntactic_name_ref_highlighting, | 310 | syntactic_name_ref_highlighting, |
214 | element_to_highlight.clone(), | 311 | element_to_highlight.clone(), |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 058e37ff0..9503c936d 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | 19 | ||
20 | pub(super) fn element( | 20 | pub(super) fn element( |
21 | sema: &Semantics<RootDatabase>, | 21 | sema: &Semantics<RootDatabase>, |
22 | krate: Option<hir::Crate>, | ||
22 | bindings_shadow_count: &mut FxHashMap<hir::Name, u32>, | 23 | bindings_shadow_count: &mut FxHashMap<hir::Name, u32>, |
23 | syntactic_name_ref_highlighting: bool, | 24 | syntactic_name_ref_highlighting: bool, |
24 | element: SyntaxElement, | 25 | element: SyntaxElement, |
@@ -46,8 +47,10 @@ pub(super) fn element( | |||
46 | 47 | ||
47 | match name_kind { | 48 | match name_kind { |
48 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), | 49 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), |
49 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | 50 | Some(NameClass::Definition(def)) => { |
50 | Some(NameClass::ConstReference(def)) => highlight_def(db, def), | 51 | highlight_def(db, krate, def) | HlMod::Definition |
52 | } | ||
53 | Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def), | ||
51 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | 54 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { |
52 | let mut h = HlTag::Symbol(SymbolKind::Field).into(); | 55 | let mut h = HlTag::Symbol(SymbolKind::Field).into(); |
53 | if let Definition::Field(field) = field_ref { | 56 | if let Definition::Field(field) = field_ref { |
@@ -68,7 +71,7 @@ pub(super) fn element( | |||
68 | } | 71 | } |
69 | NAME_REF => { | 72 | NAME_REF => { |
70 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | 73 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); |
71 | highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { | 74 | highlight_func_by_name_ref(sema, krate, &name_ref).unwrap_or_else(|| { |
72 | let is_self = name_ref.self_token().is_some(); | 75 | let is_self = name_ref.self_token().is_some(); |
73 | let h = match NameRefClass::classify(sema, &name_ref) { | 76 | let h = match NameRefClass::classify(sema, &name_ref) { |
74 | Some(name_kind) => match name_kind { | 77 | Some(name_kind) => match name_kind { |
@@ -82,7 +85,7 @@ pub(super) fn element( | |||
82 | } | 85 | } |
83 | }; | 86 | }; |
84 | 87 | ||
85 | let mut h = highlight_def(db, def); | 88 | let mut h = highlight_def(db, krate, def); |
86 | 89 | ||
87 | if let Definition::Local(local) = &def { | 90 | if let Definition::Local(local) = &def { |
88 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | 91 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { |
@@ -105,7 +108,7 @@ pub(super) fn element( | |||
105 | NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(), | 108 | NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(), |
106 | }, | 109 | }, |
107 | None if syntactic_name_ref_highlighting => { | 110 | None if syntactic_name_ref_highlighting => { |
108 | highlight_name_ref_by_syntax(name_ref, sema) | 111 | highlight_name_ref_by_syntax(name_ref, sema, krate) |
109 | } | 112 | } |
110 | None => HlTag::UnresolvedReference.into(), | 113 | None => HlTag::UnresolvedReference.into(), |
111 | }; | 114 | }; |
@@ -136,9 +139,11 @@ pub(super) fn element( | |||
136 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); | 139 | let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); |
137 | 140 | ||
138 | match NameClass::classify_lifetime(sema, &lifetime) { | 141 | match NameClass::classify_lifetime(sema, &lifetime) { |
139 | Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, | 142 | Some(NameClass::Definition(def)) => { |
143 | highlight_def(db, krate, def) | HlMod::Definition | ||
144 | } | ||
140 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { | 145 | None => match NameRefClass::classify_lifetime(sema, &lifetime) { |
141 | Some(NameRefClass::Definition(def)) => highlight_def(db, def), | 146 | Some(NameRefClass::Definition(def)) => highlight_def(db, krate, def), |
142 | _ => SymbolKind::LifetimeParam.into(), | 147 | _ => SymbolKind::LifetimeParam.into(), |
143 | }, | 148 | }, |
144 | _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition, | 149 | _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition, |
@@ -277,12 +282,12 @@ pub(super) fn element( | |||
277 | hash((name, shadow_count)) | 282 | hash((name, shadow_count)) |
278 | } | 283 | } |
279 | } | 284 | } |
280 | fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | 285 | fn highlight_def(db: &RootDatabase, krate: Option<hir::Crate>, def: Definition) -> Highlight { |
281 | match def { | 286 | let mut h = match def { |
282 | Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro), | 287 | Definition::Macro(_) => Highlight::new(HlTag::Symbol(SymbolKind::Macro)), |
283 | Definition::Field(_) => HlTag::Symbol(SymbolKind::Field), | 288 | Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)), |
284 | Definition::ModuleDef(def) => match def { | 289 | Definition::ModuleDef(def) => match def { |
285 | hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), | 290 | hir::ModuleDef::Module(_) => Highlight::new(HlTag::Symbol(SymbolKind::Module)), |
286 | hir::ModuleDef::Function(func) => { | 291 | hir::ModuleDef::Function(func) => { |
287 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); | 292 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); |
288 | if let Some(item) = func.as_assoc_item(db) { | 293 | if let Some(item) = func.as_assoc_item(db) { |
@@ -314,14 +319,22 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
314 | if func.is_async(db) { | 319 | if func.is_async(db) { |
315 | h |= HlMod::Async; | 320 | h |= HlMod::Async; |
316 | } | 321 | } |
317 | return h; | 322 | |
323 | h | ||
324 | } | ||
325 | hir::ModuleDef::Adt(adt) => { | ||
326 | let h = match adt { | ||
327 | hir::Adt::Struct(_) => HlTag::Symbol(SymbolKind::Struct), | ||
328 | hir::Adt::Enum(_) => HlTag::Symbol(SymbolKind::Enum), | ||
329 | hir::Adt::Union(_) => HlTag::Symbol(SymbolKind::Union), | ||
330 | }; | ||
331 | |||
332 | Highlight::new(h) | ||
318 | } | 333 | } |
319 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct), | 334 | hir::ModuleDef::Variant(_) => Highlight::new(HlTag::Symbol(SymbolKind::Variant)), |
320 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum), | ||
321 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union), | ||
322 | hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), | ||
323 | hir::ModuleDef::Const(konst) => { | 335 | hir::ModuleDef::Const(konst) => { |
324 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); | 336 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); |
337 | |||
325 | if let Some(item) = konst.as_assoc_item(db) { | 338 | if let Some(item) = konst.as_assoc_item(db) { |
326 | h |= HlMod::Associated; | 339 | h |= HlMod::Associated; |
327 | match item.container(db) { | 340 | match item.container(db) { |
@@ -336,7 +349,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
336 | } | 349 | } |
337 | } | 350 | } |
338 | 351 | ||
339 | return h; | 352 | h |
340 | } | 353 | } |
341 | hir::ModuleDef::Trait(trait_) => { | 354 | hir::ModuleDef::Trait(trait_) => { |
342 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait)); | 355 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait)); |
@@ -344,10 +357,12 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
344 | if trait_.is_unsafe(db) { | 357 | if trait_.is_unsafe(db) { |
345 | h |= HlMod::Unsafe; | 358 | h |= HlMod::Unsafe; |
346 | } | 359 | } |
347 | return h; | 360 | |
361 | h | ||
348 | } | 362 | } |
349 | hir::ModuleDef::TypeAlias(type_) => { | 363 | hir::ModuleDef::TypeAlias(type_) => { |
350 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); | 364 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); |
365 | |||
351 | if let Some(item) = type_.as_assoc_item(db) { | 366 | if let Some(item) = type_.as_assoc_item(db) { |
352 | h |= HlMod::Associated; | 367 | h |= HlMod::Associated; |
353 | match item.container(db) { | 368 | match item.container(db) { |
@@ -361,23 +376,30 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
361 | } | 376 | } |
362 | } | 377 | } |
363 | } | 378 | } |
364 | return h; | 379 | |
380 | h | ||
365 | } | 381 | } |
366 | hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType, | 382 | hir::ModuleDef::BuiltinType(_) => Highlight::new(HlTag::BuiltinType), |
367 | hir::ModuleDef::Static(s) => { | 383 | hir::ModuleDef::Static(s) => { |
368 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); | 384 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); |
385 | |||
369 | if s.is_mut(db) { | 386 | if s.is_mut(db) { |
370 | h |= HlMod::Mutable; | 387 | h |= HlMod::Mutable; |
371 | h |= HlMod::Unsafe; | 388 | h |= HlMod::Unsafe; |
372 | } | 389 | } |
373 | return h; | 390 | |
391 | h | ||
374 | } | 392 | } |
375 | }, | 393 | }, |
376 | Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl), | 394 | Definition::SelfType(_) => Highlight::new(HlTag::Symbol(SymbolKind::Impl)), |
377 | Definition::GenericParam(it) => match it { | 395 | Definition::GenericParam(it) => match it { |
378 | hir::GenericParam::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam), | 396 | hir::GenericParam::TypeParam(_) => Highlight::new(HlTag::Symbol(SymbolKind::TypeParam)), |
379 | hir::GenericParam::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam), | 397 | hir::GenericParam::ConstParam(_) => { |
380 | hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam), | 398 | Highlight::new(HlTag::Symbol(SymbolKind::ConstParam)) |
399 | } | ||
400 | hir::GenericParam::LifetimeParam(_) => { | ||
401 | Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | ||
402 | } | ||
381 | }, | 403 | }, |
382 | Definition::Local(local) => { | 404 | Definition::Local(local) => { |
383 | let tag = if local.is_self(db) { | 405 | let tag = if local.is_self(db) { |
@@ -395,28 +417,40 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
395 | if ty.as_callable(db).is_some() || ty.impls_fnonce(db) { | 417 | if ty.as_callable(db).is_some() || ty.impls_fnonce(db) { |
396 | h |= HlMod::Callable; | 418 | h |= HlMod::Callable; |
397 | } | 419 | } |
398 | return h; | 420 | h |
399 | } | 421 | } |
400 | Definition::Label(_) => HlTag::Symbol(SymbolKind::Label), | 422 | Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)), |
423 | }; | ||
424 | |||
425 | let is_from_other_crate = def.module(db).map(hir::Module::krate) != krate; | ||
426 | let is_builtin_type = matches!(def, Definition::ModuleDef(hir::ModuleDef::BuiltinType(_))); | ||
427 | |||
428 | if is_from_other_crate && !is_builtin_type { | ||
429 | h |= HlMod::Library; | ||
401 | } | 430 | } |
402 | .into() | 431 | |
432 | h | ||
403 | } | 433 | } |
404 | 434 | ||
405 | fn highlight_func_by_name_ref( | 435 | fn highlight_func_by_name_ref( |
406 | sema: &Semantics<RootDatabase>, | 436 | sema: &Semantics<RootDatabase>, |
437 | krate: Option<hir::Crate>, | ||
407 | name_ref: &ast::NameRef, | 438 | name_ref: &ast::NameRef, |
408 | ) -> Option<Highlight> { | 439 | ) -> Option<Highlight> { |
409 | let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; | 440 | let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; |
410 | highlight_method_call(sema, &mc) | 441 | highlight_method_call(sema, krate, &mc) |
411 | } | 442 | } |
412 | 443 | ||
413 | fn highlight_method_call( | 444 | fn highlight_method_call( |
414 | sema: &Semantics<RootDatabase>, | 445 | sema: &Semantics<RootDatabase>, |
446 | krate: Option<hir::Crate>, | ||
415 | method_call: &ast::MethodCallExpr, | 447 | method_call: &ast::MethodCallExpr, |
416 | ) -> Option<Highlight> { | 448 | ) -> Option<Highlight> { |
417 | let func = sema.resolve_method_call(&method_call)?; | 449 | let func = sema.resolve_method_call(&method_call)?; |
450 | |||
418 | let mut h = SymbolKind::Function.into(); | 451 | let mut h = SymbolKind::Function.into(); |
419 | h |= HlMod::Associated; | 452 | h |= HlMod::Associated; |
453 | |||
420 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | 454 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { |
421 | h |= HlMod::Unsafe; | 455 | h |= HlMod::Unsafe; |
422 | } | 456 | } |
@@ -424,7 +458,10 @@ fn highlight_method_call( | |||
424 | h |= HlMod::Async; | 458 | h |= HlMod::Async; |
425 | } | 459 | } |
426 | if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() { | 460 | if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() { |
427 | h |= HlMod::Trait | 461 | h |= HlMod::Trait; |
462 | } | ||
463 | if Some(func.module(sema.db).krate()) != krate { | ||
464 | h |= HlMod::Library; | ||
428 | } | 465 | } |
429 | 466 | ||
430 | if let Some(self_param) = func.self_param(sema.db) { | 467 | if let Some(self_param) = func.self_param(sema.db) { |
@@ -473,7 +510,11 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | |||
473 | tag.into() | 510 | tag.into() |
474 | } | 511 | } |
475 | 512 | ||
476 | fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight { | 513 | fn highlight_name_ref_by_syntax( |
514 | name: ast::NameRef, | ||
515 | sema: &Semantics<RootDatabase>, | ||
516 | krate: Option<hir::Crate>, | ||
517 | ) -> Highlight { | ||
477 | let default = HlTag::UnresolvedReference; | 518 | let default = HlTag::UnresolvedReference; |
478 | 519 | ||
479 | let parent = match name.syntax().parent() { | 520 | let parent = match name.syntax().parent() { |
@@ -484,7 +525,7 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas | |||
484 | match parent.kind() { | 525 | match parent.kind() { |
485 | METHOD_CALL_EXPR => { | 526 | METHOD_CALL_EXPR => { |
486 | return ast::MethodCallExpr::cast(parent) | 527 | return ast::MethodCallExpr::cast(parent) |
487 | .and_then(|it| highlight_method_call(sema, &it)) | 528 | .and_then(|it| highlight_method_call(sema, krate, &it)) |
488 | .unwrap_or_else(|| SymbolKind::Function.into()); | 529 | .unwrap_or_else(|| SymbolKind::Function.into()); |
489 | } | 530 | } |
490 | FIELD_EXPR => { | 531 | FIELD_EXPR => { |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 27473a2f9..9d481deae 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -37,6 +37,8 @@ pub enum HlTag { | |||
37 | None, | 37 | None, |
38 | } | 38 | } |
39 | 39 | ||
40 | // Don't forget to adjust the feature description in crates/ide/src/syntax_highlighting.rs. | ||
41 | // And make sure to use the lsp strings used when converting to the protocol in crates\rust-analyzer\src\semantic_tokens.rs, not the names of the variants here. | ||
40 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 42 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
41 | #[repr(u8)] | 43 | #[repr(u8)] |
42 | pub enum HlMod { | 44 | pub enum HlMod { |
@@ -67,6 +69,8 @@ pub enum HlMod { | |||
67 | Trait, | 69 | Trait, |
68 | /// Used with keywords like `async` and `await`. | 70 | /// Used with keywords like `async` and `await`. |
69 | Async, | 71 | Async, |
72 | /// Used for items from other crates. | ||
73 | Library, | ||
70 | // Keep this last! | 74 | // Keep this last! |
71 | /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations. | 75 | /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations. |
72 | Unsafe, | 76 | Unsafe, |
@@ -189,6 +193,7 @@ impl HlMod { | |||
189 | HlMod::Static, | 193 | HlMod::Static, |
190 | HlMod::Trait, | 194 | HlMod::Trait, |
191 | HlMod::Async, | 195 | HlMod::Async, |
196 | HlMod::Library, | ||
192 | HlMod::Unsafe, | 197 | HlMod::Unsafe, |
193 | ]; | 198 | ]; |
194 | 199 | ||
@@ -207,6 +212,7 @@ impl HlMod { | |||
207 | HlMod::Static => "static", | 212 | HlMod::Static => "static", |
208 | HlMod::Trait => "trait", | 213 | HlMod::Trait => "trait", |
209 | HlMod::Async => "async", | 214 | HlMod::Async => "async", |
215 | HlMod::Library => "library", | ||
210 | HlMod::Unsafe => "unsafe", | 216 | HlMod::Unsafe => "unsafe", |
211 | } | 217 | } |
212 | } | 218 | } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 878431b56..0264e39a3 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -248,4 +248,20 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
248 | <span class="brace">}</span> | 248 | <span class="brace">}</span> |
249 | 249 | ||
250 | <span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">Dangerous</span> <span class="brace">{</span><span class="brace">}</span> | 250 | <span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">Dangerous</span> <span class="brace">{</span><span class="brace">}</span> |
251 | <span class="keyword">impl</span> <span class="trait unsafe">Dangerous</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file | 251 | <span class="keyword">impl</span> <span class="trait unsafe">Dangerous</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> |
252 | |||
253 | <span class="keyword">fn</span> <span class="function declaration">use_foo_items</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
254 | <span class="keyword">let</span> <span class="variable declaration">bob</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="struct library">Person</span> <span class="brace">{</span> | ||
255 | <span class="field library">name</span><span class="colon">:</span> <span class="string_literal">"Bob"</span><span class="comma">,</span> | ||
256 | <span class="field library">age</span><span class="colon">:</span> <span class="module library">foo</span><span class="operator">::</span><span class="module library">consts</span><span class="operator">::</span><span class="constant library">NUMBER</span><span class="comma">,</span> | ||
257 | <span class="brace">}</span><span class="semicolon">;</span> | ||
258 | |||
259 | <span class="keyword">let</span> <span class="variable declaration">control_flow</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="function library">identity</span><span class="parenthesis">(</span><span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Continue</span><span class="parenthesis">)</span><span class="semicolon">;</span> | ||
260 | |||
261 | <span class="keyword control">if</span> <span class="variable">control_flow</span><span class="operator">.</span><span class="function associated consuming library">should_die</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> | ||
262 | foo::<span class="macro">die!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | ||
263 | <span class="brace">}</span> | ||
264 | <span class="brace">}</span> | ||
265 | |||
266 | |||
267 | </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 9ce26e930..662b53481 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -10,6 +10,7 @@ use crate::{fixture, FileRange, HlTag, TextRange}; | |||
10 | fn test_highlighting() { | 10 | fn test_highlighting() { |
11 | check_highlighting( | 11 | check_highlighting( |
12 | r#" | 12 | r#" |
13 | //- /main.rs crate:main deps:foo | ||
13 | use inner::{self as inner_mod}; | 14 | use inner::{self as inner_mod}; |
14 | mod inner {} | 15 | mod inner {} |
15 | 16 | ||
@@ -222,6 +223,49 @@ async fn async_main() { | |||
222 | 223 | ||
223 | unsafe trait Dangerous {} | 224 | unsafe trait Dangerous {} |
224 | impl Dangerous for () {} | 225 | impl Dangerous for () {} |
226 | |||
227 | fn use_foo_items() { | ||
228 | let bob = foo::Person { | ||
229 | name: "Bob", | ||
230 | age: foo::consts::NUMBER, | ||
231 | }; | ||
232 | |||
233 | let control_flow = foo::identity(foo::ControlFlow::Continue); | ||
234 | |||
235 | if control_flow.should_die() { | ||
236 | foo::die!(); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | |||
241 | //- /foo.rs crate:foo | ||
242 | pub struct Person { | ||
243 | pub name: &'static str, | ||
244 | pub age: u8, | ||
245 | } | ||
246 | |||
247 | pub enum ControlFlow { | ||
248 | Continue, | ||
249 | Die, | ||
250 | } | ||
251 | |||
252 | impl ControlFlow { | ||
253 | pub fn should_die(self) -> bool { | ||
254 | matches!(self, ControlFlow::Die) | ||
255 | } | ||
256 | } | ||
257 | |||
258 | pub fn identity<T>(x: T) -> T { x } | ||
259 | |||
260 | pub mod consts { | ||
261 | pub const NUMBER: i64 = 92; | ||
262 | } | ||
263 | |||
264 | macro_rules! die { | ||
265 | () => { | ||
266 | panic!(); | ||
267 | }; | ||
268 | } | ||
225 | "# | 269 | "# |
226 | .trim(), | 270 | .trim(), |
227 | expect_file!["./test_data/highlighting.html"], | 271 | expect_file!["./test_data/highlighting.html"], |