Skip to content

Commit fe8643b

Browse files
committed
Add ide-assist; Generate AsRef impl from Borrow
1 parent cf969d2 commit fe8643b

File tree

3 files changed

+315
-0
lines changed

3 files changed

+315
-0
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
use syntax::ast::edit_in_place::Indent;
2+
use syntax::ast::make;
3+
use syntax::ast::{self, AstNode, HasName};
4+
use syntax::ted;
5+
6+
use crate::{AssistContext, AssistId, Assists};
7+
8+
// Assist: generate_asref_impl_from_borrow
9+
//
10+
// Generate `AsRef` implement from `Borrow`.
11+
//
12+
// ```
13+
// struct Foo<T>(T);
14+
//
15+
// impl<T> $0Borrow<T> for Foo<T> {
16+
// fn borrow(&self) -> &T {
17+
// &self.0
18+
// }
19+
// }
20+
// ```
21+
// ->
22+
// ```
23+
// struct Foo<T>(T);
24+
//
25+
// $0impl<T> AsRef<T> for Foo<T> {
26+
// fn as_ref(&self) -> &T {
27+
// &self.0
28+
// }
29+
// }
30+
//
31+
// impl<T> Borrow<T> for Foo<T> {
32+
// fn borrow(&self) -> &T {
33+
// &self.0
34+
// }
35+
// }
36+
// ```
37+
//
38+
// ---
39+
// Generate `AsMut` implement from `BorrowMut`.
40+
//
41+
// ```
42+
// struct Foo<T>(T);
43+
//
44+
// impl<T> $0BorrowMut<T> for Foo<T> {
45+
// fn borrow_mut(&mut self) -> &mut T {
46+
// &mut self.0
47+
// }
48+
// }
49+
// ```
50+
// ->
51+
// ```
52+
// struct Foo<T>(T);
53+
//
54+
// $0impl<T> AsMut<T> for Foo<T> {
55+
// fn as_mut(&mut self) -> &mut T {
56+
// &mut self.0
57+
// }
58+
// }
59+
//
60+
// impl<T> BorrowMut<T> for Foo<T> {
61+
// fn borrow_mut(&mut self) -> &mut T {
62+
// &mut self.0
63+
// }
64+
// }
65+
// ```
66+
pub(crate) fn generate_asref_impl_from_borrow(
67+
acc: &mut Assists,
68+
ctx: &AssistContext<'_>,
69+
) -> Option<()> {
70+
let ty = ctx.find_node_at_offset::<ast::Type>()?;
71+
let impl_ = ast::Impl::cast(ty.syntax().parent()?)?.clone_for_update();
72+
let path = ast::PathType::cast(impl_.trait_()?.syntax().clone())?;
73+
let indent = impl_.indent_level();
74+
75+
let name = path.path()?.segment()?.name_ref()?;
76+
77+
let (target_name, target_method_name) = match &*name.text() {
78+
"Borrow" => ("AsRef", "as_ref"),
79+
"BorrowMut" => ("AsMut", "as_mut"),
80+
_ => return None,
81+
};
82+
83+
let method = impl_.assoc_item_list()?.assoc_items().find_map(|it| match it {
84+
ast::AssocItem::Fn(f) => Some(f),
85+
_ => None,
86+
})?;
87+
88+
let target = impl_.syntax().text_range();
89+
acc.add(
90+
AssistId::generate("generate_asref_impl_from_borrow"),
91+
format!("Generate `{target_name}` implement from `{name}`"),
92+
target,
93+
|edit| {
94+
ted::replace(name.syntax(), make::name_ref(target_name).syntax().clone_for_update());
95+
96+
if let Some(name) = method.name() {
97+
ted::replace(
98+
name.syntax(),
99+
make::name(target_method_name).syntax().clone_for_update(),
100+
);
101+
}
102+
103+
edit.insert(target.start(), format!("$0{impl_}\n\n{indent}"));
104+
},
105+
)
106+
}
107+
108+
#[cfg(test)]
109+
mod tests {
110+
use crate::tests::check_assist;
111+
112+
use super::*;
113+
114+
#[test]
115+
fn test_generate_asref_impl_from_borrow() {
116+
check_assist(
117+
generate_asref_impl_from_borrow,
118+
r#"
119+
struct Foo<T>(T);
120+
121+
impl<T> $0Borrow<T> for Foo<T> {
122+
fn borrow(&self) -> &T {
123+
&self.0
124+
}
125+
}
126+
"#,
127+
r#"
128+
struct Foo<T>(T);
129+
130+
$0impl<T> AsRef<T> for Foo<T> {
131+
fn as_ref(&self) -> &T {
132+
&self.0
133+
}
134+
}
135+
136+
impl<T> Borrow<T> for Foo<T> {
137+
fn borrow(&self) -> &T {
138+
&self.0
139+
}
140+
}
141+
"#,
142+
);
143+
}
144+
145+
#[test]
146+
fn test_generate_asmut_impl_from_borrow_mut() {
147+
check_assist(
148+
generate_asref_impl_from_borrow,
149+
r#"
150+
struct Foo<T>(T);
151+
152+
impl<T> $0BorrowMut<T> for Foo<T> {
153+
fn borrow_mut(&mut self) -> &mut T {
154+
&mut self.0
155+
}
156+
}
157+
"#,
158+
r#"
159+
struct Foo<T>(T);
160+
161+
$0impl<T> AsMut<T> for Foo<T> {
162+
fn as_mut(&mut self) -> &mut T {
163+
&mut self.0
164+
}
165+
}
166+
167+
impl<T> BorrowMut<T> for Foo<T> {
168+
fn borrow_mut(&mut self) -> &mut T {
169+
&mut self.0
170+
}
171+
}
172+
"#,
173+
);
174+
}
175+
176+
#[test]
177+
fn test_generate_asref_impl_from_borrow_attributes() {
178+
check_assist(
179+
generate_asref_impl_from_borrow,
180+
r#"
181+
struct Foo<T>(T);
182+
183+
#[cfg(feature = "foo")]
184+
impl<T> $0Borrow<T> for Foo<T> {
185+
/// some docs
186+
fn borrow(&self) -> &T {
187+
&self.0
188+
}
189+
}
190+
"#,
191+
r#"
192+
struct Foo<T>(T);
193+
194+
$0#[cfg(feature = "foo")]
195+
impl<T> AsRef<T> for Foo<T> {
196+
/// some docs
197+
fn as_ref(&self) -> &T {
198+
&self.0
199+
}
200+
}
201+
202+
#[cfg(feature = "foo")]
203+
impl<T> Borrow<T> for Foo<T> {
204+
/// some docs
205+
fn borrow(&self) -> &T {
206+
&self.0
207+
}
208+
}
209+
"#,
210+
);
211+
}
212+
213+
#[test]
214+
fn test_generate_asref_impl_from_borrow_indent() {
215+
check_assist(
216+
generate_asref_impl_from_borrow,
217+
r#"
218+
mod foo {
219+
mod bar {
220+
struct Foo<T>(T);
221+
222+
impl<T> $0Borrow<T> for Foo<T> {
223+
fn borrow(&self) -> &T {
224+
&self.0
225+
}
226+
}
227+
}
228+
}
229+
"#,
230+
r#"
231+
mod foo {
232+
mod bar {
233+
struct Foo<T>(T);
234+
235+
$0impl<T> AsRef<T> for Foo<T> {
236+
fn as_ref(&self) -> &T {
237+
&self.0
238+
}
239+
}
240+
241+
impl<T> Borrow<T> for Foo<T> {
242+
fn borrow(&self) -> &T {
243+
&self.0
244+
}
245+
}
246+
}
247+
}
248+
"#,
249+
);
250+
}
251+
}

