diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ide/src/display/short_label.rs | 6 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 62 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 10 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 55 | ||||
-rw-r--r-- | crates/ide/src/ssr.rs | 259 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/highlight.rs | 5 |
7 files changed, 363 insertions, 36 deletions
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index f7c5efaf3..107bd8432 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -27,7 +27,6 @@ text_edit = { path = "../text_edit", version = "0.0.0" } | |||
27 | ide_db = { path = "../ide_db", version = "0.0.0" } | 27 | ide_db = { path = "../ide_db", version = "0.0.0" } |
28 | cfg = { path = "../cfg", version = "0.0.0" } | 28 | cfg = { path = "../cfg", version = "0.0.0" } |
29 | profile = { path = "../profile", version = "0.0.0" } | 29 | profile = { path = "../profile", version = "0.0.0" } |
30 | test_utils = { path = "../test_utils", version = "0.0.0" } | ||
31 | ide_assists = { path = "../ide_assists", version = "0.0.0" } | 30 | ide_assists = { path = "../ide_assists", version = "0.0.0" } |
32 | ide_ssr = { path = "../ide_ssr", version = "0.0.0" } | 31 | ide_ssr = { path = "../ide_ssr", version = "0.0.0" } |
33 | ide_completion = { path = "../ide_completion", version = "0.0.0" } | 32 | ide_completion = { path = "../ide_completion", version = "0.0.0" } |
@@ -37,4 +36,5 @@ ide_completion = { path = "../ide_completion", version = "0.0.0" } | |||
37 | hir = { path = "../hir", version = "0.0.0" } | 36 | hir = { path = "../hir", version = "0.0.0" } |
38 | 37 | ||
39 | [dev-dependencies] | 38 | [dev-dependencies] |
39 | test_utils = { path = "../test_utils" } | ||
40 | expect-test = "1.1" | 40 | expect-test = "1.1" |
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs index 84b8883de..2df9266b4 100644 --- a/crates/ide/src/display/short_label.rs +++ b/crates/ide/src/display/short_label.rs | |||
@@ -71,11 +71,7 @@ impl ShortLabel for ast::TypeAlias { | |||
71 | 71 | ||
72 | impl ShortLabel for ast::Const { | 72 | impl ShortLabel for ast::Const { |
73 | fn short_label(&self) -> Option<String> { | 73 | fn short_label(&self) -> Option<String> { |
74 | let mut new_buf = short_label_from_ty(self, self.ty(), "const ")?; | 74 | short_label_from_ty(self, self.ty(), "const ") |
75 | if let Some(expr) = self.body() { | ||
76 | format_to!(new_buf, " = {}", expr.syntax()); | ||
77 | } | ||
78 | Some(new_buf) | ||
79 | } | 75 | } |
80 | } | 76 | } |
81 | 77 | ||
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 5d1cc2052..ea45086ce 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use either::Either; | ||
1 | use hir::{ | 2 | use hir::{ |
2 | Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource, | 3 | Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource, |
3 | HirDisplay, Module, ModuleDef, ModuleSource, Semantics, | 4 | HirDisplay, Module, ModuleDef, ModuleSource, Semantics, |
@@ -366,7 +367,7 @@ fn hover_for_definition( | |||
366 | .and_then(|fd| hover_for_builtin(fd, it)) | 367 | .and_then(|fd| hover_for_builtin(fd, it)) |
367 | .or_else(|| Some(Markup::fenced_block(&it.name()))), | 368 | .or_else(|| Some(Markup::fenced_block(&it.name()))), |
368 | }, | 369 | }, |
369 | Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))), | 370 | Definition::Local(it) => hover_for_local(it, db), |
370 | Definition::SelfType(impl_def) => { | 371 | Definition::SelfType(impl_def) => { |
371 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { | 372 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { |
372 | Adt::Struct(it) => from_def_source(db, it, mod_path), | 373 | Adt::Struct(it) => from_def_source(db, it, mod_path), |
@@ -405,6 +406,29 @@ fn hover_for_definition( | |||
405 | } | 406 | } |
406 | } | 407 | } |
407 | 408 | ||
409 | fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> { | ||
410 | let ty = it.ty(db); | ||
411 | let ty = ty.display(db); | ||
412 | let is_mut = if it.is_mut(db) { "mut " } else { "" }; | ||
413 | let desc = match it.source(db).value { | ||
414 | Either::Left(ident) => { | ||
415 | let name = it.name(db).unwrap(); | ||
416 | let let_kw = if ident | ||
417 | .syntax() | ||
418 | .parent() | ||
419 | .map_or(false, |p| p.kind() == LET_STMT || p.kind() == CONDITION) | ||
420 | { | ||
421 | "let " | ||
422 | } else { | ||
423 | "" | ||
424 | }; | ||
425 | format!("{}{}{}: {}", let_kw, is_mut, name, ty) | ||
426 | } | ||
427 | Either::Right(_) => format!("{}self: {}", is_mut, ty), | ||
428 | }; | ||
429 | hover_markup(None, Some(desc), None) | ||
430 | } | ||
431 | |||
408 | fn hover_for_keyword( | 432 | fn hover_for_keyword( |
409 | sema: &Semantics<RootDatabase>, | 433 | sema: &Semantics<RootDatabase>, |
410 | links_in_hover: bool, | 434 | links_in_hover: bool, |
@@ -574,7 +598,7 @@ fn main() { | |||
574 | *iter* | 598 | *iter* |
575 | 599 | ||
576 | ```rust | 600 | ```rust |
577 | Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>> | 601 | let mut iter: Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>> |
578 | ``` | 602 | ``` |
579 | "#]], | 603 | "#]], |
580 | ); | 604 | ); |
@@ -798,7 +822,7 @@ fn main() { | |||
798 | ``` | 822 | ``` |
799 | 823 | ||
800 | ```rust | 824 | ```rust |
801 | const foo: u32 = 123 | 825 | const foo: u32 |
802 | ``` | 826 | ``` |
803 | "#]], | 827 | "#]], |
804 | ); | 828 | ); |
@@ -831,7 +855,7 @@ fn main() { | |||
831 | *zz* | 855 | *zz* |
832 | 856 | ||
833 | ```rust | 857 | ```rust |
834 | Test<i32, u8> | 858 | let zz: Test<i32, u8> |
835 | ``` | 859 | ``` |
836 | "#]], | 860 | "#]], |
837 | ); | 861 | ); |
@@ -870,7 +894,7 @@ fn main() { let b$0ar = Some(12); } | |||
870 | *bar* | 894 | *bar* |
871 | 895 | ||
872 | ```rust | 896 | ```rust |
873 | Option<i32> | 897 | let bar: Option<i32> |
874 | ``` | 898 | ``` |
875 | "#]], | 899 | "#]], |
876 | ); | 900 | ); |
@@ -938,7 +962,7 @@ fn main() { | |||
938 | *foo* | 962 | *foo* |
939 | 963 | ||
940 | ```rust | 964 | ```rust |
941 | i32 | 965 | foo: i32 |
942 | ``` | 966 | ``` |
943 | "#]], | 967 | "#]], |
944 | ) | 968 | ) |
@@ -952,7 +976,7 @@ fn main() { | |||
952 | *foo* | 976 | *foo* |
953 | 977 | ||
954 | ```rust | 978 | ```rust |
955 | i32 | 979 | foo: i32 |
956 | ``` | 980 | ``` |
957 | "#]], | 981 | "#]], |
958 | ) | 982 | ) |
@@ -966,7 +990,7 @@ fn main() { | |||
966 | *foo* | 990 | *foo* |
967 | 991 | ||
968 | ```rust | 992 | ```rust |
969 | i32 | 993 | foo: i32 |
970 | ``` | 994 | ``` |
971 | "#]], | 995 | "#]], |
972 | ) | 996 | ) |
@@ -980,7 +1004,7 @@ fn main() { | |||
980 | *foo* | 1004 | *foo* |
981 | 1005 | ||
982 | ```rust | 1006 | ```rust |
983 | i32 | 1007 | foo: i32 |
984 | ``` | 1008 | ``` |
985 | "#]], | 1009 | "#]], |
986 | ) | 1010 | ) |
@@ -1000,7 +1024,7 @@ fn main() { | |||
1000 | *_x* | 1024 | *_x* |
1001 | 1025 | ||
1002 | ```rust | 1026 | ```rust |
1003 | impl Deref<Target = u8> + DerefMut<Target = u8> | 1027 | _x: impl Deref<Target = u8> + DerefMut<Target = u8> |
1004 | ``` | 1028 | ``` |
1005 | "#]], | 1029 | "#]], |
1006 | ) | 1030 | ) |
@@ -1022,7 +1046,7 @@ fn main() { let foo_$0test = Thing::new(); } | |||
1022 | *foo_test* | 1046 | *foo_test* |
1023 | 1047 | ||
1024 | ```rust | 1048 | ```rust |
1025 | Thing | 1049 | let foo_test: Thing |
1026 | ``` | 1050 | ``` |
1027 | "#]], | 1051 | "#]], |
1028 | ) | 1052 | ) |
@@ -1081,7 +1105,7 @@ fn main() { | |||
1081 | ``` | 1105 | ``` |
1082 | 1106 | ||
1083 | ```rust | 1107 | ```rust |
1084 | const C: u32 = 1 | 1108 | const C: u32 |
1085 | ``` | 1109 | ``` |
1086 | "#]], | 1110 | "#]], |
1087 | ) | 1111 | ) |
@@ -1182,7 +1206,7 @@ fn y() { | |||
1182 | *x* | 1206 | *x* |
1183 | 1207 | ||
1184 | ```rust | 1208 | ```rust |
1185 | i32 | 1209 | let x: i32 |
1186 | ``` | 1210 | ``` |
1187 | "#]], | 1211 | "#]], |
1188 | ) | 1212 | ) |
@@ -1259,7 +1283,7 @@ fn foo(bar:u32) { let a = id!(ba$0r); } | |||
1259 | *bar* | 1283 | *bar* |
1260 | 1284 | ||
1261 | ```rust | 1285 | ```rust |
1262 | u32 | 1286 | bar: u32 |
1263 | ``` | 1287 | ``` |
1264 | "#]], | 1288 | "#]], |
1265 | ); | 1289 | ); |
@@ -1277,7 +1301,7 @@ fn foo(bar:u32) { let a = id!(ba$0r); } | |||
1277 | *bar* | 1301 | *bar* |
1278 | 1302 | ||
1279 | ```rust | 1303 | ```rust |
1280 | u32 | 1304 | bar: u32 |
1281 | ``` | 1305 | ``` |
1282 | "#]], | 1306 | "#]], |
1283 | ); | 1307 | ); |
@@ -3302,7 +3326,7 @@ fn main() { | |||
3302 | *f* | 3326 | *f* |
3303 | 3327 | ||
3304 | ```rust | 3328 | ```rust |
3305 | &i32 | 3329 | f: &i32 |
3306 | ``` | 3330 | ``` |
3307 | "#]], | 3331 | "#]], |
3308 | ); | 3332 | ); |
@@ -3321,7 +3345,7 @@ impl Foo { | |||
3321 | *self* | 3345 | *self* |
3322 | 3346 | ||
3323 | ```rust | 3347 | ```rust |
3324 | &Foo | 3348 | self: &Foo |
3325 | ``` | 3349 | ``` |
3326 | "#]], | 3350 | "#]], |
3327 | ); | 3351 | ); |
@@ -3341,7 +3365,7 @@ impl Foo { | |||
3341 | *self* | 3365 | *self* |
3342 | 3366 | ||
3343 | ```rust | 3367 | ```rust |
3344 | Arc<Foo> | 3368 | self: Arc<Foo> |
3345 | ``` | 3369 | ``` |
3346 | "#]], | 3370 | "#]], |
3347 | ); | 3371 | ); |
@@ -3537,7 +3561,7 @@ fn foo() { | |||
3537 | ``` | 3561 | ``` |
3538 | 3562 | ||
3539 | ```rust | 3563 | ```rust |
3540 | const FOO: usize = 3 | 3564 | const FOO: usize |
3541 | ``` | 3565 | ``` |
3542 | 3566 | ||
3543 | --- | 3567 | --- |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index f83ed65d5..0a493d2f3 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -41,6 +41,7 @@ mod parent_module; | |||
41 | mod references; | 41 | mod references; |
42 | mod fn_references; | 42 | mod fn_references; |
43 | mod runnables; | 43 | mod runnables; |
44 | mod ssr; | ||
44 | mod status; | 45 | mod status; |
45 | mod syntax_highlighting; | 46 | mod syntax_highlighting; |
46 | mod syntax_tree; | 47 | mod syntax_tree; |
@@ -51,6 +52,7 @@ mod doc_links; | |||
51 | use std::sync::Arc; | 52 | use std::sync::Arc; |
52 | 53 | ||
53 | use cfg::CfgOptions; | 54 | use cfg::CfgOptions; |
55 | |||
54 | use ide_db::base_db::{ | 56 | use ide_db::base_db::{ |
55 | salsa::{self, ParallelDatabase}, | 57 | salsa::{self, ParallelDatabase}, |
56 | CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath, | 58 | CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath, |
@@ -85,7 +87,7 @@ pub use crate::{ | |||
85 | pub use hir::{Documentation, Semantics}; | 87 | pub use hir::{Documentation, Semantics}; |
86 | pub use ide_assists::{Assist, AssistConfig, AssistId, AssistKind}; | 88 | pub use ide_assists::{Assist, AssistConfig, AssistId, AssistKind}; |
87 | pub use ide_completion::{ | 89 | pub use ide_completion::{ |
88 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, | 90 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit, |
89 | InsertTextFormat, | 91 | InsertTextFormat, |
90 | }; | 92 | }; |
91 | pub use ide_db::{ | 93 | pub use ide_db::{ |
@@ -502,7 +504,11 @@ impl Analysis { | |||
502 | resolve: bool, | 504 | resolve: bool, |
503 | frange: FileRange, | 505 | frange: FileRange, |
504 | ) -> Cancelable<Vec<Assist>> { | 506 | ) -> Cancelable<Vec<Assist>> { |
505 | self.with_db(|db| Assist::get(db, config, resolve, frange)) | 507 | self.with_db(|db| { |
508 | let mut acc = Assist::get(db, config, resolve, frange); | ||
509 | ssr::add_ssr_assist(db, &mut acc, resolve, frange); | ||
510 | acc | ||
511 | }) | ||
506 | } | 512 | } |
507 | 513 | ||
508 | /// Computes the set of diagnostics for the given file. | 514 | /// Computes the set of diagnostics for the given file. |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 05c73de88..1e378279d 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -21,7 +21,7 @@ use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceCh | |||
21 | 21 | ||
22 | type RenameResult<T> = Result<T, RenameError>; | 22 | type RenameResult<T> = Result<T, RenameError>; |
23 | #[derive(Debug)] | 23 | #[derive(Debug)] |
24 | pub struct RenameError(pub(crate) String); | 24 | pub struct RenameError(String); |
25 | 25 | ||
26 | impl fmt::Display for RenameError { | 26 | impl fmt::Display for RenameError { |
27 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 27 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
@@ -47,16 +47,15 @@ pub(crate) fn prepare_rename( | |||
47 | let sema = Semantics::new(db); | 47 | let sema = Semantics::new(db); |
48 | let source_file = sema.parse(position.file_id); | 48 | let source_file = sema.parse(position.file_id); |
49 | let syntax = source_file.syntax(); | 49 | let syntax = source_file.syntax(); |
50 | let range = match &sema | 50 | let name_like = sema |
51 | .find_node_at_offset_with_descend(&syntax, position.offset) | 51 | .find_node_at_offset_with_descend(&syntax, position.offset) |
52 | .ok_or_else(|| format_err!("No references found at position"))? | 52 | .ok_or_else(|| format_err!("No references found at position"))?; |
53 | { | 53 | let node = match &name_like { |
54 | ast::NameLike::Name(it) => it.syntax(), | 54 | ast::NameLike::Name(it) => it.syntax(), |
55 | ast::NameLike::NameRef(it) => it.syntax(), | 55 | ast::NameLike::NameRef(it) => it.syntax(), |
56 | ast::NameLike::Lifetime(it) => it.syntax(), | 56 | ast::NameLike::Lifetime(it) => it.syntax(), |
57 | } | 57 | }; |
58 | .text_range(); | 58 | Ok(RangeInfo::new(sema.original_range(node).range, ())) |
59 | Ok(RangeInfo::new(range, ())) | ||
60 | } | 59 | } |
61 | 60 | ||
62 | // Feature: Rename | 61 | // Feature: Rename |
@@ -94,6 +93,7 @@ pub(crate) fn rename_with_semantics( | |||
94 | } | 93 | } |
95 | } | 94 | } |
96 | 95 | ||
96 | /// Called by the client when it is about to rename a file. | ||
97 | pub(crate) fn will_rename_file( | 97 | pub(crate) fn will_rename_file( |
98 | db: &RootDatabase, | 98 | db: &RootDatabase, |
99 | file_id: FileId, | 99 | file_id: FileId, |
@@ -545,6 +545,8 @@ mod tests { | |||
545 | 545 | ||
546 | use crate::{fixture, FileId}; | 546 | use crate::{fixture, FileId}; |
547 | 547 | ||
548 | use super::{RangeInfo, RenameError}; | ||
549 | |||
548 | fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 550 | fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
549 | let ra_fixture_after = &trim_indent(ra_fixture_after); | 551 | let ra_fixture_after = &trim_indent(ra_fixture_after); |
550 | let (analysis, position) = fixture::position(ra_fixture_before); | 552 | let (analysis, position) = fixture::position(ra_fixture_before); |
@@ -590,6 +592,45 @@ mod tests { | |||
590 | expect.assert_debug_eq(&source_change) | 592 | expect.assert_debug_eq(&source_change) |
591 | } | 593 | } |
592 | 594 | ||
595 | fn check_prepare(ra_fixture: &str, expect: Expect) { | ||
596 | let (analysis, position) = fixture::position(ra_fixture); | ||
597 | let result = analysis | ||
598 | .prepare_rename(position) | ||
599 | .unwrap_or_else(|err| panic!("PrepareRename was cancelled: {}", err)); | ||
600 | match result { | ||
601 | Ok(RangeInfo { range, info: () }) => { | ||
602 | let source = analysis.file_text(position.file_id).unwrap(); | ||
603 | expect.assert_eq(&format!("{:?}: {}", range, &source[range])) | ||
604 | } | ||
605 | Err(RenameError(err)) => expect.assert_eq(&err), | ||
606 | }; | ||
607 | } | ||
608 | |||
609 | #[test] | ||
610 | fn test_prepare_rename_namelikes() { | ||
611 | check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]); | ||
612 | check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]); | ||
613 | check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]); | ||
614 | } | ||
615 | |||
616 | #[test] | ||
617 | fn test_prepare_rename_in_macro() { | ||
618 | check_prepare( | ||
619 | r"macro_rules! foo { | ||
620 | ($ident:ident) => { | ||
621 | pub struct $ident; | ||
622 | } | ||
623 | } | ||
624 | foo!(Foo$0);", | ||
625 | expect![[r#"83..86: Foo"#]], | ||
626 | ); | ||
627 | } | ||
628 | |||
629 | #[test] | ||
630 | fn test_prepare_rename_keyword() { | ||
631 | check_prepare(r"struct$0 Foo;", expect![[r#"No references found at position"#]]); | ||
632 | } | ||
633 | |||
593 | #[test] | 634 | #[test] |
594 | fn test_rename_to_underscore() { | 635 | fn test_rename_to_underscore() { |
595 | check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); | 636 | check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); |
diff --git a/crates/ide/src/ssr.rs b/crates/ide/src/ssr.rs new file mode 100644 index 000000000..f3638d928 --- /dev/null +++ b/crates/ide/src/ssr.rs | |||
@@ -0,0 +1,259 @@ | |||
1 | //! This module provides an SSR assist. It is not desirable to include this | ||
2 | //! assist in ide_assists because that would require the ide_assists crate | ||
3 | //! depend on the ide_ssr crate. | ||
4 | |||
5 | use ide_assists::{Assist, AssistId, AssistKind, GroupLabel}; | ||
6 | use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase}; | ||
7 | |||
8 | pub(crate) fn add_ssr_assist( | ||
9 | db: &RootDatabase, | ||
10 | base: &mut Vec<Assist>, | ||
11 | resolve: bool, | ||
12 | frange: FileRange, | ||
13 | ) -> Option<()> { | ||
14 | let (match_finder, comment_range) = ide_ssr::ssr_from_comment(db, frange)?; | ||
15 | |||
16 | let (source_change_for_file, source_change_for_workspace) = if resolve { | ||
17 | let edits = match_finder.edits(); | ||
18 | |||
19 | let source_change_for_file = { | ||
20 | let text_edit_for_file = edits.get(&frange.file_id).cloned().unwrap_or_default(); | ||
21 | SourceChange::from_text_edit(frange.file_id, text_edit_for_file) | ||
22 | }; | ||
23 | |||
24 | let source_change_for_workspace = SourceChange::from(match_finder.edits()); | ||
25 | |||
26 | (Some(source_change_for_file), Some(source_change_for_workspace)) | ||
27 | } else { | ||
28 | (None, None) | ||
29 | }; | ||
30 | |||
31 | let assists = vec![ | ||
32 | ("Apply SSR in file", source_change_for_file), | ||
33 | ("Apply SSR in workspace", source_change_for_workspace), | ||
34 | ]; | ||
35 | |||
36 | for (label, source_change) in assists.into_iter() { | ||
37 | let assist = Assist { | ||
38 | id: AssistId("ssr", AssistKind::RefactorRewrite), | ||
39 | label: Label::new(label), | ||
40 | group: Some(GroupLabel("Apply SSR".into())), | ||
41 | target: comment_range, | ||
42 | source_change, | ||
43 | }; | ||
44 | |||
45 | base.push(assist); | ||
46 | } | ||
47 | Some(()) | ||
48 | } | ||
49 | |||
50 | #[cfg(test)] | ||
51 | mod tests { | ||
52 | use std::sync::Arc; | ||
53 | |||
54 | use expect_test::expect; | ||
55 | use ide_assists::Assist; | ||
56 | use ide_db::{ | ||
57 | base_db::{fixture::WithFixture, salsa::Durability, FileRange}, | ||
58 | symbol_index::SymbolsDatabase, | ||
59 | RootDatabase, | ||
60 | }; | ||
61 | use rustc_hash::FxHashSet; | ||
62 | |||
63 | use super::add_ssr_assist; | ||
64 | |||
65 | fn get_assists(ra_fixture: &str, resolve: bool) -> Vec<Assist> { | ||
66 | let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture); | ||
67 | let mut local_roots = FxHashSet::default(); | ||
68 | local_roots.insert(ide_db::base_db::fixture::WORKSPACE); | ||
69 | db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); | ||
70 | |||
71 | let mut assists = vec![]; | ||
72 | |||
73 | add_ssr_assist( | ||
74 | &db, | ||
75 | &mut assists, | ||
76 | resolve, | ||
77 | FileRange { file_id, range: range_or_offset.into() }, | ||
78 | ); | ||
79 | |||
80 | assists | ||
81 | } | ||
82 | |||
83 | #[test] | ||
84 | fn not_applicable_comment_not_ssr() { | ||
85 | let ra_fixture = r#" | ||
86 | //- /lib.rs | ||
87 | |||
88 | // This is foo $0 | ||
89 | fn foo() {} | ||
90 | "#; | ||
91 | let resolve = true; | ||
92 | |||
93 | let assists = get_assists(ra_fixture, resolve); | ||
94 | |||
95 | assert_eq!(0, assists.len()); | ||
96 | } | ||
97 | |||
98 | #[test] | ||
99 | fn resolve_edits_true() { | ||
100 | let resolve = true; | ||
101 | let assists = get_assists( | ||
102 | r#" | ||
103 | //- /lib.rs | ||
104 | mod bar; | ||
105 | |||
106 | // 2 ==>> 3$0 | ||
107 | fn foo() { 2 } | ||
108 | |||
109 | //- /bar.rs | ||
110 | fn bar() { 2 } | ||
111 | "#, | ||
112 | resolve, | ||
113 | ); | ||
114 | |||
115 | assert_eq!(2, assists.len()); | ||
116 | let mut assists = assists.into_iter(); | ||
117 | |||
118 | let apply_in_file_assist = assists.next().unwrap(); | ||
119 | expect![[r#" | ||
120 | Assist { | ||
121 | id: AssistId( | ||
122 | "ssr", | ||
123 | RefactorRewrite, | ||
124 | ), | ||
125 | label: "Apply SSR in file", | ||
126 | group: Some( | ||
127 | GroupLabel( | ||
128 | "Apply SSR", | ||
129 | ), | ||
130 | ), | ||
131 | target: 10..21, | ||
132 | source_change: Some( | ||
133 | SourceChange { | ||
134 | source_file_edits: { | ||
135 | FileId( | ||
136 | 0, | ||
137 | ): TextEdit { | ||
138 | indels: [ | ||
139 | Indel { | ||
140 | insert: "3", | ||
141 | delete: 33..34, | ||
142 | }, | ||
143 | ], | ||
144 | }, | ||
145 | }, | ||
146 | file_system_edits: [], | ||
147 | is_snippet: false, | ||
148 | }, | ||
149 | ), | ||
150 | } | ||
151 | "#]] | ||
152 | .assert_debug_eq(&apply_in_file_assist); | ||
153 | |||
154 | let apply_in_workspace_assist = assists.next().unwrap(); | ||
155 | expect![[r#" | ||
156 | Assist { | ||
157 | id: AssistId( | ||
158 | "ssr", | ||
159 | RefactorRewrite, | ||
160 | ), | ||
161 | label: "Apply SSR in workspace", | ||
162 | group: Some( | ||
163 | GroupLabel( | ||
164 | "Apply SSR", | ||
165 | ), | ||
166 | ), | ||
167 | target: 10..21, | ||
168 | source_change: Some( | ||
169 | SourceChange { | ||
170 | source_file_edits: { | ||
171 | FileId( | ||
172 | 0, | ||
173 | ): TextEdit { | ||
174 | indels: [ | ||
175 | Indel { | ||
176 | insert: "3", | ||
177 | delete: 33..34, | ||
178 | }, | ||
179 | ], | ||
180 | }, | ||
181 | FileId( | ||
182 | 1, | ||
183 | ): TextEdit { | ||
184 | indels: [ | ||
185 | Indel { | ||
186 | insert: "3", | ||
187 | delete: 11..12, | ||
188 | }, | ||
189 | ], | ||
190 | }, | ||
191 | }, | ||
192 | file_system_edits: [], | ||
193 | is_snippet: false, | ||
194 | }, | ||
195 | ), | ||
196 | } | ||
197 | "#]] | ||
198 | .assert_debug_eq(&apply_in_workspace_assist); | ||
199 | } | ||
200 | |||
201 | #[test] | ||
202 | fn resolve_edits_false() { | ||
203 | let resolve = false; | ||
204 | let assists = get_assists( | ||
205 | r#" | ||
206 | //- /lib.rs | ||
207 | mod bar; | ||
208 | |||
209 | // 2 ==>> 3$0 | ||
210 | fn foo() { 2 } | ||
211 | |||
212 | //- /bar.rs | ||
213 | fn bar() { 2 } | ||
214 | "#, | ||
215 | resolve, | ||
216 | ); | ||
217 | |||
218 | assert_eq!(2, assists.len()); | ||
219 | let mut assists = assists.into_iter(); | ||
220 | |||
221 | let apply_in_file_assist = assists.next().unwrap(); | ||
222 | expect![[r#" | ||
223 | Assist { | ||
224 | id: AssistId( | ||
225 | "ssr", | ||
226 | RefactorRewrite, | ||
227 | ), | ||
228 | label: "Apply SSR in file", | ||
229 | group: Some( | ||
230 | GroupLabel( | ||
231 | "Apply SSR", | ||
232 | ), | ||
233 | ), | ||
234 | target: 10..21, | ||
235 | source_change: None, | ||
236 | } | ||
237 | "#]] | ||
238 | .assert_debug_eq(&apply_in_file_assist); | ||
239 | |||
240 | let apply_in_workspace_assist = assists.next().unwrap(); | ||
241 | expect![[r#" | ||
242 | Assist { | ||
243 | id: AssistId( | ||
244 | "ssr", | ||
245 | RefactorRewrite, | ||
246 | ), | ||
247 | label: "Apply SSR in workspace", | ||
248 | group: Some( | ||
249 | GroupLabel( | ||
250 | "Apply SSR", | ||
251 | ), | ||
252 | ), | ||
253 | target: 10..21, | ||
254 | source_change: None, | ||
255 | } | ||
256 | "#]] | ||
257 | .assert_debug_eq(&apply_in_workspace_assist); | ||
258 | } | ||
259 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 24fcbb584..b0cfdd8b7 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -330,10 +330,11 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
330 | HlTag::Symbol(SymbolKind::Local) | 330 | HlTag::Symbol(SymbolKind::Local) |
331 | }; | 331 | }; |
332 | let mut h = Highlight::new(tag); | 332 | let mut h = Highlight::new(tag); |
333 | if local.is_mut(db) || local.ty(db).is_mutable_reference() { | 333 | let ty = local.ty(db); |
334 | if local.is_mut(db) || ty.is_mutable_reference() { | ||
334 | h |= HlMod::Mutable; | 335 | h |= HlMod::Mutable; |
335 | } | 336 | } |
336 | if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) { | 337 | if ty.as_callable(db).is_some() || ty.impls_fnonce(db) { |
337 | h |= HlMod::Callable; | 338 | h |= HlMod::Callable; |
338 | } | 339 | } |
339 | return h; | 340 | return h; |