@@ -56,12 +56,14 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
5656 ImportCandidate :: QualifierStart ( _) => {
5757 mark:: hit!( qualify_path_qualifier_start) ;
5858 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 ( ) )
6161 }
6262 ImportCandidate :: UnqualifiedName ( _) => {
6363 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)
6567 }
6668 ImportCandidate :: TraitAssocItem ( _) => {
6769 mark:: hit!( qualify_path_trait_assoc_item) ;
@@ -96,22 +98,25 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
9698}
9799
98100enum QualifyCandidate < ' db > {
99- QualifierStart ( ast:: PathSegment ) ,
100- UnqualifiedName ,
101+ QualifierStart ( ast:: PathSegment , Option < ast :: GenericArgList > ) ,
102+ UnqualifiedName ( Option < ast :: GenericArgList > ) ,
101103 TraitAssocItem ( ast:: Path , ast:: PathSegment ) ,
102104 TraitMethod ( & ' db RootDatabase , ast:: MethodCallExpr ) ,
103105}
104106
105107impl QualifyCandidate < ' _ > {
106108 fn qualify ( & self , mut replacer : impl FnMut ( String ) , import : hir:: ModPath , item : hir:: ItemInNs ) {
109+ let import = mod_path_to_ast ( & import) ;
107110 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) ) ;
111118 }
112- QualifyCandidate :: UnqualifiedName => replacer ( mod_path_to_ast ( & import) . to_string ( ) ) ,
113119 QualifyCandidate :: TraitAssocItem ( qualifier, segment) => {
114- let import = mod_path_to_ast ( & import) ;
115120 replacer ( format ! ( "<{} as {}>::{}" , qualifier, import, segment) ) ;
116121 }
117122 & QualifyCandidate :: TraitMethod ( db, ref mcall_expr) => {
@@ -124,25 +129,27 @@ impl QualifyCandidate<'_> {
124129 db : & RootDatabase ,
125130 mcall_expr : & ast:: MethodCallExpr ,
126131 mut replacer : impl FnMut ( String ) ,
127- import : hir :: ModPath ,
132+ import : ast :: Path ,
128133 item : hir:: ItemInNs ,
129134 ) -> Option < ( ) > {
130135 let receiver = mcall_expr. receiver ( ) ?;
131136 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) ;
132139 let arg_list = mcall_expr. arg_list ( ) . map ( |arg_list| arg_list. args ( ) ) ;
133140 let trait_ = item_as_trait ( item) ?;
134141 let method = find_trait_method ( db, trait_, & trait_method_name) ?;
135142 if let Some ( self_access) = method. self_param ( db) . map ( |sp| sp. access ( db) ) {
136- let import = mod_path_to_ast ( & import) ;
137143 let receiver = match self_access {
138144 hir:: Access :: Shared => make:: expr_ref ( receiver, false ) ,
139145 hir:: Access :: Exclusive => make:: expr_ref ( receiver, true ) ,
140146 hir:: Access :: Owned => receiver,
141147 } ;
142148 replacer ( format ! (
143- "{}::{}{}" ,
149+ "{}::{}{}{} " ,
144150 import,
145151 trait_method_name,
152+ generics,
146153 match arg_list. clone( ) {
147154 Some ( args) => make:: arg_list( iter:: once( receiver) . chain( args) ) ,
148155 None => make:: arg_list( iter:: once( receiver) ) ,
@@ -1045,4 +1052,153 @@ fn main() {
10451052" ,
10461053 ) ;
10471054 }
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+ }
10481204}
0 commit comments