diff options
Diffstat (limited to 'crates/ide_assists/src/handlers/fix_visibility.rs')
-rw-r--r-- | crates/ide_assists/src/handlers/fix_visibility.rs | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs new file mode 100644 index 000000000..6c7824e55 --- /dev/null +++ b/crates/ide_assists/src/handlers/fix_visibility.rs | |||
@@ -0,0 +1,607 @@ | |||
1 | use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; | ||
2 | use ide_db::base_db::FileId; | ||
3 | use syntax::{ | ||
4 | ast::{self, VisibilityOwner}, | ||
5 | AstNode, TextRange, TextSize, | ||
6 | }; | ||
7 | |||
8 | use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; | ||
9 | |||
10 | // FIXME: this really should be a fix for diagnostic, rather than an assist. | ||
11 | |||
12 | // Assist: fix_visibility | ||
13 | // | ||
14 | // Makes inaccessible item public. | ||
15 | // | ||
16 | // ``` | ||
17 | // mod m { | ||
18 | // fn frobnicate() {} | ||
19 | // } | ||
20 | // fn main() { | ||
21 | // m::frobnicate$0() {} | ||
22 | // } | ||
23 | // ``` | ||
24 | // -> | ||
25 | // ``` | ||
26 | // mod m { | ||
27 | // $0pub(crate) fn frobnicate() {} | ||
28 | // } | ||
29 | // fn main() { | ||
30 | // m::frobnicate() {} | ||
31 | // } | ||
32 | // ``` | ||
33 | pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
34 | add_vis_to_referenced_module_def(acc, ctx) | ||
35 | .or_else(|| add_vis_to_referenced_record_field(acc, ctx)) | ||
36 | } | ||
37 | |||
38 | fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
39 | let path: ast::Path = ctx.find_node_at_offset()?; | ||
40 | let path_res = ctx.sema.resolve_path(&path)?; | ||
41 | let def = match path_res { | ||
42 | PathResolution::Def(def) => def, | ||
43 | _ => return None, | ||
44 | }; | ||
45 | |||
46 | let current_module = ctx.sema.scope(&path.syntax()).module()?; | ||
47 | let target_module = def.module(ctx.db())?; | ||
48 | |||
49 | let vis = target_module.visibility_of(ctx.db(), &def)?; | ||
50 | if vis.is_visible_from(ctx.db(), current_module.into()) { | ||
51 | return None; | ||
52 | }; | ||
53 | |||
54 | let (offset, current_visibility, target, target_file, target_name) = | ||
55 | target_data_for_def(ctx.db(), def)?; | ||
56 | |||
57 | let missing_visibility = | ||
58 | if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; | ||
59 | |||
60 | let assist_label = match target_name { | ||
61 | None => format!("Change visibility to {}", missing_visibility), | ||
62 | Some(name) => format!("Change visibility of {} to {}", name, missing_visibility), | ||
63 | }; | ||
64 | |||
65 | acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| { | ||
66 | builder.edit_file(target_file); | ||
67 | match ctx.config.snippet_cap { | ||
68 | Some(cap) => match current_visibility { | ||
69 | Some(current_visibility) => builder.replace_snippet( | ||
70 | cap, | ||
71 | current_visibility.syntax().text_range(), | ||
72 | format!("$0{}", missing_visibility), | ||
73 | ), | ||
74 | None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | ||
75 | }, | ||
76 | None => match current_visibility { | ||
77 | Some(current_visibility) => { | ||
78 | builder.replace(current_visibility.syntax().text_range(), missing_visibility) | ||
79 | } | ||
80 | None => builder.insert(offset, format!("{} ", missing_visibility)), | ||
81 | }, | ||
82 | } | ||
83 | }) | ||
84 | } | ||
85 | |||
86 | fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
87 | let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; | ||
88 | let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; | ||
89 | |||
90 | let current_module = ctx.sema.scope(record_field.syntax()).module()?; | ||
91 | let visibility = record_field_def.visibility(ctx.db()); | ||
92 | if visibility.is_visible_from(ctx.db(), current_module.into()) { | ||
93 | return None; | ||
94 | } | ||
95 | |||
96 | let parent = record_field_def.parent_def(ctx.db()); | ||
97 | let parent_name = parent.name(ctx.db()); | ||
98 | let target_module = parent.module(ctx.db()); | ||
99 | |||
100 | let in_file_source = record_field_def.source(ctx.db())?; | ||
101 | let (offset, current_visibility, target) = match in_file_source.value { | ||
102 | hir::FieldSource::Named(it) => { | ||
103 | let s = it.syntax(); | ||
104 | (vis_offset(s), it.visibility(), s.text_range()) | ||
105 | } | ||
106 | hir::FieldSource::Pos(it) => { | ||
107 | let s = it.syntax(); | ||
108 | (vis_offset(s), it.visibility(), s.text_range()) | ||
109 | } | ||
110 | }; | ||
111 | |||
112 | let missing_visibility = | ||
113 | if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; | ||
114 | let target_file = in_file_source.file_id.original_file(ctx.db()); | ||
115 | |||
116 | let target_name = record_field_def.name(ctx.db()); | ||
117 | let assist_label = | ||
118 | format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); | ||
119 | |||
120 | acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| { | ||
121 | builder.edit_file(target_file); | ||
122 | match ctx.config.snippet_cap { | ||
123 | Some(cap) => match current_visibility { | ||
124 | Some(current_visibility) => builder.replace_snippet( | ||
125 | cap, | ||
126 | current_visibility.syntax().text_range(), | ||
127 | format!("$0{}", missing_visibility), | ||
128 | ), | ||
129 | None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | ||
130 | }, | ||
131 | None => match current_visibility { | ||
132 | Some(current_visibility) => { | ||
133 | builder.replace(current_visibility.syntax().text_range(), missing_visibility) | ||
134 | } | ||
135 | None => builder.insert(offset, format!("{} ", missing_visibility)), | ||
136 | }, | ||
137 | } | ||
138 | }) | ||
139 | } | ||
140 | |||
141 | fn target_data_for_def( | ||
142 | db: &dyn HirDatabase, | ||
143 | def: hir::ModuleDef, | ||
144 | ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId, Option<hir::Name>)> { | ||
145 | fn offset_target_and_file_id<S, Ast>( | ||
146 | db: &dyn HirDatabase, | ||
147 | x: S, | ||
148 | ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)> | ||
149 | where | ||
150 | S: HasSource<Ast = Ast>, | ||
151 | Ast: AstNode + ast::VisibilityOwner, | ||
152 | { | ||
153 | let source = x.source(db)?; | ||
154 | let in_file_syntax = source.syntax(); | ||
155 | let file_id = in_file_syntax.file_id; | ||
156 | let syntax = in_file_syntax.value; | ||
157 | let current_visibility = source.value.visibility(); | ||
158 | Some(( | ||
159 | vis_offset(syntax), | ||
160 | current_visibility, | ||
161 | syntax.text_range(), | ||
162 | file_id.original_file(db.upcast()), | ||
163 | )) | ||
164 | } | ||
165 | |||
166 | let target_name; | ||
167 | let (offset, current_visibility, target, target_file) = match def { | ||
168 | hir::ModuleDef::Function(f) => { | ||
169 | target_name = Some(f.name(db)); | ||
170 | offset_target_and_file_id(db, f)? | ||
171 | } | ||
172 | hir::ModuleDef::Adt(adt) => { | ||
173 | target_name = Some(adt.name(db)); | ||
174 | match adt { | ||
175 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?, | ||
176 | hir::Adt::Union(u) => offset_target_and_file_id(db, u)?, | ||
177 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?, | ||
178 | } | ||
179 | } | ||
180 | hir::ModuleDef::Const(c) => { | ||
181 | target_name = c.name(db); | ||
182 | offset_target_and_file_id(db, c)? | ||
183 | } | ||
184 | hir::ModuleDef::Static(s) => { | ||
185 | target_name = s.name(db); | ||
186 | offset_target_and_file_id(db, s)? | ||
187 | } | ||
188 | hir::ModuleDef::Trait(t) => { | ||
189 | target_name = Some(t.name(db)); | ||
190 | offset_target_and_file_id(db, t)? | ||
191 | } | ||
192 | hir::ModuleDef::TypeAlias(t) => { | ||
193 | target_name = Some(t.name(db)); | ||
194 | offset_target_and_file_id(db, t)? | ||
195 | } | ||
196 | hir::ModuleDef::Module(m) => { | ||
197 | target_name = m.name(db); | ||
198 | let in_file_source = m.declaration_source(db)?; | ||
199 | let file_id = in_file_source.file_id.original_file(db.upcast()); | ||
200 | let syntax = in_file_source.value.syntax(); | ||
201 | (vis_offset(syntax), in_file_source.value.visibility(), syntax.text_range(), file_id) | ||
202 | } | ||
203 | // Enum variants can't be private, we can't modify builtin types | ||
204 | hir::ModuleDef::Variant(_) | hir::ModuleDef::BuiltinType(_) => return None, | ||
205 | }; | ||
206 | |||
207 | Some((offset, current_visibility, target, target_file, target_name)) | ||
208 | } | ||
209 | |||
210 | #[cfg(test)] | ||
211 | mod tests { | ||
212 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
213 | |||
214 | use super::*; | ||
215 | |||
216 | #[test] | ||
217 | fn fix_visibility_of_fn() { | ||
218 | check_assist( | ||
219 | fix_visibility, | ||
220 | r"mod foo { fn foo() {} } | ||
221 | fn main() { foo::foo$0() } ", | ||
222 | r"mod foo { $0pub(crate) fn foo() {} } | ||
223 | fn main() { foo::foo() } ", | ||
224 | ); | ||
225 | check_assist_not_applicable( | ||
226 | fix_visibility, | ||
227 | r"mod foo { pub fn foo() {} } | ||
228 | fn main() { foo::foo$0() } ", | ||
229 | ) | ||
230 | } | ||
231 | |||
232 | #[test] | ||
233 | fn fix_visibility_of_adt_in_submodule() { | ||
234 | check_assist( | ||
235 | fix_visibility, | ||
236 | r"mod foo { struct Foo; } | ||
237 | fn main() { foo::Foo$0 } ", | ||
238 | r"mod foo { $0pub(crate) struct Foo; } | ||
239 | fn main() { foo::Foo } ", | ||
240 | ); | ||
241 | check_assist_not_applicable( | ||
242 | fix_visibility, | ||
243 | r"mod foo { pub struct Foo; } | ||
244 | fn main() { foo::Foo$0 } ", | ||
245 | ); | ||
246 | check_assist( | ||
247 | fix_visibility, | ||
248 | r"mod foo { enum Foo; } | ||
249 | fn main() { foo::Foo$0 } ", | ||
250 | r"mod foo { $0pub(crate) enum Foo; } | ||
251 | fn main() { foo::Foo } ", | ||
252 | ); | ||
253 | check_assist_not_applicable( | ||
254 | fix_visibility, | ||
255 | r"mod foo { pub enum Foo; } | ||
256 | fn main() { foo::Foo$0 } ", | ||
257 | ); | ||
258 | check_assist( | ||
259 | fix_visibility, | ||
260 | r"mod foo { union Foo; } | ||
261 | fn main() { foo::Foo$0 } ", | ||
262 | r"mod foo { $0pub(crate) union Foo; } | ||
263 | fn main() { foo::Foo } ", | ||
264 | ); | ||
265 | check_assist_not_applicable( | ||
266 | fix_visibility, | ||
267 | r"mod foo { pub union Foo; } | ||
268 | fn main() { foo::Foo$0 } ", | ||
269 | ); | ||
270 | } | ||
271 | |||
272 | #[test] | ||
273 | fn fix_visibility_of_adt_in_other_file() { | ||
274 | check_assist( | ||
275 | fix_visibility, | ||
276 | r" | ||
277 | //- /main.rs | ||
278 | mod foo; | ||
279 | fn main() { foo::Foo$0 } | ||
280 | |||
281 | //- /foo.rs | ||
282 | struct Foo; | ||
283 | ", | ||
284 | r"$0pub(crate) struct Foo; | ||
285 | ", | ||
286 | ); | ||
287 | } | ||
288 | |||
289 | #[test] | ||
290 | fn fix_visibility_of_struct_field() { | ||
291 | check_assist( | ||
292 | fix_visibility, | ||
293 | r"mod foo { pub struct Foo { bar: (), } } | ||
294 | fn main() { foo::Foo { $0bar: () }; } ", | ||
295 | r"mod foo { pub struct Foo { $0pub(crate) bar: (), } } | ||
296 | fn main() { foo::Foo { bar: () }; } ", | ||
297 | ); | ||
298 | check_assist( | ||
299 | fix_visibility, | ||
300 | r" | ||
301 | //- /lib.rs | ||
302 | mod foo; | ||
303 | fn main() { foo::Foo { $0bar: () }; } | ||
304 | //- /foo.rs | ||
305 | pub struct Foo { bar: () } | ||
306 | ", | ||
307 | r"pub struct Foo { $0pub(crate) bar: () } | ||
308 | ", | ||
309 | ); | ||
310 | check_assist_not_applicable( | ||
311 | fix_visibility, | ||
312 | r"mod foo { pub struct Foo { pub bar: (), } } | ||
313 | fn main() { foo::Foo { $0bar: () }; } ", | ||
314 | ); | ||
315 | check_assist_not_applicable( | ||
316 | fix_visibility, | ||
317 | r" | ||
318 | //- /lib.rs | ||
319 | mod foo; | ||
320 | fn main() { foo::Foo { $0bar: () }; } | ||
321 | //- /foo.rs | ||
322 | pub struct Foo { pub bar: () } | ||
323 | ", | ||
324 | ); | ||
325 | } | ||
326 | |||
327 | #[test] | ||
328 | fn fix_visibility_of_enum_variant_field() { | ||
329 | // Enum variants, as well as their fields, always get the enum's visibility. In fact, rustc | ||
330 | // rejects any visibility specifiers on them, so this assist should never fire on them. | ||
331 | check_assist_not_applicable( | ||
332 | fix_visibility, | ||
333 | r"mod foo { pub enum Foo { Bar { bar: () } } } | ||
334 | fn main() { foo::Foo::Bar { $0bar: () }; } ", | ||
335 | ); | ||
336 | check_assist_not_applicable( | ||
337 | fix_visibility, | ||
338 | r" | ||
339 | //- /lib.rs | ||
340 | mod foo; | ||
341 | fn main() { foo::Foo::Bar { $0bar: () }; } | ||
342 | //- /foo.rs | ||
343 | pub enum Foo { Bar { bar: () } } | ||
344 | ", | ||
345 | ); | ||
346 | check_assist_not_applicable( | ||
347 | fix_visibility, | ||
348 | r"mod foo { pub struct Foo { pub bar: (), } } | ||
349 | fn main() { foo::Foo { $0bar: () }; } ", | ||
350 | ); | ||
351 | check_assist_not_applicable( | ||
352 | fix_visibility, | ||
353 | r" | ||
354 | //- /lib.rs | ||
355 | mod foo; | ||
356 | fn main() { foo::Foo { $0bar: () }; } | ||
357 | //- /foo.rs | ||
358 | pub struct Foo { pub bar: () } | ||
359 | ", | ||
360 | ); | ||
361 | } | ||
362 | |||
363 | #[test] | ||
364 | #[ignore] | ||
365 | // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields | ||
366 | fn fix_visibility_of_union_field() { | ||
367 | check_assist( | ||
368 | fix_visibility, | ||
369 | r"mod foo { pub union Foo { bar: (), } } | ||
370 | fn main() { foo::Foo { $0bar: () }; } ", | ||
371 | r"mod foo { pub union Foo { $0pub(crate) bar: (), } } | ||
372 | fn main() { foo::Foo { bar: () }; } ", | ||
373 | ); | ||
374 | check_assist( | ||
375 | fix_visibility, | ||
376 | r" | ||
377 | //- /lib.rs | ||
378 | mod foo; | ||
379 | fn main() { foo::Foo { $0bar: () }; } | ||
380 | //- /foo.rs | ||
381 | pub union Foo { bar: () } | ||
382 | ", | ||
383 | r"pub union Foo { $0pub(crate) bar: () } | ||
384 | ", | ||
385 | ); | ||
386 | check_assist_not_applicable( | ||
387 | fix_visibility, | ||
388 | r"mod foo { pub union Foo { pub bar: (), } } | ||
389 | fn main() { foo::Foo { $0bar: () }; } ", | ||
390 | ); | ||
391 | check_assist_not_applicable( | ||
392 | fix_visibility, | ||
393 | r" | ||
394 | //- /lib.rs | ||
395 | mod foo; | ||
396 | fn main() { foo::Foo { $0bar: () }; } | ||
397 | //- /foo.rs | ||
398 | pub union Foo { pub bar: () } | ||
399 | ", | ||
400 | ); | ||
401 | } | ||
402 | |||
403 | #[test] | ||
404 | fn fix_visibility_of_const() { | ||
405 | check_assist( | ||
406 | fix_visibility, | ||
407 | r"mod foo { const FOO: () = (); } | ||
408 | fn main() { foo::FOO$0 } ", | ||
409 | r"mod foo { $0pub(crate) const FOO: () = (); } | ||
410 | fn main() { foo::FOO } ", | ||
411 | ); | ||
412 | check_assist_not_applicable( | ||
413 | fix_visibility, | ||
414 | r"mod foo { pub const FOO: () = (); } | ||
415 | fn main() { foo::FOO$0 } ", | ||
416 | ); | ||
417 | } | ||
418 | |||
419 | #[test] | ||
420 | fn fix_visibility_of_static() { | ||
421 | check_assist( | ||
422 | fix_visibility, | ||
423 | r"mod foo { static FOO: () = (); } | ||
424 | fn main() { foo::FOO$0 } ", | ||
425 | r"mod foo { $0pub(crate) static FOO: () = (); } | ||
426 | fn main() { foo::FOO } ", | ||
427 | ); | ||
428 | check_assist_not_applicable( | ||
429 | fix_visibility, | ||
430 | r"mod foo { pub static FOO: () = (); } | ||
431 | fn main() { foo::FOO$0 } ", | ||
432 | ); | ||
433 | } | ||
434 | |||
435 | #[test] | ||
436 | fn fix_visibility_of_trait() { | ||
437 | check_assist( | ||
438 | fix_visibility, | ||
439 | r"mod foo { trait Foo { fn foo(&self) {} } } | ||
440 | fn main() { let x: &dyn foo::$0Foo; } ", | ||
441 | r"mod foo { $0pub(crate) trait Foo { fn foo(&self) {} } } | ||
442 | fn main() { let x: &dyn foo::Foo; } ", | ||
443 | ); | ||
444 | check_assist_not_applicable( | ||
445 | fix_visibility, | ||
446 | r"mod foo { pub trait Foo { fn foo(&self) {} } } | ||
447 | fn main() { let x: &dyn foo::Foo$0; } ", | ||
448 | ); | ||
449 | } | ||
450 | |||
451 | #[test] | ||
452 | fn fix_visibility_of_type_alias() { | ||
453 | check_assist( | ||
454 | fix_visibility, | ||
455 | r"mod foo { type Foo = (); } | ||
456 | fn main() { let x: foo::Foo$0; } ", | ||
457 | r"mod foo { $0pub(crate) type Foo = (); } | ||
458 | fn main() { let x: foo::Foo; } ", | ||
459 | ); | ||
460 | check_assist_not_applicable( | ||
461 | fix_visibility, | ||
462 | r"mod foo { pub type Foo = (); } | ||
463 | fn main() { let x: foo::Foo$0; } ", | ||
464 | ); | ||
465 | } | ||
466 | |||
467 | #[test] | ||
468 | fn fix_visibility_of_module() { | ||
469 | check_assist( | ||
470 | fix_visibility, | ||
471 | r"mod foo { mod bar { fn bar() {} } } | ||
472 | fn main() { foo::bar$0::bar(); } ", | ||
473 | r"mod foo { $0pub(crate) mod bar { fn bar() {} } } | ||
474 | fn main() { foo::bar::bar(); } ", | ||
475 | ); | ||
476 | |||
477 | check_assist( | ||
478 | fix_visibility, | ||
479 | r" | ||
480 | //- /main.rs | ||
481 | mod foo; | ||
482 | fn main() { foo::bar$0::baz(); } | ||
483 | |||
484 | //- /foo.rs | ||
485 | mod bar { | ||
486 | pub fn baz() {} | ||
487 | } | ||
488 | ", | ||
489 | r"$0pub(crate) mod bar { | ||
490 | pub fn baz() {} | ||
491 | } | ||
492 | ", | ||
493 | ); | ||
494 | |||
495 | check_assist_not_applicable( | ||
496 | fix_visibility, | ||
497 | r"mod foo { pub mod bar { pub fn bar() {} } } | ||
498 | fn main() { foo::bar$0::bar(); } ", | ||
499 | ); | ||
500 | } | ||
501 | |||
502 | #[test] | ||
503 | fn fix_visibility_of_inline_module_in_other_file() { | ||
504 | check_assist( | ||
505 | fix_visibility, | ||
506 | r" | ||
507 | //- /main.rs | ||
508 | mod foo; | ||
509 | fn main() { foo::bar$0::baz(); } | ||
510 | |||
511 | //- /foo.rs | ||
512 | mod bar; | ||
513 | //- /foo/bar.rs | ||
514 | pub fn baz() {} | ||
515 | ", | ||
516 | r"$0pub(crate) mod bar; | ||
517 | ", | ||
518 | ); | ||
519 | } | ||
520 | |||
521 | #[test] | ||
522 | fn fix_visibility_of_module_declaration_in_other_file() { | ||
523 | check_assist( | ||
524 | fix_visibility, | ||
525 | r" | ||
526 | //- /main.rs | ||
527 | mod foo; | ||
528 | fn main() { foo::bar$0>::baz(); } | ||
529 | |||
530 | //- /foo.rs | ||
531 | mod bar { | ||
532 | pub fn baz() {} | ||
533 | } | ||
534 | ", | ||
535 | r"$0pub(crate) mod bar { | ||
536 | pub fn baz() {} | ||
537 | } | ||
538 | ", | ||
539 | ); | ||
540 | } | ||
541 | |||
542 | #[test] | ||
543 | fn adds_pub_when_target_is_in_another_crate() { | ||
544 | check_assist( | ||
545 | fix_visibility, | ||
546 | r" | ||
547 | //- /main.rs crate:a deps:foo | ||
548 | foo::Bar$0 | ||
549 | //- /lib.rs crate:foo | ||
550 | struct Bar; | ||
551 | ", | ||
552 | r"$0pub struct Bar; | ||
553 | ", | ||
554 | ) | ||
555 | } | ||
556 | |||
557 | #[test] | ||
558 | fn replaces_pub_crate_with_pub() { | ||
559 | check_assist( | ||
560 | fix_visibility, | ||
561 | r" | ||
562 | //- /main.rs crate:a deps:foo | ||
563 | foo::Bar$0 | ||
564 | //- /lib.rs crate:foo | ||
565 | pub(crate) struct Bar; | ||
566 | ", | ||
567 | r"$0pub struct Bar; | ||
568 | ", | ||
569 | ); | ||
570 | check_assist( | ||
571 | fix_visibility, | ||
572 | r" | ||
573 | //- /main.rs crate:a deps:foo | ||
574 | fn main() { | ||
575 | foo::Foo { $0bar: () }; | ||
576 | } | ||
577 | //- /lib.rs crate:foo | ||
578 | pub struct Foo { pub(crate) bar: () } | ||
579 | ", | ||
580 | r"pub struct Foo { $0pub bar: () } | ||
581 | ", | ||
582 | ); | ||
583 | } | ||
584 | |||
585 | #[test] | ||
586 | #[ignore] | ||
587 | // FIXME handle reexports properly | ||
588 | fn fix_visibility_of_reexport() { | ||
589 | check_assist( | ||
590 | fix_visibility, | ||
591 | r" | ||
592 | mod foo { | ||
593 | use bar::Baz; | ||
594 | mod bar { pub(super) struct Baz; } | ||
595 | } | ||
596 | foo::Baz$0 | ||
597 | ", | ||
598 | r" | ||
599 | mod foo { | ||
600 | $0pub(crate) use bar::Baz; | ||
601 | mod bar { pub(super) struct Baz; } | ||
602 | } | ||
603 | foo::Baz | ||
604 | ", | ||
605 | ) | ||
606 | } | ||
607 | } | ||