aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/assists/src/handlers/qualify_path.rs182
1 files changed, 169 insertions, 13 deletions
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs
index f436bdbbf..d5bc4e574 100644
--- a/crates/assists/src/handlers/qualify_path.rs
+++ b/crates/assists/src/handlers/qualify_path.rs
@@ -56,12 +56,14 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
56 ImportCandidate::QualifierStart(_) => { 56 ImportCandidate::QualifierStart(_) => {
57 mark::hit!(qualify_path_qualifier_start); 57 mark::hit!(qualify_path_qualifier_start);
58 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; 58 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
59 let segment = path.segment()?; 59 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
60 QualifyCandidate::QualifierStart(segment) 60 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
61 } 61 }
62 ImportCandidate::UnqualifiedName(_) => { 62 ImportCandidate::UnqualifiedName(_) => {
63 mark::hit!(qualify_path_unqualified_name); 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 ImportCandidate::TraitAssocItem(_) => { 68 ImportCandidate::TraitAssocItem(_) => {
67 mark::hit!(qualify_path_trait_assoc_item); 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
98enum QualifyCandidate<'db> { 100enum QualifyCandidate<'db> {
99 QualifierStart(ast::PathSegment), 101 QualifierStart(ast::PathSegment, Option<ast::GenericArgList>),
100 UnqualifiedName, 102 UnqualifiedName(Option<ast::GenericArgList>),
101 TraitAssocItem(ast::Path, ast::PathSegment), 103 TraitAssocItem(ast::Path, ast::PathSegment),
102 TraitMethod(&'db RootDatabase, ast::MethodCallExpr), 104 TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
103} 105}
104 106
105impl QualifyCandidate<'_> { 107impl QualifyCandidate<'_> {
106 fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) { 108 fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) {
109 let import = mod_path_to_ast(&import);
107 match self { 110 match self {
108 QualifyCandidate::QualifierStart(segment) => { 111 QualifyCandidate::QualifierStart(segment, generics) => {
109 let import = mod_path_to_ast(&import); 112 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
110 replacer(format!("{}::{}", import, segment)); 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 QualifyCandidate::TraitAssocItem(qualifier, segment) => { 119 QualifyCandidate::TraitAssocItem(qualifier, segment) => {
114 let import = mod_path_to_ast(&import);
115 replacer(format!("<{} as {}>::{}", qualifier, import, segment)); 120 replacer(format!("<{} as {}>::{}", qualifier, import, segment));
116 } 121 }
117 &QualifyCandidate::TraitMethod(db, ref mcall_expr) => { 122 &QualifyCandidate::TraitMethod(db, ref mcall_expr) => {
@@ -124,25 +129,27 @@ impl QualifyCandidate<'_> {
124 db: &RootDatabase, 129 db: &RootDatabase,
125 mcall_expr: &ast::MethodCallExpr, 130 mcall_expr: &ast::MethodCallExpr,
126 mut replacer: impl FnMut(String), 131 mut replacer: impl FnMut(String),
127 import: hir::ModPath, 132 import: ast::Path,
128 item: hir::ItemInNs, 133 item: hir::ItemInNs,
129 ) -> Option<()> { 134 ) -> Option<()> {
130 let receiver = mcall_expr.receiver()?; 135 let receiver = mcall_expr.receiver()?;
131 let trait_method_name = mcall_expr.name_ref()?; 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 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args()); 139 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
133 let trait_ = item_as_trait(item)?; 140 let trait_ = item_as_trait(item)?;
134 let method = find_trait_method(db, trait_, &trait_method_name)?; 141 let method = find_trait_method(db, trait_, &trait_method_name)?;
135 if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) { 142 if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) {
136 let import = mod_path_to_ast(&import);
137 let receiver = match self_access { 143 let receiver = match self_access {
138 hir::Access::Shared => make::expr_ref(receiver, false), 144 hir::Access::Shared => make::expr_ref(receiver, false),
139 hir::Access::Exclusive => make::expr_ref(receiver, true), 145 hir::Access::Exclusive => make::expr_ref(receiver, true),
140 hir::Access::Owned => receiver, 146 hir::Access::Owned => receiver,
141 }; 147 };
142 replacer(format!( 148 replacer(format!(
143 "{}::{}{}", 149 "{}::{}{}{}",
144 import, 150 import,
145 trait_method_name, 151 trait_method_name,
152 generics,
146 match arg_list.clone() { 153 match arg_list.clone() {
147 Some(args) => make::arg_list(iter::once(receiver).chain(args)), 154 Some(args) => make::arg_list(iter::once(receiver).chain(args)),
148 None => make::arg_list(iter::once(receiver)), 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
1062pub mod generic { pub struct Thing<'a, T>(&'a T); }
1063
1064//- /main.rs crate:main deps:dep
1065fn foo() -> Thin<|>g<'static, ()> {}
1066
1067fn main() {}
1068",
1069 r"
1070fn foo() -> dep::generic::Thing<'static, ()> {}
1071
1072fn 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
1083pub mod generic { pub struct Thing<'a, T>(&'a T); }
1084
1085//- /main.rs crate:main deps:dep
1086fn foo() -> Thin<|>g::<'static, ()> {}
1087
1088fn main() {}
1089",
1090 r"
1091fn foo() -> dep::generic::Thing::<'static, ()> {}
1092
1093fn 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}