2 ast::{self, NameOwner, VisibilityOwner},
4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY},
8 use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
10 // Assist: change_visibility
12 // Adds or changes existing visibility specifier.
15 // $0fn frobnicate() {}
19 // pub(crate) fn frobnicate() {}
21 pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
22 if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
23 return change_vis(acc, vis);
28 fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
29 let item_keyword = ctx.token_at_offset().find(|leaf| {
43 let (offset, target) = if let Some(keyword) = item_keyword {
44 let parent = keyword.parent();
45 let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT];
46 // Parent is not a definition, can't add visibility
47 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
50 // Already have visibility, do nothing
51 if parent.children().any(|child| child.kind() == VISIBILITY) {
54 (vis_offset(&parent), keyword.text_range())
55 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
56 let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?;
57 if field.name()? != field_name {
58 cov_mark::hit!(change_visibility_field_false_positive);
61 if field.visibility().is_some() {
64 (vis_offset(field.syntax()), field_name.syntax().text_range())
65 } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleField>() {
66 if field.visibility().is_some() {
69 (vis_offset(field.syntax()), field.syntax().text_range())
75 AssistId("change_visibility", AssistKind::RefactorRewrite),
76 "Change visibility to pub(crate)",
79 edit.insert(offset, "pub(crate) ");
84 fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
85 if vis.syntax().text() == "pub" {
86 let target = vis.syntax().text_range();
88 AssistId("change_visibility", AssistKind::RefactorRewrite),
89 "Change Visibility to pub(crate)",
92 edit.replace(vis.syntax().text_range(), "pub(crate)");
96 if vis.syntax().text() == "pub(crate)" {
97 let target = vis.syntax().text_range();
99 AssistId("change_visibility", AssistKind::RefactorRewrite),
100 "Change visibility to pub",
103 edit.replace(vis.syntax().text_range(), "pub");
112 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
117 fn change_visibility_adds_pub_crate_to_items() {
118 check_assist(change_visibility, "$0fn foo() {}", "pub(crate) fn foo() {}");
119 check_assist(change_visibility, "f$0n foo() {}", "pub(crate) fn foo() {}");
120 check_assist(change_visibility, "$0struct Foo {}", "pub(crate) struct Foo {}");
121 check_assist(change_visibility, "$0mod foo {}", "pub(crate) mod foo {}");
122 check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}");
123 check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}");
124 check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}");
128 fn change_visibility_works_with_struct_fields() {
131 r"struct S { $0field: u32 }",
132 r"struct S { pub(crate) field: u32 }",
134 check_assist(change_visibility, r"struct S ( $0u32 )", r"struct S ( pub(crate) u32 )");
138 fn change_visibility_field_false_positive() {
139 cov_mark::check!(change_visibility_field_false_positive);
140 check_assist_not_applicable(
142 r"struct S { field: [(); { let $0x = ();}] }",
147 fn change_visibility_pub_to_pub_crate() {
148 check_assist(change_visibility, "$0pub fn foo() {}", "pub(crate) fn foo() {}")
152 fn change_visibility_pub_crate_to_pub() {
153 check_assist(change_visibility, "$0pub(crate) fn foo() {}", "pub fn foo() {}")
157 fn change_visibility_const() {
158 check_assist(change_visibility, "$0const FOO = 3u8;", "pub(crate) const FOO = 3u8;");
162 fn change_visibility_static() {
163 check_assist(change_visibility, "$0static FOO = 3u8;", "pub(crate) static FOO = 3u8;");
167 fn change_visibility_type_alias() {
168 check_assist(change_visibility, "$0type T = ();", "pub(crate) type T = ();");
172 fn change_visibility_handles_comment_attrs() {
189 pub(crate) struct Foo;
195 fn not_applicable_for_enum_variants() {
196 check_assist_not_applicable(
198 r"mod foo { pub enum Foo {Foo1} }
199 fn main() { foo::Foo::Foo1$0 } ",
204 fn change_visibility_target() {
205 check_assist_target(change_visibility, "$0fn foo() {}", "fn");
206 check_assist_target(change_visibility, "pub(crate)$0 fn foo() {}", "pub(crate)");
207 check_assist_target(change_visibility, "struct S { $0field: u32 }", "field");