crates/ide-assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ mod handlers {
153153
mod flip_comma;
154154
mod flip_or_pattern;
155155
mod flip_trait_bound;
156+
mod generate_asref_impl_from_borrow;
156157
mod generate_constant;
157158
mod generate_default_from_enum_variant;
158159
mod generate_default_from_new;
@@ -302,6 +303,7 @@ mod handlers {
302303
generate_impl::generate_impl,
303304
generate_impl::generate_trait_impl,
304305
generate_is_empty_from_len::generate_is_empty_from_len,
306+
generate_asref_impl_from_borrow::generate_asref_impl_from_borrow,
305307
generate_mut_trait_impl::generate_mut_trait_impl,
306308
generate_new::generate_new,
307309
generate_trait_from_impl::generate_trait_from_impl,

crates/ide-assists/src/tests/generated.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,68 @@ fn foo<T: Copy + Clone>() { }
13111311
)
13121312
}
13131313

1314+
#[test]
1315+
fn doctest_generate_asref_impl_from_borrow() {
1316+
check_doc_test(
1317+
"generate_asref_impl_from_borrow",
1318+
r#####"
1319+
struct Foo<T>(T);
1320+
1321+
impl<T> $0Borrow<T> for Foo<T> {
1322+
fn borrow(&self) -> &T {
1323+
&self.0
1324+
}
1325+
}
1326+
"#####,
1327+
r#####"
1328+
struct Foo<T>(T);
1329+
1330+
$0impl<T> AsRef<T> for Foo<T> {
1331+
fn as_ref(&self) -> &T {
1332+
&self.0
1333+
}
1334+
}
1335+
1336+
impl<T> Borrow<T> for Foo<T> {
1337+
fn borrow(&self) -> &T {
1338+
&self.0
1339+
}
1340+
}
1341+
"#####,
1342+
)
1343+
}
1344+
1345+
#[test]
1346+
fn doctest_generate_asref_impl_from_borrow_1() {
1347+
check_doc_test(
1348+
"generate_asref_impl_from_borrow",
1349+
r#####"
1350+
struct Foo<T>(T);
1351+
1352+
impl<T> $0BorrowMut<T> for Foo<T> {
1353+
fn borrow_mut(&mut self) -> &mut T {
1354+
&mut self.0
1355+
}
1356+
}
1357+
"#####,
1358+
r#####"
1359+
struct Foo<T>(T);
1360+
1361+
$0impl<T> AsMut<T> for Foo<T> {
1362+
fn as_mut(&mut self) -> &mut T {
1363+
&mut self.0
1364+
}
1365+
}
1366+
1367+
impl<T> BorrowMut<T> for Foo<T> {
1368+
fn borrow_mut(&mut self) -> &mut T {
1369+
&mut self.0
1370+
}
1371+
}
1372+
"#####,
1373+
)
1374+
}
1375+
13141376
#[test]
13151377
fn doctest_generate_constant() {
13161378
check_doc_test(

0 commit comments

Comments
 (0)