@@ -56,12 +56,14 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
56
56
ImportCandidate :: QualifierStart ( _) => {
57
57
mark:: hit!( qualify_path_qualifier_start) ;
58
58
let path = ast:: Path :: cast ( import_assets. syntax_under_caret ( ) . clone ( ) ) ?;
59
- let segment = path. segment ( ) ?;
60
- QualifyCandidate :: QualifierStart ( segment)
59
+ let ( prev_segment , segment) = ( path. qualifier ( ) ? . segment ( ) ?, path . segment ( ) ? ) ;
60
+ QualifyCandidate :: QualifierStart ( segment, prev_segment . generic_arg_list ( ) )
61
61
}
62
62
ImportCandidate :: UnqualifiedName ( _) => {
63
63
mark:: hit!( qualify_path_unqualified_name) ;
64
- QualifyCandidate :: UnqualifiedName
64
+ let path = ast:: Path :: cast ( import_assets. syntax_under_caret ( ) . clone ( ) ) ?;
65
+ let generics = path. segment ( ) ?. generic_arg_list ( ) ;
66
+ QualifyCandidate :: UnqualifiedName ( generics)
65
67
}
66
68
ImportCandidate :: TraitAssocItem ( _) => {
67
69
mark:: hit!( qualify_path_trait_assoc_item) ;
@@ -96,22 +98,25 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
96
98
}
97
99
98
100
enum QualifyCandidate < ' db > {
99
- QualifierStart ( ast:: PathSegment ) ,
100
- UnqualifiedName ,
101
+ QualifierStart ( ast:: PathSegment , Option < ast :: GenericArgList > ) ,
102
+ UnqualifiedName ( Option < ast :: GenericArgList > ) ,
101
103
TraitAssocItem ( ast:: Path , ast:: PathSegment ) ,
102
104
TraitMethod ( & ' db RootDatabase , ast:: MethodCallExpr ) ,
103
105
}
104
106
105
107
impl QualifyCandidate < ' _ > {
106
108
fn qualify ( & self , mut replacer : impl FnMut ( String ) , import : hir:: ModPath , item : hir:: ItemInNs ) {
109
+ let import = mod_path_to_ast ( & import) ;
107
110
match self {
108
- QualifyCandidate :: QualifierStart ( segment) => {
109
- let import = mod_path_to_ast ( & import) ;
110
- replacer ( format ! ( "{}::{}" , import, segment) ) ;
111
+ QualifyCandidate :: QualifierStart ( segment, generics) => {
112
+ let generics = generics. as_ref ( ) . map_or_else ( String :: new, ToString :: to_string) ;
113
+ replacer ( format ! ( "{}{}::{}" , import, generics, segment) ) ;
114
+ }
115
+ QualifyCandidate :: UnqualifiedName ( generics) => {
116
+ let generics = generics. as_ref ( ) . map_or_else ( String :: new, ToString :: to_string) ;
117
+ replacer ( format ! ( "{}{}" , import. to_string( ) , generics) ) ;
111
118
}
112
- QualifyCandidate :: UnqualifiedName => replacer ( mod_path_to_ast ( & import) . to_string ( ) ) ,
113
119
QualifyCandidate :: TraitAssocItem ( qualifier, segment) => {
114
- let import = mod_path_to_ast ( & import) ;
115
120
replacer ( format ! ( "<{} as {}>::{}" , qualifier, import, segment) ) ;
116
121
}
117
122
& QualifyCandidate :: TraitMethod ( db, ref mcall_expr) => {
@@ -124,25 +129,27 @@ impl QualifyCandidate<'_> {
124
129
db : & RootDatabase ,
125
130
mcall_expr : & ast:: MethodCallExpr ,
126
131
mut replacer : impl FnMut ( String ) ,
127
- import : hir :: ModPath ,
132
+ import : ast :: Path ,
128
133
item : hir:: ItemInNs ,
129
134
) -> Option < ( ) > {
130
135
let receiver = mcall_expr. receiver ( ) ?;
131
136
let trait_method_name = mcall_expr. name_ref ( ) ?;
137
+ let generics =
138
+ mcall_expr. generic_arg_list ( ) . as_ref ( ) . map_or_else ( String :: new, ToString :: to_string) ;
132
139
let arg_list = mcall_expr. arg_list ( ) . map ( |arg_list| arg_list. args ( ) ) ;
133
140
let trait_ = item_as_trait ( item) ?;
134
141
let method = find_trait_method ( db, trait_, & trait_method_name) ?;
135
142
if let Some ( self_access) = method. self_param ( db) . map ( |sp| sp. access ( db) ) {
136
- let import = mod_path_to_ast ( & import) ;
137
143
let receiver = match self_access {
138
144
hir:: Access :: Shared => make:: expr_ref ( receiver, false ) ,
139
145
hir:: Access :: Exclusive => make:: expr_ref ( receiver, true ) ,
140
146
hir:: Access :: Owned => receiver,
141
147
} ;
142
148
replacer ( format ! (
143
- "{}::{}{}" ,
149
+ "{}::{}{}{} " ,
144
150
import,
145
151
trait_method_name,
152
+ generics,
146
153
match arg_list. clone( ) {
147
154
Some ( args) => make:: arg_list( iter:: once( receiver) . chain( args) ) ,
148
155
None => make:: arg_list( iter:: once( receiver) ) ,
@@ -1045,4 +1052,153 @@ fn main() {
1045
1052
" ,
1046
1053
) ;
1047
1054
}
1055
+
1056
+ #[ test]
1057
+ fn keep_generic_annotations ( ) {
1058
+ check_assist (
1059
+ qualify_path,
1060
+ r"
1061
+ //- /lib.rs crate:dep
1062
+ pub mod generic { pub struct Thing<'a, T>(&'a T); }
1063
+
1064
+ //- /main.rs crate:main deps:dep
1065
+ fn foo() -> Thin<|>g<'static, ()> {}
1066
+
1067
+ fn main() {}
1068
+ " ,
1069
+ r"
1070
+ fn foo() -> dep::generic::Thing<'static, ()> {}
1071
+
1072
+ fn main() {}
1073
+ " ,
1074
+ ) ;
1075
+ }
1076
+
1077
+ #[ test]
1078
+ fn keep_generic_annotations_leading_colon ( ) {
1079
+ check_assist (
1080
+ qualify_path,
1081
+ r"
1082
+ //- /lib.rs crate:dep
1083
+ pub mod generic { pub struct Thing<'a, T>(&'a T); }
1084
+
1085
+ //- /main.rs crate:main deps:dep
1086
+ fn foo() -> Thin<|>g::<'static, ()> {}
1087
+
1088
+ fn main() {}
1089
+ " ,
1090
+ r"
1091
+ fn foo() -> dep::generic::Thing::<'static, ()> {}
1092
+
1093
+ fn main() {}
1094
+ " ,
1095
+ ) ;
1096
+ }
1097
+
1098
+ #[ test]
1099
+ fn associated_struct_const_generic ( ) {
1100
+ check_assist (
1101
+ qualify_path,
1102
+ r"
1103
+ mod test_mod {
1104
+ pub struct TestStruct<T> {}
1105
+ impl<T> TestStruct<T> {
1106
+ const TEST_CONST: u8 = 42;
1107
+ }
1108
+ }
1109
+
1110
+ fn main() {
1111
+ TestStruct::<()>::TEST_CONST<|>
1112
+ }
1113
+ " ,
1114
+ r"
1115
+ mod test_mod {
1116
+ pub struct TestStruct<T> {}
1117
+ impl<T> TestStruct<T> {
1118
+ const TEST_CONST: u8 = 42;
1119
+ }
1120
+ }
1121
+
1122
+ fn main() {
1123
+ test_mod::TestStruct::<()>::TEST_CONST
1124
+ }
1125
+ " ,
1126
+ ) ;
1127
+ }
1128
+
1129
+ #[ test]
1130
+ fn associated_trait_const_generic ( ) {
1131
+ check_assist (
1132
+ qualify_path,
1133
+ r"
1134
+ mod test_mod {
1135
+ pub trait TestTrait {
1136
+ const TEST_CONST: u8;
1137
+ }
1138
+ pub struct TestStruct<T> {}
1139
+ impl<T> TestTrait for TestStruct<T> {
1140
+ const TEST_CONST: u8 = 42;
1141
+ }
1142
+ }
1143
+
1144
+ fn main() {
1145
+ test_mod::TestStruct::<()>::TEST_CONST<|>
1146
+ }
1147
+ " ,
1148
+ r"
1149
+ mod test_mod {
1150
+ pub trait TestTrait {
1151
+ const TEST_CONST: u8;
1152
+ }
1153
+ pub struct TestStruct<T> {}
1154
+ impl<T> TestTrait for TestStruct<T> {
1155
+ const TEST_CONST: u8 = 42;
1156
+ }
1157
+ }
1158
+
1159
+ fn main() {
1160
+ <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST
1161
+ }
1162
+ " ,
1163
+ ) ;
1164
+ }
1165
+
1166
+ #[ test]
1167
+ fn trait_method_generic ( ) {
1168
+ check_assist (
1169
+ qualify_path,
1170
+ r"
1171
+ mod test_mod {
1172
+ pub trait TestTrait {
1173
+ fn test_method<T>(&self);
1174
+ }
1175
+ pub struct TestStruct {}
1176
+ impl TestTrait for TestStruct {
1177
+ fn test_method<T>(&self) {}
1178
+ }
1179
+ }
1180
+
1181
+ fn main() {
1182
+ let test_struct = test_mod::TestStruct {};
1183
+ test_struct.test_meth<|>od::<()>()
1184
+ }
1185
+ " ,
1186
+ r"
1187
+ mod test_mod {
1188
+ pub trait TestTrait {
1189
+ fn test_method<T>(&self);
1190
+ }
1191
+ pub struct TestStruct {}
1192
+ impl TestTrait for TestStruct {
1193
+ fn test_method<T>(&self) {}
1194
+ }
1195
+ }
1196
+
1197
+ fn main() {
1198
+ let test_struct = test_mod::TestStruct {};
1199
+ test_mod::TestTrait::test_method::<()>(&test_struct)
1200
+ }
1201
+ " ,
1202
+ ) ;
1203
+ }
1048
1204
}
0 commit comments