aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-09 16:55:42 +0100
committerGitHub <[email protected]>2021-05-09 16:55:42 +0100
commita3b034938ebe12b29ef37ff6e54bad3c574464be (patch)
tree1ed28e5499d4db6948c18f96e2136a2f61f5e222
parent0900beeaa2ca4b9e91d51165545935d4e1db7bb6 (diff)
parent5342800147679a0ded5546322c94aa6339d58fbc (diff)
Merge #8781
8781: internal: rewrite **Repalce impl Trait** assist to mutable syntax trees r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ide/src/join_lines.rs36
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs2
-rw-r--r--crates/ide_assists/src/handlers/introduce_named_lifetime.rs4
-rw-r--r--crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs120
-rw-r--r--crates/ide_assists/src/utils/suggest_name.rs15
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs19
-rw-r--r--crates/syntax/src/ast/make.rs4
7 files changed, 100 insertions, 100 deletions
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 482b23cf5..61dcbb399 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -1,3 +1,5 @@
1use std::convert::TryFrom;
2
1use ide_assists::utils::extract_trivial_expression; 3use ide_assists::utils::extract_trivial_expression;
2use itertools::Itertools; 4use itertools::Itertools;
3use syntax::{ 5use syntax::{
@@ -65,6 +67,14 @@ fn remove_newlines(edit: &mut TextEditBuilder, token: &SyntaxToken, range: TextR
65 67
66fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) { 68fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) {
67 if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { 69 if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 {
70 let n_spaces_after_line_break = {
71 let suff = &token.text()[TextRange::new(
72 offset - token.text_range().start() + TextSize::of('\n'),
73 TextSize::of(token.text()),
74 )];
75 suff.bytes().take_while(|&b| b == b' ').count()
76 };
77
68 let mut no_space = false; 78 let mut no_space = false;
69 if let Some(string) = ast::String::cast(token.clone()) { 79 if let Some(string) = ast::String::cast(token.clone()) {
70 if let Some(range) = string.open_quote_text_range() { 80 if let Some(range) = string.open_quote_text_range() {
@@ -73,18 +83,13 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
73 } 83 }
74 if let Some(range) = string.close_quote_text_range() { 84 if let Some(range) = string.close_quote_text_range() {
75 cov_mark::hit!(join_string_literal_close_quote); 85 cov_mark::hit!(join_string_literal_close_quote);
76 no_space |= range.start() == offset + TextSize::of('\n'); 86 no_space |= range.start()
87 == offset
88 + TextSize::of('\n')
89 + TextSize::try_from(n_spaces_after_line_break).unwrap();
77 } 90 }
78 } 91 }
79 92
80 let n_spaces_after_line_break = {
81 let suff = &token.text()[TextRange::new(
82 offset - token.text_range().start() + TextSize::of('\n'),
83 TextSize::of(token.text()),
84 )];
85 suff.bytes().take_while(|&b| b == b' ').count()
86 };
87
88 let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into()); 93 let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into());
89 let replace_with = if no_space { "" } else { " " }; 94 let replace_with = if no_space { "" } else { " " };
90 edit.replace(range, replace_with.to_string()); 95 edit.replace(range, replace_with.to_string());
@@ -835,6 +840,19 @@ fn main() {
835} 840}
836"#, 841"#,
837 ); 842 );
843 check_join_lines(
844 r#"
845fn main() {
846 $0r"hello
847 ";
848}
849"#,
850 r#"
851fn main() {
852 $0r"hello";
853}
854"#,
855 );
838 } 856 }
839 857
840 check_join_lines( 858 check_join_lines(
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs
index 136b9a55b..ae084c86c 100644
--- a/crates/ide_assists/src/handlers/extract_variable.rs
+++ b/crates/ide_assists/src/handlers/extract_variable.rs
@@ -54,7 +54,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
54 54
55 let var_name = match &field_shorthand { 55 let var_name = match &field_shorthand {
56 Some(it) => it.to_string(), 56 Some(it) => it.to_string(),
57 None => suggest_name::variable(&to_extract, &ctx.sema), 57 None => suggest_name::for_variable(&to_extract, &ctx.sema),
58 }; 58 };
59 let expr_range = match &field_shorthand { 59 let expr_range = match &field_shorthand {
60 Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()), 60 Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()),
diff --git a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
index 9f4f71d6c..cb71ca8bd 100644
--- a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
@@ -139,12 +139,12 @@ fn generate_unique_lifetime_param_name(
139 139
140fn add_lifetime_param(type_params: ast::GenericParamList, new_lifetime_param: char) { 140fn add_lifetime_param(type_params: ast::GenericParamList, new_lifetime_param: char) {
141 let generic_param = 141 let generic_param =
142 make::generic_param(format!("'{}", new_lifetime_param), None).clone_for_update(); 142 make::generic_param(&format!("'{}", new_lifetime_param), None).clone_for_update();
143 type_params.add_generic_param(generic_param); 143 type_params.add_generic_param(generic_param);
144} 144}
145 145
146fn make_ast_lifetime(new_lifetime_param: char) -> ast::Lifetime { 146fn make_ast_lifetime(new_lifetime_param: char) -> ast::Lifetime {
147 make::generic_param(format!("'{}", new_lifetime_param), None) 147 make::generic_param(&format!("'{}", new_lifetime_param), None)
148 .syntax() 148 .syntax()
149 .descendants() 149 .descendants()
150 .find_map(ast::Lifetime::cast) 150 .find_map(ast::Lifetime::cast)
diff --git a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs
index ff25b61ea..16cae0281 100644
--- a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs
+++ b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs
@@ -1,6 +1,9 @@
1use syntax::ast::{self, edit::AstNodeEdit, make, AstNode, GenericParamsOwner}; 1use syntax::{
2 ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode},
3 ted,
4};
2 5
3use crate::{AssistContext, AssistId, AssistKind, Assists}; 6use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
4 7
5// Assist: replace_impl_trait_with_generic 8// Assist: replace_impl_trait_with_generic
6// 9//
@@ -17,30 +20,29 @@ pub(crate) fn replace_impl_trait_with_generic(
17 acc: &mut Assists, 20 acc: &mut Assists,
18 ctx: &AssistContext, 21 ctx: &AssistContext,
19) -> Option<()> { 22) -> Option<()> {
20 let type_impl_trait = ctx.find_node_at_offset::<ast::ImplTraitType>()?; 23 let impl_trait_type = ctx.find_node_at_offset::<ast::ImplTraitType>()?;
21 let type_param = type_impl_trait.syntax().parent().and_then(ast::Param::cast)?; 24 let param = impl_trait_type.syntax().parent().and_then(ast::Param::cast)?;
22 let type_fn = type_param.syntax().ancestors().find_map(ast::Fn::cast)?; 25 let fn_ = param.syntax().ancestors().find_map(ast::Fn::cast)?;
23 26
24 let impl_trait_ty = type_impl_trait.type_bound_list()?; 27 let type_bound_list = impl_trait_type.type_bound_list()?;
25 28
26 let target = type_fn.syntax().text_range(); 29 let target = fn_.syntax().text_range();
27 acc.add( 30 acc.add(
28 AssistId("replace_impl_trait_with_generic", AssistKind::RefactorRewrite), 31 AssistId("replace_impl_trait_with_generic", AssistKind::RefactorRewrite),
29 "Replace impl trait with generic", 32 "Replace impl trait with generic",
30 target, 33 target,
31 |edit| { 34 |edit| {
32 let generic_letter = impl_trait_ty.to_string().chars().next().unwrap().to_string(); 35 let impl_trait_type = edit.make_ast_mut(impl_trait_type);
36 let fn_ = edit.make_ast_mut(fn_);
33 37
34 let generic_param_list = type_fn 38 let type_param_name = suggest_name::for_generic_parameter(&impl_trait_type);
35 .generic_param_list()
36 .unwrap_or_else(|| make::generic_param_list(None))
37 .append_param(make::generic_param(generic_letter.clone(), Some(impl_trait_ty)));
38 39
39 let new_type_fn = type_fn 40 let type_param =
40 .replace_descendant::<ast::Type>(type_impl_trait.into(), make::ty(&generic_letter)) 41 make::generic_param(&type_param_name, Some(type_bound_list)).clone_for_update();
41 .with_generic_param_list(generic_param_list); 42 let new_ty = make::ty(&type_param_name).clone_for_update();
42 43
43 edit.replace_ast(type_fn.clone(), new_type_fn); 44 ted::replace(impl_trait_type.syntax(), new_ty.syntax());
45 fn_.get_or_create_generic_param_list().add_generic_param(type_param)
44 }, 46 },
45 ) 47 )
46} 48}
@@ -55,12 +57,8 @@ mod tests {
55 fn replace_impl_trait_with_generic_params() { 57 fn replace_impl_trait_with_generic_params() {
56 check_assist( 58 check_assist(
57 replace_impl_trait_with_generic, 59 replace_impl_trait_with_generic,
58 r#" 60 r#"fn foo<G>(bar: $0impl Bar) {}"#,
59 fn foo<G>(bar: $0impl Bar) {} 61 r#"fn foo<G, B: Bar>(bar: B) {}"#,
60 "#,
61 r#"
62 fn foo<G, B: Bar>(bar: B) {}
63 "#,
64 ); 62 );
65 } 63 }
66 64
@@ -68,12 +66,8 @@ mod tests {
68 fn replace_impl_trait_without_generic_params() { 66 fn replace_impl_trait_without_generic_params() {
69 check_assist( 67 check_assist(
70 replace_impl_trait_with_generic, 68 replace_impl_trait_with_generic,
71 r#" 69 r#"fn foo(bar: $0impl Bar) {}"#,
72 fn foo(bar: $0impl Bar) {} 70 r#"fn foo<B: Bar>(bar: B) {}"#,
73 "#,
74 r#"
75 fn foo<B: Bar>(bar: B) {}
76 "#,
77 ); 71 );
78 } 72 }
79 73
@@ -81,12 +75,8 @@ mod tests {
81 fn replace_two_impl_trait_with_generic_params() { 75 fn replace_two_impl_trait_with_generic_params() {
82 check_assist( 76 check_assist(
83 replace_impl_trait_with_generic, 77 replace_impl_trait_with_generic,
84 r#" 78 r#"fn foo<G>(foo: impl Foo, bar: $0impl Bar) {}"#,
85 fn foo<G>(foo: impl Foo, bar: $0impl Bar) {} 79 r#"fn foo<G, B: Bar>(foo: impl Foo, bar: B) {}"#,
86 "#,
87 r#"
88 fn foo<G, B: Bar>(foo: impl Foo, bar: B) {}
89 "#,
90 ); 80 );
91 } 81 }
92 82
@@ -94,12 +84,8 @@ mod tests {
94 fn replace_impl_trait_with_empty_generic_params() { 84 fn replace_impl_trait_with_empty_generic_params() {
95 check_assist( 85 check_assist(
96 replace_impl_trait_with_generic, 86 replace_impl_trait_with_generic,
97 r#" 87 r#"fn foo<>(bar: $0impl Bar) {}"#,
98 fn foo<>(bar: $0impl Bar) {} 88 r#"fn foo<B: Bar>(bar: B) {}"#,
99 "#,
100 r#"
101 fn foo<B: Bar>(bar: B) {}
102 "#,
103 ); 89 );
104 } 90 }
105 91
@@ -108,13 +94,13 @@ mod tests {
108 check_assist( 94 check_assist(
109 replace_impl_trait_with_generic, 95 replace_impl_trait_with_generic,
110 r#" 96 r#"
111 fn foo< 97fn foo<
112 >(bar: $0impl Bar) {} 98>(bar: $0impl Bar) {}
113 "#, 99"#,
114 r#" 100 r#"
115 fn foo<B: Bar 101fn foo<B: Bar
116 >(bar: B) {} 102>(bar: B) {}
117 "#, 103"#,
118 ); 104 );
119 } 105 }
120 106
@@ -123,12 +109,8 @@ mod tests {
123 fn replace_impl_trait_with_exist_generic_letter() { 109 fn replace_impl_trait_with_exist_generic_letter() {
124 check_assist( 110 check_assist(
125 replace_impl_trait_with_generic, 111 replace_impl_trait_with_generic,
126 r#" 112 r#"fn foo<B>(bar: $0impl Bar) {}"#,
127 fn foo<B>(bar: $0impl Bar) {} 113 r#"fn foo<B, C: Bar>(bar: C) {}"#,
128 "#,
129 r#"
130 fn foo<B, C: Bar>(bar: C) {}
131 "#,
132 ); 114 );
133 } 115 }
134 116
@@ -137,19 +119,19 @@ mod tests {
137 check_assist( 119 check_assist(
138 replace_impl_trait_with_generic, 120 replace_impl_trait_with_generic,
139 r#" 121 r#"
140 fn foo< 122fn foo<
141 G: Foo, 123 G: Foo,
142 F, 124 F,
143 H, 125 H,
144 >(bar: $0impl Bar) {} 126>(bar: $0impl Bar) {}
145 "#, 127"#,
146 r#" 128 r#"
147 fn foo< 129fn foo<
148 G: Foo, 130 G: Foo,
149 F, 131 F,
150 H, B: Bar 132 H, B: Bar,
151 >(bar: B) {} 133>(bar: B) {}
152 "#, 134"#,
153 ); 135 );
154 } 136 }
155 137
@@ -157,12 +139,8 @@ mod tests {
157 fn replace_impl_trait_multiple() { 139 fn replace_impl_trait_multiple() {
158 check_assist( 140 check_assist(
159 replace_impl_trait_with_generic, 141 replace_impl_trait_with_generic,
160 r#" 142 r#"fn foo(bar: $0impl Foo + Bar) {}"#,
161 fn foo(bar: $0impl Foo + Bar) {} 143 r#"fn foo<F: Foo + Bar>(bar: F) {}"#,
162 "#,
163 r#"
164 fn foo<F: Foo + Bar>(bar: F) {}
165 "#,
166 ); 144 );
167 } 145 }
168} 146}
diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs
index deafcd630..b3aabeab3 100644
--- a/crates/ide_assists/src/utils/suggest_name.rs
+++ b/crates/ide_assists/src/utils/suggest_name.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
6use stdx::to_lower_snake_case; 6use stdx::to_lower_snake_case;
7use syntax::{ 7use syntax::{
8 ast::{self, NameOwner}, 8 ast::{self, NameOwner},
9 match_ast, AstNode, 9 match_ast, AstNode, SmolStr,
10}; 10};
11 11
12/// Trait names, that will be ignored when in `impl Trait` and `dyn Trait` 12/// Trait names, that will be ignored when in `impl Trait` and `dyn Trait`
@@ -57,6 +57,14 @@ const USELESS_METHODS: &[&str] = &[
57 "iter_mut", 57 "iter_mut",
58]; 58];
59 59
60pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
61 let c = ty
62 .type_bound_list()
63 .and_then(|bounds| bounds.syntax().text().char_at(0.into()))
64 .unwrap_or('T');
65 c.encode_utf8(&mut [0; 4]).into()
66}
67
60/// Suggest name of variable for given expression 68/// Suggest name of variable for given expression
61/// 69///
62/// **NOTE**: it is caller's responsibility to guarantee uniqueness of the name. 70/// **NOTE**: it is caller's responsibility to guarantee uniqueness of the name.
@@ -75,7 +83,8 @@ const USELESS_METHODS: &[&str] = &[
75/// It also applies heuristics to filter out less informative names 83/// It also applies heuristics to filter out less informative names
76/// 84///
77/// Currently it sticks to the first name found. 85/// Currently it sticks to the first name found.
78pub(crate) fn variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { 86// FIXME: Microoptimize and return a `SmolStr` here.
87pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String {
79 // `from_param` does not benifit from stripping 88 // `from_param` does not benifit from stripping
80 // it need the largest context possible 89 // it need the largest context possible
81 // so we check firstmost 90 // so we check firstmost
@@ -276,7 +285,7 @@ mod tests {
276 frange.range, 285 frange.range,
277 "selection is not an expression(yet contained in one)" 286 "selection is not an expression(yet contained in one)"
278 ); 287 );
279 let name = variable(&expr, &sema); 288 let name = for_variable(&expr, &sema);
280 assert_eq!(&name, expected); 289 assert_eq!(&name, expected);
281 } 290 }
282 291
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 04f97f368..168355555 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -195,18 +195,13 @@ impl ast::GenericParamList {
195 pub fn add_generic_param(&self, generic_param: ast::GenericParam) { 195 pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
196 match self.generic_params().last() { 196 match self.generic_params().last() {
197 Some(last_param) => { 197 Some(last_param) => {
198 let mut elems = Vec::new(); 198 let position = Position::after(last_param.syntax());
199 if !last_param 199 let elements = vec![
200 .syntax() 200 make::token(T![,]).into(),
201 .siblings_with_tokens(Direction::Next) 201 make::tokens::single_space().into(),
202 .any(|it| it.kind() == T![,]) 202 generic_param.syntax().clone().into(),
203 { 203 ];
204 elems.push(make::token(T![,]).into()); 204 ted::insert_all(position, elements);
205 elems.push(make::tokens::single_space().into());
206 };
207 elems.push(generic_param.syntax().clone().into());
208 let after_last_param = Position::after(last_param.syntax());
209 ted::insert_all(after_last_param, elems);
210 } 205 }
211 None => { 206 None => {
212 let after_l_angle = Position::after(self.l_angle_token().unwrap()); 207 let after_l_angle = Position::after(self.l_angle_token().unwrap());
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 5a6687397..2289d8f3e 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -475,8 +475,8 @@ pub fn param_list(
475 }; 475 };
476 ast_from_text(&list) 476 ast_from_text(&list)
477} 477}
478 478// FIXME: s/&str/ast:Name
479pub fn generic_param(name: String, ty: Option<ast::TypeBoundList>) -> ast::GenericParam { 479pub fn generic_param(name: &str, ty: Option<ast::TypeBoundList>) -> ast::GenericParam {
480 let bound = match ty { 480 let bound = match ty {
481 Some(it) => format!(": {}", it), 481 Some(it) => format!(": {}", it),
482 None => String::new(), 482 None => String::new(),