@@ -43,16 +43,12 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
43
43
return None ;
44
44
}
45
45
46
- let target_module = if let Some ( qualifier) = path. qualifier ( ) {
47
- if let Some ( hir:: PathResolution :: Def ( hir:: ModuleDef :: Module ( module) ) ) =
48
- ctx. sema . resolve_path ( & qualifier)
49
- {
50
- Some ( module. definition_source ( ctx. sema . db ) )
51
- } else {
52
- return None ;
53
- }
54
- } else {
55
- None
46
+ let target_module = match path. qualifier ( ) {
47
+ Some ( qualifier) => match ctx. sema . resolve_path ( & qualifier) {
48
+ Some ( hir:: PathResolution :: Def ( hir:: ModuleDef :: Module ( module) ) ) => Some ( module) ,
49
+ _ => return None ,
50
+ } ,
51
+ None => None ,
56
52
} ;
57
53
58
54
let function_builder = FunctionBuilder :: from_call ( & ctx, & call, & path, target_module) ?;
@@ -83,25 +79,29 @@ struct FunctionBuilder {
83
79
}
84
80
85
81
impl FunctionBuilder {
86
- /// Prepares a generated function that matches `call` in `generate_in`
87
- /// (or as close to `call` as possible, if `generate_in` is `None`)
82
+ /// Prepares a generated function that matches `call`.
83
+ /// The function is generated in `target_module` or next to `call`
88
84
fn from_call (
89
85
ctx : & AssistContext ,
90
86
call : & ast:: CallExpr ,
91
87
path : & ast:: Path ,
92
- target_module : Option < hir:: InFile < hir :: ModuleSource > > ,
88
+ target_module : Option < hir:: Module > ,
93
89
) -> Option < Self > {
94
- let needs_pub = target_module. is_some ( ) ;
95
90
let mut file = ctx. frange . file_id ;
96
- let target = if let Some ( target_module) = target_module {
97
- let ( in_file, target) = next_space_for_fn_in_module ( ctx. sema . db , target_module) ?;
98
- file = in_file;
99
- target
100
- } else {
101
- next_space_for_fn_after_call_site ( & call) ?
91
+ let target = match & target_module {
92
+ Some ( target_module) => {
93
+ let module_source = target_module. definition_source ( ctx. db ) ;
94
+ let ( in_file, target) = next_space_for_fn_in_module ( ctx. sema . db , & module_source) ?;
95
+ file = in_file;
96
+ target
97
+ }
98
+ None => next_space_for_fn_after_call_site ( & call) ?,
102
99
} ;
100
+ let needs_pub = target_module. is_some ( ) ;
101
+ let target_module = target_module. or_else ( || ctx. sema . scope ( target. syntax ( ) ) . module ( ) ) ?;
103
102
let fn_name = fn_name ( & path) ?;
104
- let ( type_params, params) = fn_args ( ctx, & call) ?;
103
+ let ( type_params, params) = fn_args ( ctx, target_module, & call) ?;
104
+
105
105
Some ( Self { target, fn_name, type_params, params, file, needs_pub } )
106
106
}
107
107
@@ -144,6 +144,15 @@ enum GeneratedFunctionTarget {
144
144
InEmptyItemList ( ast:: ItemList ) ,
145
145
}
146
146
147
+ impl GeneratedFunctionTarget {
148
+ fn syntax ( & self ) -> & SyntaxNode {
149
+ match self {
150
+ GeneratedFunctionTarget :: BehindItem ( it) => it,
151
+ GeneratedFunctionTarget :: InEmptyItemList ( it) => it. syntax ( ) ,
152
+ }
153
+ }
154
+ }
155
+
147
156
fn fn_name ( call : & ast:: Path ) -> Option < ast:: Name > {
148
157
let name = call. segment ( ) ?. syntax ( ) . to_string ( ) ;
149
158
Some ( ast:: make:: name ( & name) )
@@ -152,17 +161,17 @@ fn fn_name(call: &ast::Path) -> Option<ast::Name> {
152
161
/// Computes the type variables and arguments required for the generated function
153
162
fn fn_args (
154
163
ctx : & AssistContext ,
164
+ target_module : hir:: Module ,
155
165
call : & ast:: CallExpr ,
156
166
) -> Option < ( Option < ast:: TypeParamList > , ast:: ParamList ) > {
157
167
let mut arg_names = Vec :: new ( ) ;
158
168
let mut arg_types = Vec :: new ( ) ;
159
169
for arg in call. arg_list ( ) ?. args ( ) {
160
- let arg_name = match fn_arg_name ( & arg) {
170
+ arg_names . push ( match fn_arg_name ( & arg) {
161
171
Some ( name) => name,
162
172
None => String :: from ( "arg" ) ,
163
- } ;
164
- arg_names. push ( arg_name) ;
165
- arg_types. push ( match fn_arg_type ( ctx, & arg) {
173
+ } ) ;
174
+ arg_types. push ( match fn_arg_type ( ctx, target_module, & arg) {
166
175
Some ( ty) => ty,
167
176
None => String :: from ( "()" ) ,
168
177
} ) ;
@@ -218,12 +227,21 @@ fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
218
227
}
219
228
}
220
229
221
- fn fn_arg_type ( ctx : & AssistContext , fn_arg : & ast:: Expr ) -> Option < String > {
230
+ fn fn_arg_type (
231
+ ctx : & AssistContext ,
232
+ target_module : hir:: Module ,
233
+ fn_arg : & ast:: Expr ,
234
+ ) -> Option < String > {
222
235
let ty = ctx. sema . type_of_expr ( fn_arg) ?;
223
236
if ty. is_unknown ( ) {
224
237
return None ;
225
238
}
226
- Some ( ty. display ( ctx. sema . db ) . to_string ( ) )
239
+
240
+ if let Ok ( rendered) = ty. display_source_code ( ctx. db , target_module. into ( ) ) {
241
+ Some ( rendered)
242
+ } else {
243
+ None
244
+ }
227
245
}
228
246
229
247
/// Returns the position inside the current mod or file
@@ -252,10 +270,10 @@ fn next_space_for_fn_after_call_site(expr: &ast::CallExpr) -> Option<GeneratedFu
252
270
253
271
fn next_space_for_fn_in_module (
254
272
db : & dyn hir:: db:: AstDatabase ,
255
- module : hir:: InFile < hir:: ModuleSource > ,
273
+ module_source : & hir:: InFile < hir:: ModuleSource > ,
256
274
) -> Option < ( FileId , GeneratedFunctionTarget ) > {
257
- let file = module . file_id . original_file ( db) ;
258
- let assist_item = match module . value {
275
+ let file = module_source . file_id . original_file ( db) ;
276
+ let assist_item = match & module_source . value {
259
277
hir:: ModuleSource :: SourceFile ( it) => {
260
278
if let Some ( last_item) = it. items ( ) . last ( ) {
261
279
GeneratedFunctionTarget :: BehindItem ( last_item. syntax ( ) . clone ( ) )
@@ -599,8 +617,33 @@ fn bar(foo: impl Foo) {
599
617
}
600
618
601
619
#[ test]
602
- #[ ignore]
603
- // FIXME print paths properly to make this test pass
620
+ fn borrowed_arg ( ) {
621
+ check_assist (
622
+ add_function,
623
+ r"
624
+ struct Baz;
625
+ fn baz() -> Baz { todo!() }
626
+
627
+ fn foo() {
628
+ bar<|>(&baz())
629
+ }
630
+ " ,
631
+ r"
632
+ struct Baz;
633
+ fn baz() -> Baz { todo!() }
634
+
635
+ fn foo() {
636
+ bar(&baz())
637
+ }
638
+
639
+ fn bar(baz: &Baz) {
640
+ <|>todo!()
641
+ }
642
+ " ,
643
+ )
644
+ }
645
+
646
+ #[ test]
604
647
fn add_function_with_qualified_path_arg ( ) {
605
648
check_assist (
606
649
add_function,
@@ -609,25 +652,21 @@ mod Baz {
609
652
pub struct Bof;
610
653
pub fn baz() -> Bof { Bof }
611
654
}
612
- mod Foo {
613
- fn foo() {
614
- <|>bar(super::Baz::baz())
615
- }
655
+ fn foo() {
656
+ <|>bar(Baz::baz())
616
657
}
617
658
" ,
618
659
r"
619
660
mod Baz {
620
661
pub struct Bof;
621
662
pub fn baz() -> Bof { Bof }
622
663
}
623
- mod Foo {
624
- fn foo() {
625
- bar(super::Baz::baz())
626
- }
664
+ fn foo() {
665
+ bar(Baz::baz())
666
+ }
627
667
628
- fn bar(baz: super::Baz::Bof) {
629
- <|>todo!()
630
- }
668
+ fn bar(baz: Baz::Bof) {
669
+ <|>todo!()
631
670
}
632
671
" ,
633
672
)
@@ -808,6 +847,40 @@ fn foo() {
808
847
)
809
848
}
810
849
850
+ #[ test]
851
+ #[ ignore]
852
+ // Ignored until local imports are supported.
853
+ // See https://github.com/rust-analyzer/rust-analyzer/issues/1165
854
+ fn qualified_path_uses_correct_scope ( ) {
855
+ check_assist (
856
+ add_function,
857
+ "
858
+ mod foo {
859
+ pub struct Foo;
860
+ }
861
+ fn bar() {
862
+ use foo::Foo;
863
+ let foo = Foo;
864
+ baz<|>(foo)
865
+ }
866
+ " ,
867
+ "
868
+ mod foo {
869
+ pub struct Foo;
870
+ }
871
+ fn bar() {
872
+ use foo::Foo;
873
+ let foo = Foo;
874
+ baz(foo)
875
+ }
876
+
877
+ fn baz(foo: foo::Foo) {
878
+ <|>todo!()
879
+ }
880
+ " ,
881
+ )
882
+ }
883
+
811
884
#[ test]
812
885
fn add_function_in_module_containing_other_items ( ) {
813
886
check_assist (
@@ -919,21 +992,6 @@ fn bar(baz: ()) {}
919
992
)
920
993
}
921
994
922
- #[ test]
923
- fn add_function_not_applicable_if_function_path_not_singleton ( ) {
924
- // In the future this assist could be extended to generate functions
925
- // if the path is in the same crate (or even the same workspace).
926
- // For the beginning, I think this is fine.
927
- check_assist_not_applicable (
928
- add_function,
929
- r"
930
- fn foo() {
931
- other_crate::bar<|>();
932
- }
933
- " ,
934
- )
935
- }
936
-
937
995
#[ test]
938
996
#[ ignore]
939
997
fn create_method_with_no_args ( ) {
0 commit comments