diff options
-rw-r--r-- | crates/ra_assists/src/handlers/change_visibility.rs | 40 | ||||
-rw-r--r-- | crates/ra_assists/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 44 |
3 files changed, 55 insertions, 30 deletions
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 54e0a6c84..cd6d1ee6c 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -2,13 +2,14 @@ use ra_syntax::{ | |||
2 | ast::{self, NameOwner, VisibilityOwner}, | 2 | ast::{self, NameOwner, VisibilityOwner}, |
3 | AstNode, | 3 | AstNode, |
4 | SyntaxKind::{ | 4 | SyntaxKind::{ |
5 | ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, IDENT, MODULE, STRUCT_DEF, TRAIT_DEF, | 5 | ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, |
6 | VISIBILITY, WHITESPACE, | 6 | WHITESPACE, |
7 | }, | 7 | }, |
8 | SyntaxNode, TextUnit, T, | 8 | SyntaxNode, TextUnit, T, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{Assist, AssistCtx, AssistId}; | 11 | use crate::{Assist, AssistCtx, AssistId}; |
12 | use test_utils::tested_by; | ||
12 | 13 | ||
13 | // Assist: change_visibility | 14 | // Assist: change_visibility |
14 | // | 15 | // |
@@ -47,13 +48,16 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> { | |||
47 | } | 48 | } |
48 | (vis_offset(&parent), keyword.text_range()) | 49 | (vis_offset(&parent), keyword.text_range()) |
49 | } else { | 50 | } else { |
50 | let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?; | 51 | let field_name: ast::Name = ctx.find_node_at_offset()?; |
51 | let field = ident.parent().ancestors().find_map(ast::RecordFieldDef::cast)?; | 52 | let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; |
52 | if field.name()?.syntax().text_range() != ident.text_range() && field.visibility().is_some() | 53 | if field.name()? != field_name { |
53 | { | 54 | tested_by!(change_visibility_field_false_positive); |
54 | return None; | 55 | return None; |
55 | } | 56 | } |
56 | (vis_offset(field.syntax()), ident.text_range()) | 57 | if field.visibility().is_some() { |
58 | return None; | ||
59 | } | ||
60 | (vis_offset(field.syntax()), field_name.syntax().text_range()) | ||
57 | }; | 61 | }; |
58 | 62 | ||
59 | ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| { | 63 | ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| { |
@@ -98,8 +102,11 @@ fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { | |||
98 | 102 | ||
99 | #[cfg(test)] | 103 | #[cfg(test)] |
100 | mod tests { | 104 | mod tests { |
105 | use test_utils::covers; | ||
106 | |||
107 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
108 | |||
101 | use super::*; | 109 | use super::*; |
102 | use crate::helpers::{check_assist, check_assist_target}; | ||
103 | 110 | ||
104 | #[test] | 111 | #[test] |
105 | fn change_visibility_adds_pub_crate_to_items() { | 112 | fn change_visibility_adds_pub_crate_to_items() { |
@@ -120,8 +127,17 @@ mod tests { | |||
120 | fn change_visibility_works_with_struct_fields() { | 127 | fn change_visibility_works_with_struct_fields() { |
121 | check_assist( | 128 | check_assist( |
122 | change_visibility, | 129 | change_visibility, |
123 | "struct S { <|>field: u32 }", | 130 | r"struct S { <|>field: u32 }", |
124 | "struct S { <|>pub(crate) field: u32 }", | 131 | r"struct S { <|>pub(crate) field: u32 }", |
132 | ) | ||
133 | } | ||
134 | |||
135 | #[test] | ||
136 | fn change_visibility_field_false_positive() { | ||
137 | covers!(change_visibility_field_false_positive); | ||
138 | check_assist_not_applicable( | ||
139 | change_visibility, | ||
140 | r"struct S { field: [(); { let <|>x = ();}] }", | ||
125 | ) | 141 | ) |
126 | } | 142 | } |
127 | 143 | ||
@@ -144,7 +160,7 @@ mod tests { | |||
144 | fn change_visibility_handles_comment_attrs() { | 160 | fn change_visibility_handles_comment_attrs() { |
145 | check_assist( | 161 | check_assist( |
146 | change_visibility, | 162 | change_visibility, |
147 | " | 163 | r" |
148 | /// docs | 164 | /// docs |
149 | 165 | ||
150 | // comments | 166 | // comments |
@@ -152,7 +168,7 @@ mod tests { | |||
152 | #[derive(Debug)] | 168 | #[derive(Debug)] |
153 | <|>struct Foo; | 169 | <|>struct Foo; |
154 | ", | 170 | ", |
155 | " | 171 | r" |
156 | /// docs | 172 | /// docs |
157 | 173 | ||
158 | // comments | 174 | // comments |
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs index 22404ee80..6c2a2b8b6 100644 --- a/crates/ra_assists/src/marks.rs +++ b/crates/ra_assists/src/marks.rs | |||
@@ -7,4 +7,5 @@ test_utils::marks![ | |||
7 | not_applicable_outside_of_bind_pat | 7 | not_applicable_outside_of_bind_pat |
8 | test_not_inline_mut_variable | 8 | test_not_inline_mut_variable |
9 | test_not_applicable_if_variable_unused | 9 | test_not_applicable_if_variable_unused |
10 | change_visibility_field_false_positive | ||
10 | ]; | 11 | ]; |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 1cc2f6571..1033d6de9 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -734,19 +734,29 @@ pub fn handle_code_action( | |||
734 | res.push(fix.action.clone()); | 734 | res.push(fix.action.clone()); |
735 | } | 735 | } |
736 | 736 | ||
737 | let mut grouped_assists: FxHashMap<String, Vec<Assist>> = FxHashMap::default(); | 737 | let mut grouped_assists: FxHashMap<String, (usize, Vec<Assist>)> = FxHashMap::default(); |
738 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { | 738 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { |
739 | match &assist.group_label { | 739 | match &assist.group_label { |
740 | Some(label) => grouped_assists.entry(label.to_owned()).or_default().push(assist), | 740 | Some(label) => grouped_assists |
741 | None => res.push(create_single_code_action(assist, &world)?.into()), | 741 | .entry(label.to_owned()) |
742 | .or_insert_with(|| { | ||
743 | let idx = res.len(); | ||
744 | let dummy = Command::new(String::new(), String::new(), None); | ||
745 | res.push(dummy.into()); | ||
746 | (idx, Vec::new()) | ||
747 | }) | ||
748 | .1 | ||
749 | .push(assist), | ||
750 | None => { | ||
751 | res.push(create_single_code_action(assist, &world)?.into()); | ||
752 | } | ||
742 | } | 753 | } |
743 | } | 754 | } |
744 | 755 | ||
745 | for (group_label, assists) in grouped_assists { | 756 | for (group_label, (idx, assists)) in grouped_assists { |
746 | if assists.len() == 1 { | 757 | if assists.len() == 1 { |
747 | res.push( | 758 | res[idx] = |
748 | create_single_code_action(assists.into_iter().next().unwrap(), &world)?.into(), | 759 | create_single_code_action(assists.into_iter().next().unwrap(), &world)?.into(); |
749 | ); | ||
750 | } else { | 760 | } else { |
751 | let title = group_label; | 761 | let title = group_label; |
752 | 762 | ||
@@ -760,17 +770,15 @@ pub fn handle_code_action( | |||
760 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), | 770 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), |
761 | arguments: Some(vec![serde_json::Value::Array(arguments)]), | 771 | arguments: Some(vec![serde_json::Value::Array(arguments)]), |
762 | }); | 772 | }); |
763 | res.push( | 773 | res[idx] = CodeAction { |
764 | CodeAction { | 774 | title, |
765 | title, | 775 | kind: None, |
766 | kind: None, | 776 | diagnostics: None, |
767 | diagnostics: None, | 777 | edit: None, |
768 | edit: None, | 778 | command, |
769 | command, | 779 | is_preferred: None, |
770 | is_preferred: None, | 780 | } |
771 | } | 781 | .into(); |
772 | .into(), | ||
773 | ); | ||
774 | } | 782 | } |
775 | } | 783 | } |
776 | 784 | ||