1
1
// Some ideas for future improvements:
2
2
// - Support replacing aliases which are used in expressions, e.g. `A::new()`.
3
- // - "inline_alias_to_users" assist #10881.
4
3
// - Remove unused aliases if there are no longer any users, see inline_call.rs.
5
4
6
5
use hir:: { HasSource , PathResolution } ;
6
+ use ide_db:: { defs:: Definition , search:: FileReference } ;
7
7
use itertools:: Itertools ;
8
8
use std:: collections:: HashMap ;
9
9
use syntax:: {
@@ -16,6 +16,78 @@ use crate::{
16
16
AssistId , AssistKind ,
17
17
} ;
18
18
19
+ // Assist: inline_type_alias_uses
20
+ //
21
+ // Inline a type alias into all of its uses where possible.
22
+ //
23
+ // ```
24
+ // type $0A = i32;
25
+ // fn id(x: A) -> A {
26
+ // x
27
+ // };
28
+ // fn foo() {
29
+ // let _: A = 3;
30
+ // }
31
+ // ```
32
+ // ->
33
+ // ```
34
+ // type A = i32;
35
+ // fn id(x: i32) -> i32 {
36
+ // x
37
+ // };
38
+ // fn foo() {
39
+ // let _: i32 = 3;
40
+ // }
41
+ pub ( crate ) fn inline_type_alias_uses ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
42
+ let name = ctx. find_node_at_offset :: < ast:: Name > ( ) ?;
43
+ let ast_alias = name. syntax ( ) . parent ( ) . and_then ( ast:: TypeAlias :: cast) ?;
44
+
45
+ let hir_alias = ctx. sema . to_def ( & ast_alias) ?;
46
+ let concrete_type = ast_alias. ty ( ) ?;
47
+
48
+ let usages = Definition :: TypeAlias ( hir_alias) . usages ( & ctx. sema ) ;
49
+ if !usages. at_least_one ( ) {
50
+ return None ;
51
+ }
52
+
53
+ // until this is ok
54
+
55
+ acc. add (
56
+ AssistId ( "inline_type_alias_uses" , AssistKind :: RefactorInline ) ,
57
+ "Inline type alias into all uses" ,
58
+ name. syntax ( ) . text_range ( ) ,
59
+ |builder| {
60
+ let usages = usages. all ( ) ;
61
+
62
+ let mut inline_refs_for_file = |file_id, refs : Vec < FileReference > | {
63
+ builder. edit_file ( file_id) ;
64
+
65
+ let path_types: Vec < ast:: PathType > = refs
66
+ . into_iter ( )
67
+ . filter_map ( |file_ref| match file_ref. name {
68
+ ast:: NameLike :: NameRef ( path_type) => {
69
+ path_type. syntax ( ) . ancestors ( ) . nth ( 3 ) . and_then ( ast:: PathType :: cast)
70
+ }
71
+ _ => None ,
72
+ } )
73
+ . collect ( ) ;
74
+
75
+ for ( target, replacement) in path_types. into_iter ( ) . filter_map ( |path_type| {
76
+ let replacement = inline ( & ast_alias, & path_type) ?. to_text ( & concrete_type) ;
77
+ let target = path_type. syntax ( ) . text_range ( ) ;
78
+ Some ( ( target, replacement) )
79
+ } ) {
80
+ builder. replace ( target, replacement) ;
81
+ }
82
+ } ;
83
+
84
+ for ( file_id, refs) in usages. into_iter ( ) {
85
+ inline_refs_for_file ( file_id, refs) ;
86
+ }
87
+ } ,
88
+ )
89
+ }
90
+
19
91
// Assist: inline_type_alias
20
92
//
21
93
// Replace a type alias with its concrete type.
@@ -36,11 +108,6 @@ use crate::{
36
108
// }
37
109
// ```
38
110
pub ( crate ) fn inline_type_alias ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
39
- enum Replacement {
40
- Generic { lifetime_map : LifetimeMap , const_and_type_map : ConstAndTypeMap } ,
41
- Plain ,
42
- }
43
-
44
111
let alias_instance = ctx. find_node_at_offset :: < ast:: PathType > ( ) ?;
45
112
let concrete_type;
46
113
let replacement;
@@ -59,23 +126,7 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
59
126
_ => {
60
127
let alias = get_type_alias ( & ctx, & alias_instance) ?;
61
128
concrete_type = alias. ty ( ) ?;
62
-
63
- replacement = if let Some ( alias_generics) = alias. generic_param_list ( ) {
64
- if alias_generics. generic_params ( ) . next ( ) . is_none ( ) {
65
- cov_mark:: hit!( no_generics_params) ;
66
- return None ;
67
- }
68
-
69
- let instance_args =
70
- alias_instance. syntax ( ) . descendants ( ) . find_map ( ast:: GenericArgList :: cast) ;
71
-
72
- Replacement :: Generic {
73
- lifetime_map : LifetimeMap :: new ( & instance_args, & alias_generics) ?,
74
- const_and_type_map : ConstAndTypeMap :: new ( & instance_args, & alias_generics) ?,
75
- }
76
- } else {
77
- Replacement :: Plain
78
- } ;
129
+ replacement = inline ( & alias, & alias_instance) ?;
79
130
}
80
131
}
81
132
@@ -85,19 +136,45 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
85
136
AssistId ( "inline_type_alias" , AssistKind :: RefactorInline ) ,
86
137
"Inline type alias" ,
87
138
target,
88
- |builder| {
89
- let replacement_text = match replacement {
90
- Replacement :: Generic { lifetime_map, const_and_type_map } => {
91
- create_replacement ( & lifetime_map, & const_and_type_map, & concrete_type)
92
- }
93
- Replacement :: Plain => concrete_type. to_string ( ) ,
94
- } ;
95
-
96
- builder. replace ( target, replacement_text) ;
97
- } ,
139
+ |builder| builder. replace ( target, replacement. to_text ( & concrete_type) ) ,
98
140
)
99
141
}
100
142
143
+ impl Replacement {
144
+ fn to_text ( & self , concrete_type : & ast:: Type ) -> String {
145
+ match self {
146
+ Replacement :: Generic { lifetime_map, const_and_type_map } => {
147
+ create_replacement ( & lifetime_map, & const_and_type_map, & concrete_type)
148
+ }
149
+ Replacement :: Plain => concrete_type. to_string ( ) ,
150
+ }
151
+ }
152
+ }
153
+
154
+ enum Replacement {
155
+ Generic { lifetime_map : LifetimeMap , const_and_type_map : ConstAndTypeMap } ,
156
+ Plain ,
157
+ }
158
+
159
+ fn inline ( alias_def : & ast:: TypeAlias , alias_instance : & ast:: PathType ) -> Option < Replacement > {
160
+ let repl = if let Some ( alias_generics) = alias_def. generic_param_list ( ) {
161
+ if alias_generics. generic_params ( ) . next ( ) . is_none ( ) {
162
+ cov_mark:: hit!( no_generics_params) ;
163
+ return None ;
164
+ }
165
+ let instance_args =
166
+ alias_instance. syntax ( ) . descendants ( ) . find_map ( ast:: GenericArgList :: cast) ;
167
+
168
+ Replacement :: Generic {
169
+ lifetime_map : LifetimeMap :: new ( & instance_args, & alias_generics) ?,
170
+ const_and_type_map : ConstAndTypeMap :: new ( & instance_args, & alias_generics) ?,
171
+ }
172
+ } else {
173
+ Replacement :: Plain
174
+ } ;
175
+ Some ( repl)
176
+ }
177
+
101
178
struct LifetimeMap ( HashMap < String , ast:: Lifetime > ) ;
102
179
103
180
impl LifetimeMap {
@@ -835,4 +912,90 @@ trait Tr {
835
912
"# ,
836
913
) ;
837
914
}
915
+
916
+ mod inline_type_alias_uses {
917
+ use crate :: { handlers:: inline_type_alias:: inline_type_alias_uses, tests:: check_assist} ;
918
+
919
+ #[ test]
920
+ fn inline_uses ( ) {
921
+ check_assist (
922
+ inline_type_alias_uses,
923
+ r#"
924
+ type $0A = u32;
925
+
926
+ fn foo() {
927
+ let _: A = 3;
928
+ let _: A = 4;
929
+ }
930
+ "# ,
931
+ r#"
932
+ type A = u32;
933
+
934
+ fn foo() {
935
+ let _: u32 = 3;
936
+ let _: u32 = 4;
937
+ }
938
+ "# ,
939
+ ) ;
940
+ }
941
+
942
+ #[ test]
943
+ fn inline_uses_across_files ( ) {
944
+ check_assist (
945
+ inline_type_alias_uses,
946
+ r#"
947
+ //- /lib.rs
948
+ mod foo;
949
+ type $0T<E> = Vec<E>;
950
+ fn f() -> T<&str> {
951
+ vec!["hello"]
952
+ }
953
+
954
+ //- /foo.rs
955
+ use super::T;
956
+ fn foo() {
957
+ let _: T<i8> = Vec::new();
958
+ }
959
+ "# ,
960
+ r#"
961
+ //- /lib.rs
962
+ mod foo;
963
+ type T<E> = Vec<E>;
964
+ fn f() -> Vec<&str> {
965
+ vec!["hello"]
966
+ }
967
+
968
+ //- /foo.rs
969
+ use super::T;
970
+ fn foo() {
971
+ let _: Vec<i8> = Vec::new();
972
+ }
973
+ "# ,
974
+ ) ;
975
+ }
976
+
977
+ #[ test]
978
+ fn inline_uses_across_files_2 ( ) {
979
+ check_assist (
980
+ inline_type_alias_uses,
981
+ r#"
982
+ //- /lib.rs
983
+ mod foo;
984
+ type $0I = i32;
985
+
986
+ //- /foo.rs
987
+ use super::I;
988
+ fn foo() {
989
+ let _: I = 0;
990
+ }
991
+ "# ,
992
+ r#"
993
+ use super::I;
994
+ fn foo() {
995
+ let _: i32 = 0;
996
+ }
997
+ "# ,
998
+ ) ;
999
+ }
1000
+ }
838
1001
}
0 commit comments