@@ -5,6 +5,7 @@ use ide_db::{
5
5
base_db:: FileId ,
6
6
defs:: { Definition , NameRefClass } ,
7
7
famous_defs:: FamousDefs ,
8
+ helpers:: is_editable_crate,
8
9
path_transform:: PathTransform ,
9
10
FxHashMap , FxHashSet , RootDatabase , SnippetCap ,
10
11
} ;
@@ -65,6 +66,13 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
65
66
let fn_name = & * name_ref. text ( ) ;
66
67
let TargetInfo { target_module, adt_name, target, file, insert_offset } =
67
68
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
+
68
76
let function_builder = FunctionBuilder :: from_call ( ctx, & call, fn_name, target_module, target) ?;
69
77
let text_range = call. syntax ( ) . text_range ( ) ;
70
78
let label = format ! ( "Generate {} function" , function_builder. fn_name) ;
@@ -141,12 +149,11 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
141
149
let receiver_ty = ctx. sema . type_of_expr ( & call. receiver ( ) ?) ?. original ( ) . strip_references ( ) ;
142
150
let adt = receiver_ty. as_adt ( ) ?;
143
151
144
- let current_module = ctx. sema . scope ( call. syntax ( ) ) ?. module ( ) ;
145
152
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 ( ) ) {
148
154
return None ;
149
155
}
156
+
150
157
let ( impl_, file) = get_adt_source ( ctx, & adt, fn_name. text ( ) . as_str ( ) ) ?;
151
158
let ( target, insert_offset) = get_method_target ( ctx, & impl_, & adt) ?;
152
159
@@ -253,7 +260,7 @@ struct FunctionBuilder {
253
260
params : ast:: ParamList ,
254
261
ret_type : Option < ast:: RetType > ,
255
262
should_focus_return_type : bool ,
256
- needs_pub : bool ,
263
+ visibility : Visibility ,
257
264
is_async : bool ,
258
265
}
259
266
@@ -264,12 +271,14 @@ impl FunctionBuilder {
264
271
ctx : & AssistContext < ' _ > ,
265
272
call : & ast:: CallExpr ,
266
273
fn_name : & str ,
267
- target_module : Option < hir :: Module > ,
274
+ target_module : Option < Module > ,
268
275
target : GeneratedFunctionTarget ,
269
276
) -> Option < Self > {
270
- let needs_pub = target_module. is_some ( ) ;
271
277
let target_module =
272
278
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) ;
273
282
let fn_name = make:: name ( fn_name) ;
274
283
let mut necessary_generic_params = FxHashSet :: default ( ) ;
275
284
let params = fn_args (
@@ -300,7 +309,7 @@ impl FunctionBuilder {
300
309
params,
301
310
ret_type,
302
311
should_focus_return_type,
303
- needs_pub ,
312
+ visibility ,
304
313
is_async,
305
314
} )
306
315
}
@@ -313,8 +322,9 @@ impl FunctionBuilder {
313
322
target_module : Module ,
314
323
target : GeneratedFunctionTarget ,
315
324
) -> 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
+
318
328
let fn_name = make:: name ( & name. text ( ) ) ;
319
329
let mut necessary_generic_params = FxHashSet :: default ( ) ;
320
330
necessary_generic_params. extend ( receiver_ty. generic_params ( ctx. db ( ) ) ) ;
@@ -346,15 +356,19 @@ impl FunctionBuilder {
346
356
params,
347
357
ret_type,
348
358
should_focus_return_type,
349
- needs_pub ,
359
+ visibility ,
350
360
is_async,
351
361
} )
352
362
}
353
363
354
364
fn render ( self , is_method : bool ) -> FunctionTemplate {
355
365
let placeholder_expr = make:: ext:: expr_todo ( ) ;
356
366
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
+ } ;
358
372
let mut fn_def = make:: fn_ (
359
373
visibility,
360
374
self . fn_name ,
@@ -527,7 +541,7 @@ impl GeneratedFunctionTarget {
527
541
/// Computes parameter list for the generated function.
528
542
fn fn_args (
529
543
ctx : & AssistContext < ' _ > ,
530
- target_module : hir :: Module ,
544
+ target_module : Module ,
531
545
call : ast:: CallableExpr ,
532
546
necessary_generic_params : & mut FxHashSet < hir:: GenericParam > ,
533
547
) -> Option < ast:: ParamList > {
@@ -957,13 +971,13 @@ fn fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> Stri
957
971
958
972
fn fn_arg_type (
959
973
ctx : & AssistContext < ' _ > ,
960
- target_module : hir :: Module ,
974
+ target_module : Module ,
961
975
fn_arg : & ast:: Expr ,
962
976
generic_params : & mut FxHashSet < hir:: GenericParam > ,
963
977
) -> String {
964
978
fn maybe_displayed_type (
965
979
ctx : & AssistContext < ' _ > ,
966
- target_module : hir :: Module ,
980
+ target_module : Module ,
967
981
fn_arg : & ast:: Expr ,
968
982
generic_params : & mut FxHashSet < hir:: GenericParam > ,
969
983
) -> Option < String > {
@@ -1048,16 +1062,29 @@ fn next_space_for_fn_in_impl(impl_: &ast::Impl) -> Option<GeneratedFunctionTarge
1048
1062
}
1049
1063
}
1050
1064
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
1059
1087
}
1060
- false
1061
1088
}
1062
1089
1063
1090
// 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() {
2656
2683
" ,
2657
2684
)
2658
2685
}
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
+ }
2659
2761
}
0 commit comments