Skip to content

Commit 3a82548

Browse files
author
Côme ALLART
committed
fix: reduce assist scope: pub fn's in pub modules
1 parent d55d3b6 commit 3a82548

File tree

2 files changed

+102
-46
lines changed

2 files changed

+102
-46
lines changed

crates/ide_assists/src/handlers/generate_documentation_template.rs

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use ide_db::assists::{AssistId, AssistKind};
22
use stdx::to_lower_snake_case;
33
use syntax::{
4-
ast::{self, edit::IndentLevel, HasDocComments, HasName},
4+
ast::{self, edit::IndentLevel, HasDocComments, HasName, HasVisibility},
55
AstNode,
66
};
77

@@ -12,7 +12,7 @@ use crate::assist_context::{AssistContext, Assists};
1212
// Adds a documentation template above a function definition / declaration.
1313
//
1414
// ```
15-
// fn my_$0func(a: i32, b: i32) -> Result<(), std::io::Error> {
15+
// pub fn my_$0func(a: i32, b: i32) -> Result<(), std::io::Error> {
1616
// unimplemented!()
1717
// }
1818
// ```
@@ -31,7 +31,7 @@ use crate::assist_context::{AssistContext, Assists};
3131
// /// # Errors
3232
// ///
3333
// /// This function will return an error if .
34-
// fn my_func(a: i32, b: i32) -> Result<(), std::io::Error> {
34+
// pub fn my_func(a: i32, b: i32) -> Result<(), std::io::Error> {
3535
// unimplemented!()
3636
// }
3737
// ```
@@ -40,17 +40,10 @@ pub(crate) fn generate_documentation_template(
4040
ctx: &AssistContext,
4141
) -> Option<()> {
4242
let name = ctx.find_node_at_offset::<ast::Name>()?;
43-
let ast_func = ast::Fn::cast(name.syntax().parent()?)?;
44-
if is_in_trait_impl(&ast_func) {
43+
let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;
44+
if is_in_trait_impl(&ast_func) || !is_public(&ast_func) {
4545
return None;
4646
}
47-
// TODO disable at least examples if function not public, as the example will fail to build on
48-
// `cargo test`. What is the exact criteria of `pub`ness? All parent modules must be `pub`, for
49-
// `impl { fn }` both `fn` and `struct`* must be public.
50-
//
51-
// What about `pub(crate)`?
52-
//
53-
// *: Seems complex but maybe ignoring this criteria can be ignored.
5447

5548
let parent_syntax = ast_func.syntax();
5649
let text_range = parent_syntax.text_range();
@@ -217,6 +210,21 @@ fn gen_ex_start_helper(ast_func: &ast::Fn, krate_name: String) -> Option<(Vec<St
217210
Some((lines, ex_helper))
218211
}
219212

213+
/// Check if the function and all its parent modules are exactly `pub`
214+
fn is_public(ast_func: &ast::Fn) -> bool {
215+
has_pub(ast_func)
216+
&& ast_func
217+
.syntax()
218+
.ancestors()
219+
.filter_map(ast::Module::cast)
220+
.all(|module| has_pub(&module))
221+
}
222+
223+
/// Check if visibility is exactly `pub` (not `pub(crate)` for instance)
224+
fn has_pub<T: HasVisibility>(item: &T) -> bool {
225+
item.visibility().map(|v| v.path().is_none()).unwrap_or(false)
226+
}
227+
220228
/// `None` if function without a body; some bool to guess if function can panic
221229
fn can_panic(ast_func: &ast::Fn) -> Option<bool> {
222230
let body = ast_func.body()?.to_string();
@@ -445,12 +453,60 @@ impl MyTrait for MyStruct {
445453
)
446454
}
447455

456+
#[test]
457+
fn not_applicable_if_function_is_private() {
458+
check_assist_not_applicable(generate_documentation_template, r#"fn priv$0ate() {}"#);
459+
}
460+
461+
#[test]
462+
fn not_applicable_if_function_is_pub_crate() {
463+
check_assist_not_applicable(
464+
generate_documentation_template,
465+
r#"pub(crate) fn pri$0vate() {}"#,
466+
);
467+
}
468+
469+
#[test]
470+
fn not_applicable_if_function_is_in_private_mod() {
471+
check_assist_not_applicable(
472+
generate_documentation_template,
473+
r#"
474+
mod PrivateModule {
475+
pub fn pri$0vate() {}
476+
}"#,
477+
);
478+
}
479+
480+
#[test]
481+
fn not_applicable_if_function_is_in_pub_crate_mod() {
482+
check_assist_not_applicable(
483+
generate_documentation_template,
484+
r#"
485+
pub(crate) mod PrivateModule {
486+
pub fn pr$0ivate() {}
487+
}"#,
488+
);
489+
}
490+
491+
#[test]
492+
fn not_applicable_if_function_is_in_non_public_mod_is_recursive() {
493+
check_assist_not_applicable(
494+
generate_documentation_template,
495+
r#"
496+
mod ParentPrivateModule {
497+
pub mod PrivateModule {
498+
pub fn pr$0ivate() {}
499+
}
500+
}"#,
501+
);
502+
}
503+
448504
#[test]
449505
fn supports_noop_function() {
450506
check_assist(
451507
generate_documentation_template,
452508
r#"
453-
fn no$0op() {}
509+
pub fn no$0op() {}
454510
"#,
455511
r#"
456512
/// .
@@ -462,7 +518,7 @@ fn no$0op() {}
462518
///
463519
/// noop();
464520
/// ```
465-
fn noop() {}
521+
pub fn noop() {}
466522
"#,
467523
);
468524
}
@@ -472,7 +528,7 @@ fn noop() {}
472528
check_assist(
473529
generate_documentation_template,
474530
r#"
475-
fn no$0op_with_param(_a: i32) {}
531+
pub fn no$0op_with_param(_a: i32) {}
476532
"#,
477533
r#"
478534
/// .
@@ -484,7 +540,7 @@ fn no$0op_with_param(_a: i32) {}
484540
///
485541
/// noop_with_param(_a);
486542
/// ```
487-
fn noop_with_param(_a: i32) {}
543+
pub fn noop_with_param(_a: i32) {}
488544
"#,
489545
);
490546
}
@@ -494,7 +550,7 @@ fn noop_with_param(_a: i32) {}
494550
check_assist(
495551
generate_documentation_template,
496552
r#"
497-
unsafe fn no$0op_unsafe() {}
553+
pub unsafe fn no$0op_unsafe() {}
498554
"#,
499555
r#"
500556
/// .
@@ -510,7 +566,7 @@ unsafe fn no$0op_unsafe() {}
510566
/// # Safety
511567
///
512568
/// .
513-
unsafe fn noop_unsafe() {}
569+
pub unsafe fn noop_unsafe() {}
514570
"#,
515571
);
516572
}
@@ -520,7 +576,7 @@ unsafe fn noop_unsafe() {}
520576
check_assist(
521577
generate_documentation_template,
522578
r#"
523-
fn panic$0s_if(a: bool) {
579+
pub fn panic$0s_if(a: bool) {
524580
if a {
525581
panic!();
526582
}
@@ -546,7 +602,7 @@ fn panic$0s_if(a: bool) {
546602
/// # Panics
547603
///
548604
/// Panics if .
549-
fn panics_if(a: bool) {
605+
pub fn panics_if(a: bool) {
550606
if a {
551607
panic!();
552608
}
@@ -560,7 +616,7 @@ fn panics_if(a: bool) {
560616
check_assist(
561617
generate_documentation_template,
562618
r#"
563-
fn $0panics_if_not(a: bool) {
619+
pub fn $0panics_if_not(a: bool) {
564620
assert!(a == true);
565621
}
566622
"#,
@@ -584,7 +640,7 @@ fn $0panics_if_not(a: bool) {
584640
/// # Panics
585641
///
586642
/// Panics if .
587-
fn panics_if_not(a: bool) {
643+
pub fn panics_if_not(a: bool) {
588644
assert!(a == true);
589645
}
590646
"#,
@@ -596,7 +652,7 @@ fn panics_if_not(a: bool) {
596652
check_assist(
597653
generate_documentation_template,
598654
r#"
599-
fn $0panics_if_none(a: Option<()>) {
655+
pub fn $0panics_if_none(a: Option<()>) {
600656
a.unwrap();
601657
}
602658
"#,
@@ -620,7 +676,7 @@ fn $0panics_if_none(a: Option<()>) {
620676
/// # Panics
621677
///
622678
/// Panics if .
623-
fn panics_if_none(a: Option<()>) {
679+
pub fn panics_if_none(a: Option<()>) {
624680
a.unwrap();
625681
}
626682
"#,
@@ -632,7 +688,7 @@ fn panics_if_none(a: Option<()>) {
632688
check_assist(
633689
generate_documentation_template,
634690
r#"
635-
fn $0panics_if_none2(a: Option<()>) {
691+
pub fn $0panics_if_none2(a: Option<()>) {
636692
a.expect("Bouh!");
637693
}
638694
"#,
@@ -656,7 +712,7 @@ fn $0panics_if_none2(a: Option<()>) {
656712
/// # Panics
657713
///
658714
/// Panics if .
659-
fn panics_if_none2(a: Option<()>) {
715+
pub fn panics_if_none2(a: Option<()>) {
660716
a.expect("Bouh!");
661717
}
662718
"#,
@@ -668,7 +724,7 @@ fn panics_if_none2(a: Option<()>) {
668724
check_assist(
669725
generate_documentation_template,
670726
r#"
671-
fn returns_a_value$0() -> i32 {
727+
pub fn returns_a_value$0() -> i32 {
672728
0
673729
}
674730
"#,
@@ -682,7 +738,7 @@ fn returns_a_value$0() -> i32 {
682738
///
683739
/// assert_eq!(returns_a_value(), );
684740
/// ```
685-
fn returns_a_value() -> i32 {
741+
pub fn returns_a_value() -> i32 {
686742
0
687743
}
688744
"#,
@@ -694,7 +750,7 @@ fn returns_a_value() -> i32 {
694750
check_assist(
695751
generate_documentation_template,
696752
r#"
697-
fn returns_a_result$0() -> Result<i32, std::io::Error> {
753+
pub fn returns_a_result$0() -> Result<i32, std::io::Error> {
698754
Ok(0)
699755
}
700756
"#,
@@ -712,7 +768,7 @@ fn returns_a_result$0() -> Result<i32, std::io::Error> {
712768
/// # Errors
713769
///
714770
/// This function will return an error if .
715-
fn returns_a_result() -> Result<i32, std::io::Error> {
771+
pub fn returns_a_result() -> Result<i32, std::io::Error> {
716772
Ok(0)
717773
}
718774
"#,
@@ -724,7 +780,7 @@ fn returns_a_result() -> Result<i32, std::io::Error> {
724780
check_assist(
725781
generate_documentation_template,
726782
r#"
727-
fn modifies_a_value$0(a: &mut i32) {
783+
pub fn modifies_a_value$0(a: &mut i32) {
728784
*a = 0;
729785
}
730786
"#,
@@ -740,7 +796,7 @@ fn modifies_a_value$0(a: &mut i32) {
740796
/// modifies_a_value(&mut a);
741797
/// assert_eq!(a, );
742798
/// ```
743-
fn modifies_a_value(a: &mut i32) {
799+
pub fn modifies_a_value(a: &mut i32) {
744800
*a = 0;
745801
}
746802
"#,
@@ -752,7 +808,7 @@ fn modifies_a_value(a: &mut i32) {
752808
check_assist(
753809
generate_documentation_template,
754810
r#"
755-
fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
811+
pub fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
756812
a + b + c
757813
}
758814
"#,
@@ -767,7 +823,7 @@ fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
767823
/// let result = sum3(a, b, c);
768824
/// assert_eq!(result, );
769825
/// ```
770-
fn sum3(a: i32, b: i32, c: i32) -> i32 {
826+
pub fn sum3(a: i32, b: i32, c: i32) -> i32 {
771827
a + b + c
772828
}
773829
"#,
@@ -779,15 +835,15 @@ fn sum3(a: i32, b: i32, c: i32) -> i32 {
779835
check_assist(
780836
generate_documentation_template,
781837
r#"
782-
mod a {
783-
mod b {
784-
fn no$0op() {}
838+
pub mod a {
839+
pub mod b {
840+
pub fn no$0op() {}
785841
}
786842
}
787843
"#,
788844
r#"
789-
mod a {
790-
mod b {
845+
pub mod a {
846+
pub mod b {
791847
/// .
792848
///
793849
/// # Examples
@@ -797,7 +853,7 @@ mod a {
797853
///
798854
/// noop();
799855
/// ```
800-
fn noop() {}
856+
pub fn noop() {}
801857
}
802858
}
803859
"#,
@@ -809,13 +865,13 @@ mod a {
809865
check_assist(
810866
generate_documentation_template,
811867
r#"
812-
struct MyStruct;
868+
pub struct MyStruct;
813869
impl MyStruct {
814-
fn no$0op() {}
870+
pub fn no$0op() {}
815871
}
816872
"#,
817873
r#"
818-
struct MyStruct;
874+
pub struct MyStruct;
819875
impl MyStruct {
820876
/// .
821877
///
@@ -826,7 +882,7 @@ impl MyStruct {
826882
///
827883
/// MyStruct::noop();
828884
/// ```
829-
fn noop() {}
885+
pub fn noop() {}
830886
}
831887
"#,
832888
);

crates/ide_assists/src/tests/generated.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ fn doctest_generate_documentation_template() {
844844
check_doc_test(
845845
"generate_documentation_template",
846846
r#####"
847-
fn my_$0func(a: i32, b: i32) -> Result<(), std::io::Error> {
847+
pub fn my_$0func(a: i32, b: i32) -> Result<(), std::io::Error> {
848848
unimplemented!()
849849
}
850850
"#####,
@@ -862,7 +862,7 @@ fn my_$0func(a: i32, b: i32) -> Result<(), std::io::Error> {
862862
/// # Errors
863863
///
864864
/// This function will return an error if .
865-
fn my_func(a: i32, b: i32) -> Result<(), std::io::Error> {
865+
pub fn my_func(a: i32, b: i32) -> Result<(), std::io::Error> {
866866
unimplemented!()
867867
}
868868
"#####,

0 commit comments

Comments
 (0)