@@ -5,6 +5,7 @@ use ide_db::{
55 base_db:: FileId ,
66 defs:: { Definition , NameRefClass } ,
77 famous_defs:: FamousDefs ,
8+ helpers:: is_editable_crate,
89 path_transform:: PathTransform ,
910 FxHashMap , FxHashSet , RootDatabase , SnippetCap ,
1011} ;
@@ -65,6 +66,13 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
6566 let fn_name = & * name_ref. text ( ) ;
6667 let TargetInfo { target_module, adt_name, target, file, insert_offset } =
6768 fn_target_info ( ctx, path, & call, fn_name) ?;
69+
70+ if let Some ( m) = target_module {
71+ if !is_editable_crate ( m. krate ( ) , ctx. db ( ) ) {
72+ return None ;
73+ }
74+ }
75+
6876 let function_builder = FunctionBuilder :: from_call ( ctx, & call, fn_name, target_module, target) ?;
6977 let text_range = call. syntax ( ) . text_range ( ) ;
7078 let label = format ! ( "Generate {} function" , function_builder. fn_name) ;
@@ -141,12 +149,11 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
141149 let receiver_ty = ctx. sema . type_of_expr ( & call. receiver ( ) ?) ?. original ( ) . strip_references ( ) ;
142150 let adt = receiver_ty. as_adt ( ) ?;
143151
144- let current_module = ctx. sema . scope ( call. syntax ( ) ) ?. module ( ) ;
145152 let target_module = adt. module ( ctx. sema . db ) ;
146-
147- if current_module. krate ( ) != target_module. krate ( ) {
153+ if !is_editable_crate ( target_module. krate ( ) , ctx. db ( ) ) {
148154 return None ;
149155 }
156+
150157 let ( impl_, file) = get_adt_source ( ctx, & adt, fn_name. text ( ) . as_str ( ) ) ?;
151158 let ( target, insert_offset) = get_method_target ( ctx, & impl_, & adt) ?;
152159
@@ -253,7 +260,7 @@ struct FunctionBuilder {
253260 params : ast:: ParamList ,
254261 ret_type : Option < ast:: RetType > ,
255262 should_focus_return_type : bool ,
256- needs_pub : bool ,
263+ visibility : Visibility ,
257264 is_async : bool ,
258265}
259266
@@ -264,12 +271,14 @@ impl FunctionBuilder {
264271 ctx : & AssistContext < ' _ > ,
265272 call : & ast:: CallExpr ,
266273 fn_name : & str ,
267- target_module : Option < hir :: Module > ,
274+ target_module : Option < Module > ,
268275 target : GeneratedFunctionTarget ,
269276 ) -> Option < Self > {
270- let needs_pub = target_module. is_some ( ) ;
271277 let target_module =
272278 target_module. or_else ( || ctx. sema . scope ( target. syntax ( ) ) . map ( |it| it. module ( ) ) ) ?;
279+
280+ let current_module = ctx. sema . scope ( call. syntax ( ) ) ?. module ( ) ;
281+ let visibility = calculate_necessary_visibility ( current_module, target_module, ctx) ;
273282 let fn_name = make:: name ( fn_name) ;
274283 let mut necessary_generic_params = FxHashSet :: default ( ) ;
275284 let params = fn_args (
@@ -300,7 +309,7 @@ impl FunctionBuilder {
300309 params,
301310 ret_type,
302311 should_focus_return_type,
303- needs_pub ,
312+ visibility ,
304313 is_async,
305314 } )
306315 }
@@ -313,8 +322,9 @@ impl FunctionBuilder {
313322 target_module : Module ,
314323 target : GeneratedFunctionTarget ,
315324 ) -> Option < Self > {
316- let needs_pub =
317- !module_is_descendant ( & ctx. sema . scope ( call. syntax ( ) ) ?. module ( ) , & target_module, ctx) ;
325+ let current_module = ctx. sema . scope ( call. syntax ( ) ) ?. module ( ) ;
326+ let visibility = calculate_necessary_visibility ( current_module, target_module, ctx) ;
327+
318328 let fn_name = make:: name ( & name. text ( ) ) ;
319329 let mut necessary_generic_params = FxHashSet :: default ( ) ;
320330 necessary_generic_params. extend ( receiver_ty. generic_params ( ctx. db ( ) ) ) ;
@@ -346,15 +356,19 @@ impl FunctionBuilder {
346356 params,
347357 ret_type,
348358 should_focus_return_type,
349- needs_pub ,
359+ visibility ,
350360 is_async,
351361 } )
352362 }
353363
354364 fn render ( self , is_method : bool ) -> FunctionTemplate {
355365 let placeholder_expr = make:: ext:: expr_todo ( ) ;
356366 let fn_body = make:: block_expr ( vec ! [ ] , Some ( placeholder_expr) ) ;
357- let visibility = if self . needs_pub { Some ( make:: visibility_pub_crate ( ) ) } else { None } ;
367+ let visibility = match self . visibility {
368+ Visibility :: None => None ,
369+ Visibility :: Crate => Some ( make:: visibility_pub_crate ( ) ) ,
370+ Visibility :: Pub => Some ( make:: visibility_pub ( ) ) ,
371+ } ;
358372 let mut fn_def = make:: fn_ (
359373 visibility,
360374 self . fn_name ,
@@ -527,7 +541,7 @@ impl GeneratedFunctionTarget {
527541/// Computes parameter list for the generated function.
528542fn fn_args (
529543 ctx : & AssistContext < ' _ > ,
530- target_module : hir :: Module ,
544+ target_module : Module ,
531545 call : ast:: CallableExpr ,
532546 necessary_generic_params : & mut FxHashSet < hir:: GenericParam > ,
533547) -> Option < ast:: ParamList > {
@@ -957,13 +971,13 @@ fn fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> Stri
957971
958972fn fn_arg_type (
959973 ctx : & AssistContext < ' _ > ,
960- target_module : hir :: Module ,
974+ target_module : Module ,
961975 fn_arg : & ast:: Expr ,
962976 generic_params : & mut FxHashSet < hir:: GenericParam > ,
963977) -> String {
964978 fn maybe_displayed_type (
965979 ctx : & AssistContext < ' _ > ,
966- target_module : hir :: Module ,
980+ target_module : Module ,
967981 fn_arg : & ast:: Expr ,
968982 generic_params : & mut FxHashSet < hir:: GenericParam > ,
969983 ) -> Option < String > {
@@ -1048,16 +1062,29 @@ fn next_space_for_fn_in_impl(impl_: &ast::Impl) -> Option<GeneratedFunctionTarge
10481062 }
10491063}
10501064
1051- fn module_is_descendant ( module : & hir:: Module , ans : & hir:: Module , ctx : & AssistContext < ' _ > ) -> bool {
1052- if module == ans {
1053- return true ;
1054- }
1055- for c in ans. children ( ctx. sema . db ) {
1056- if module_is_descendant ( module, & c, ctx) {
1057- return true ;
1058- }
1065+ #[ derive( Clone , Copy ) ]
1066+ enum Visibility {
1067+ None ,
1068+ Crate ,
1069+ Pub ,
1070+ }
1071+
1072+ fn calculate_necessary_visibility (
1073+ current_module : Module ,
1074+ target_module : Module ,
1075+ ctx : & AssistContext < ' _ > ,
1076+ ) -> Visibility {
1077+ let db = ctx. db ( ) ;
1078+ let current_module = current_module. nearest_non_block_module ( db) ;
1079+ let target_module = target_module. nearest_non_block_module ( db) ;
1080+
1081+ if target_module. krate ( ) != current_module. krate ( ) {
1082+ Visibility :: Pub
1083+ } else if current_module. path_to_root ( db) . contains ( & target_module) {
1084+ Visibility :: None
1085+ } else {
1086+ Visibility :: Crate
10591087 }
1060- false
10611088}
10621089
10631090// This is never intended to be used as a generic graph strucuture. If there's ever another need of
@@ -2656,4 +2683,79 @@ fn main() {
26562683" ,
26572684 )
26582685 }
2686+
2687+ #[ test]
2688+ fn applicable_in_different_local_crate ( ) {
2689+ check_assist (
2690+ generate_function,
2691+ r"
2692+ //- /lib.rs crate:lib new_source_root:local
2693+ fn dummy() {}
2694+ //- /main.rs crate:main deps:lib new_source_root:local
2695+ fn main() {
2696+ lib::foo$0();
2697+ }
2698+ " ,
2699+ r"
2700+ fn dummy() {}
2701+
2702+ pub fn foo() ${0:-> _} {
2703+ todo!()
2704+ }
2705+ " ,
2706+ ) ;
2707+ }
2708+
2709+ #[ test]
2710+ fn applicable_in_different_local_crate_method ( ) {
2711+ check_assist (
2712+ generate_function,
2713+ r"
2714+ //- /lib.rs crate:lib new_source_root:local
2715+ pub struct S;
2716+ //- /main.rs crate:main deps:lib new_source_root:local
2717+ fn main() {
2718+ lib::S.foo$0();
2719+ }
2720+ " ,
2721+ r"
2722+ pub struct S;
2723+ impl S {
2724+ pub fn foo(&self) ${0:-> _} {
2725+ todo!()
2726+ }
2727+ }
2728+ " ,
2729+ ) ;
2730+ }
2731+
2732+ #[ test]
2733+ fn not_applicable_in_different_library_crate ( ) {
2734+ check_assist_not_applicable (
2735+ generate_function,
2736+ r"
2737+ //- /lib.rs crate:lib new_source_root:library
2738+ fn dummy() {}
2739+ //- /main.rs crate:main deps:lib new_source_root:local
2740+ fn main() {
2741+ lib::foo$0();
2742+ }
2743+ " ,
2744+ ) ;
2745+ }
2746+
2747+ #[ test]
2748+ fn not_applicable_in_different_library_crate_method ( ) {
2749+ check_assist_not_applicable (
2750+ generate_function,
2751+ r"
2752+ //- /lib.rs crate:lib new_source_root:library
2753+ pub struct S;
2754+ //- /main.rs crate:main deps:lib new_source_root:local
2755+ fn main() {
2756+ lib::S.foo$0();
2757+ }
2758+ " ,
2759+ ) ;
2760+ }
26592761}
0 commit comments