aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r--crates/ide_assists/src/handlers/add_turbo_fish.rs108
-rw-r--r--crates/ide_assists/src/handlers/apply_demorgan.rs45
-rw-r--r--crates/ide_assists/src/handlers/convert_comment_block.rs419
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs208
4 files changed, 771 insertions, 9 deletions
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs
index 8e9ea4fad..a08b55ebb 100644
--- a/crates/ide_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs
@@ -31,6 +31,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
31 return None; 31 return None;
32 } 32 }
33 mark::hit!(add_turbo_fish_after_call); 33 mark::hit!(add_turbo_fish_after_call);
34 mark::hit!(add_type_ascription_after_call);
34 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) 35 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
35 })?; 36 })?;
36 let next_token = ident.next_token()?; 37 let next_token = ident.next_token()?;
@@ -52,6 +53,24 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
52 mark::hit!(add_turbo_fish_non_generic); 53 mark::hit!(add_turbo_fish_non_generic);
53 return None; 54 return None;
54 } 55 }
56
57 if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() {
58 if let_stmt.colon_token().is_none() {
59 let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end();
60 acc.add(
61 AssistId("add_type_ascription", AssistKind::RefactorRewrite),
62 "Add `: _` before assignment operator",
63 ident.text_range(),
64 |builder| match ctx.config.snippet_cap {
65 Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"),
66 None => builder.insert(type_pos, ": _"),
67 },
68 )?
69 } else {
70 mark::hit!(add_type_ascription_already_typed);
71 }
72 }
73
55 acc.add( 74 acc.add(
56 AssistId("add_turbo_fish", AssistKind::RefactorRewrite), 75 AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
57 "Add `::<>`", 76 "Add `::<>`",
@@ -65,7 +84,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
65 84
66#[cfg(test)] 85#[cfg(test)]
67mod tests { 86mod tests {
68 use crate::tests::{check_assist, check_assist_not_applicable}; 87 use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable};
69 88
70 use super::*; 89 use super::*;
71 use test_utils::mark; 90 use test_utils::mark;
@@ -161,4 +180,91 @@ fn main() {
161"#, 180"#,
162 ); 181 );
163 } 182 }
183
184 #[test]
185 fn add_type_ascription_function() {
186 check_assist_by_label(
187 add_turbo_fish,
188 r#"
189fn make<T>() -> T {}
190fn main() {
191 let x = make$0();
192}
193"#,
194 r#"
195fn make<T>() -> T {}
196fn main() {
197 let x: ${0:_} = make();
198}
199"#,
200 "Add `: _` before assignment operator",
201 );
202 }
203
204 #[test]
205 fn add_type_ascription_after_call() {
206 mark::check!(add_type_ascription_after_call);
207 check_assist_by_label(
208 add_turbo_fish,
209 r#"
210fn make<T>() -> T {}
211fn main() {
212 let x = make()$0;
213}
214"#,
215 r#"
216fn make<T>() -> T {}
217fn main() {
218 let x: ${0:_} = make();
219}
220"#,
221 "Add `: _` before assignment operator",
222 );
223 }
224
225 #[test]
226 fn add_type_ascription_method() {
227 check_assist_by_label(
228 add_turbo_fish,
229 r#"
230struct S;
231impl S {
232 fn make<T>(&self) -> T {}
233}
234fn main() {
235 let x = S.make$0();
236}
237"#,
238 r#"
239struct S;
240impl S {
241 fn make<T>(&self) -> T {}
242}
243fn main() {
244 let x: ${0:_} = S.make();
245}
246"#,
247 "Add `: _` before assignment operator",
248 );
249 }
250
251 #[test]
252 fn add_type_ascription_already_typed() {
253 mark::check!(add_type_ascription_already_typed);
254 check_assist(
255 add_turbo_fish,
256 r#"
257fn make<T>() -> T {}
258fn main() {
259 let x: () = make$0();
260}
261"#,
262 r#"
263fn make<T>() -> T {}
264fn main() {
265 let x: () = make::<${0:_}>();
266}
267"#,
268 );
269 }
164} 270}
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs
index 6997ea048..128b1eb56 100644
--- a/crates/ide_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ide_assists/src/handlers/apply_demorgan.rs
@@ -1,4 +1,5 @@
1use syntax::ast::{self, AstNode}; 1use syntax::ast::{self, AstNode};
2use test_utils::mark;
2 3
3use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; 4use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
4 5
@@ -43,9 +44,36 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<(
43 "Apply De Morgan's law", 44 "Apply De Morgan's law",
44 op_range, 45 op_range,
45 |edit| { 46 |edit| {
47 let paren_expr = expr.syntax().parent().and_then(|parent| ast::ParenExpr::cast(parent));
48
49 let neg_expr = paren_expr
50 .clone()
51 .and_then(|paren_expr| paren_expr.syntax().parent())
52 .and_then(|parent| ast::PrefixExpr::cast(parent))
53 .and_then(|prefix_expr| {
54 if prefix_expr.op_kind().unwrap() == ast::PrefixOp::Not {
55 Some(prefix_expr)
56 } else {
57 None
58 }
59 });
60
46 edit.replace(op_range, opposite_op); 61 edit.replace(op_range, opposite_op);
47 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); 62
48 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); 63 if let Some(paren_expr) = paren_expr {
64 edit.replace(lhs_range, not_lhs.syntax().text());
65 edit.replace(rhs_range, not_rhs.syntax().text());
66 if let Some(neg_expr) = neg_expr {
67 mark::hit!(demorgan_double_negation);
68 edit.replace(neg_expr.op_token().unwrap().text_range(), "");
69 } else {
70 mark::hit!(demorgan_double_parens);
71 edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!(");
72 }
73 } else {
74 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
75 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
76 }
49 }, 77 },
50 ) 78 )
51} 79}
@@ -62,6 +90,7 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
62#[cfg(test)] 90#[cfg(test)]
63mod tests { 91mod tests {
64 use ide_db::helpers::FamousDefs; 92 use ide_db::helpers::FamousDefs;
93 use test_utils::mark;
65 94
66 use super::*; 95 use super::*;
67 96
@@ -156,4 +185,16 @@ fn f() {
156 fn demorgan_doesnt_apply_with_cursor_not_on_op() { 185 fn demorgan_doesnt_apply_with_cursor_not_on_op() {
157 check_assist_not_applicable(apply_demorgan, "fn f() { $0 !x || !x }") 186 check_assist_not_applicable(apply_demorgan, "fn f() { $0 !x || !x }")
158 } 187 }
188
189 #[test]
190 fn demorgan_doesnt_double_negation() {
191 mark::check!(demorgan_double_negation);
192 check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }")
193 }
194
195 #[test]
196 fn demorgan_doesnt_double_parens() {
197 mark::check!(demorgan_double_parens);
198 check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }")
199 }
159} 200}
diff --git a/crates/ide_assists/src/handlers/convert_comment_block.rs b/crates/ide_assists/src/handlers/convert_comment_block.rs
new file mode 100644
index 000000000..cdc45fc42
--- /dev/null
+++ b/crates/ide_assists/src/handlers/convert_comment_block.rs
@@ -0,0 +1,419 @@
1use itertools::Itertools;
2use std::convert::identity;
3use syntax::{
4 ast::{
5 self,
6 edit::IndentLevel,
7 Comment, CommentKind,
8 CommentPlacement::{Inner, Outer},
9 CommentShape::{self, Block, Line},
10 Whitespace,
11 },
12 AstToken, Direction, SyntaxElement, TextRange,
13};
14
15use crate::{AssistContext, AssistId, AssistKind, Assists};
16
17/// Assist: line_to_block
18///
19/// Converts comments between block and single-line form
20///
21/// ```
22/// // Multi-line
23/// // comment
24/// ```
25/// ->
26/// ```
27/// /**
28/// Multi-line
29/// comment
30/// */
31/// ```
32pub(crate) fn convert_comment_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 if let Some(comment) = ctx.find_token_at_offset::<ast::Comment>() {
34 // Only allow comments which are alone on their line
35 if let Some(prev) = comment.syntax().prev_token() {
36 if Whitespace::cast(prev).filter(|w| w.text().contains('\n')).is_none() {
37 return None;
38 }
39 }
40
41 return match comment.kind().shape {
42 ast::CommentShape::Block => block_to_line(acc, comment),
43 ast::CommentShape::Line => line_to_block(acc, comment),
44 };
45 }
46
47 return None;
48}
49
50fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
51 let target = comment.syntax().text_range();
52
53 acc.add(
54 AssistId("block_to_line", AssistKind::RefactorRewrite),
55 "Replace block comment with line comments",
56 target,
57 |edit| {
58 let indentation = IndentLevel::from_token(comment.syntax());
59 let line_prefix =
60 comment_kind_prefix(CommentKind { shape: CommentShape::Line, ..comment.kind() });
61
62 let text = comment.text();
63 let text = &text[comment.prefix().len()..(text.len() - "*/".len())].trim();
64
65 let lines = text.lines().peekable();
66
67 let indent_spaces = indentation.to_string();
68 let output = lines
69 .map(|l| l.trim_start_matches(&indent_spaces))
70 .map(|l| {
71 // Don't introduce trailing whitespace
72 if l.is_empty() {
73 line_prefix.to_string()
74 } else {
75 format!("{} {}", line_prefix, l.trim_start_matches(&indent_spaces))
76 }
77 })
78 .join(&format!("\n{}", indent_spaces));
79
80 edit.replace(target, output)
81 },
82 )
83}
84
85fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
86 // Find all the comments we'll be collapsing into a block
87 let comments = relevant_line_comments(&comment);
88
89 // Establish the target of our edit based on the comments we found
90 let target = TextRange::new(
91 comments[0].syntax().text_range().start(),
92 comments.last().unwrap().syntax().text_range().end(),
93 );
94
95 acc.add(
96 AssistId("line_to_block", AssistKind::RefactorRewrite),
97 "Replace line comments with a single block comment",
98 target,
99 |edit| {
100 // We pick a single indentation level for the whole block comment based on the
101 // comment where the assist was invoked. This will be prepended to the
102 // contents of each line comment when they're put into the block comment.
103 let indentation = IndentLevel::from_token(&comment.syntax());
104
105 let block_comment_body =
106 comments.into_iter().map(|c| line_comment_text(indentation, c)).join("\n");
107
108 let block_prefix =
109 comment_kind_prefix(CommentKind { shape: CommentShape::Block, ..comment.kind() });
110
111 let output =
112 format!("{}\n{}\n{}*/", block_prefix, block_comment_body, indentation.to_string());
113
114 edit.replace(target, output)
115 },
116 )
117}
118
119/// The line -> block assist can be invoked from anywhere within a sequence of line comments.
120/// relevant_line_comments crawls backwards and forwards finding the complete sequence of comments that will
121/// be joined.
122fn relevant_line_comments(comment: &ast::Comment) -> Vec<Comment> {
123 // The prefix identifies the kind of comment we're dealing with
124 let prefix = comment.prefix();
125 let same_prefix = |c: &ast::Comment| c.prefix() == prefix;
126
127 // These tokens are allowed to exist between comments
128 let skippable = |not: &SyntaxElement| {
129 not.clone()
130 .into_token()
131 .and_then(Whitespace::cast)
132 .map(|w| !w.spans_multiple_lines())
133 .unwrap_or(false)
134 };
135
136 // Find all preceding comments (in reverse order) that have the same prefix
137 let prev_comments = comment
138 .syntax()
139 .siblings_with_tokens(Direction::Prev)
140 .filter(|s| !skippable(s))
141 .map(|not| not.into_token().and_then(Comment::cast).filter(same_prefix))
142 .take_while(|opt_com| opt_com.is_some())
143 .filter_map(identity)
144 .skip(1); // skip the first element so we don't duplicate it in next_comments
145
146 let next_comments = comment
147 .syntax()
148 .siblings_with_tokens(Direction::Next)
149 .filter(|s| !skippable(s))
150 .map(|not| not.into_token().and_then(Comment::cast).filter(same_prefix))
151 .take_while(|opt_com| opt_com.is_some())
152 .filter_map(identity);
153
154 let mut comments: Vec<_> = prev_comments.collect();
155 comments.reverse();
156 comments.extend(next_comments);
157 comments
158}
159
160// Line comments usually begin with a single space character following the prefix as seen here:
161//^
162// But comments can also include indented text:
163// > Hello there
164//
165// We handle this by stripping *AT MOST* one space character from the start of the line
166// This has its own problems because it can cause alignment issues:
167//
168// /*
169// a ----> a
170//b ----> b
171// */
172//
173// But since such comments aren't idiomatic we're okay with this.
174fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String {
175 let contents_without_prefix = comm.text().strip_prefix(comm.prefix()).unwrap();
176 let contents = contents_without_prefix.strip_prefix(' ').unwrap_or(contents_without_prefix);
177
178 // Don't add the indentation if the line is empty
179 if contents.is_empty() {
180 contents.to_owned()
181 } else {
182 indentation.to_string() + &contents
183 }
184}
185
186fn comment_kind_prefix(ck: ast::CommentKind) -> &'static str {
187 match (ck.shape, ck.doc) {
188 (Line, Some(Inner)) => "//!",
189 (Line, Some(Outer)) => "///",
190 (Line, None) => "//",
191 (Block, Some(Inner)) => "/*!",
192 (Block, Some(Outer)) => "/**",
193 (Block, None) => "/*",
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use crate::tests::{check_assist, check_assist_not_applicable};
200
201 use super::*;
202
203 #[test]
204 fn single_line_to_block() {
205 check_assist(
206 convert_comment_block,
207 r#"
208// line$0 comment
209fn main() {
210 foo();
211}
212"#,
213 r#"
214/*
215line comment
216*/
217fn main() {
218 foo();
219}
220"#,
221 );
222 }
223
224 #[test]
225 fn single_line_to_block_indented() {
226 check_assist(
227 convert_comment_block,
228 r#"
229fn main() {
230 // line$0 comment
231 foo();
232}
233"#,
234 r#"
235fn main() {
236 /*
237 line comment
238 */
239 foo();
240}
241"#,
242 );
243 }
244
245 #[test]
246 fn multiline_to_block() {
247 check_assist(
248 convert_comment_block,
249 r#"
250fn main() {
251 // above
252 // line$0 comment
253 //
254 // below
255 foo();
256}
257"#,
258 r#"
259fn main() {
260 /*
261 above
262 line comment
263
264 below
265 */
266 foo();
267}
268"#,
269 );
270 }
271
272 #[test]
273 fn end_of_line_to_block() {
274 check_assist_not_applicable(
275 convert_comment_block,
276 r#"
277fn main() {
278 foo(); // end-of-line$0 comment
279}
280"#,
281 );
282 }
283
284 #[test]
285 fn single_line_different_kinds() {
286 check_assist(
287 convert_comment_block,
288 r#"
289fn main() {
290 /// different prefix
291 // line$0 comment
292 // below
293 foo();
294}
295"#,
296 r#"
297fn main() {
298 /// different prefix
299 /*
300 line comment
301 below
302 */
303 foo();
304}
305"#,
306 );
307 }
308
309 #[test]
310 fn single_line_separate_chunks() {
311 check_assist(
312 convert_comment_block,
313 r#"
314fn main() {
315 // different chunk
316
317 // line$0 comment
318 // below
319 foo();
320}
321"#,
322 r#"
323fn main() {
324 // different chunk
325
326 /*
327 line comment
328 below
329 */
330 foo();
331}
332"#,
333 );
334 }
335
336 #[test]
337 fn doc_block_comment_to_lines() {
338 check_assist(
339 convert_comment_block,
340 r#"
341/**
342 hi$0 there
343*/
344"#,
345 r#"
346/// hi there
347"#,
348 );
349 }
350
351 #[test]
352 fn block_comment_to_lines() {
353 check_assist(
354 convert_comment_block,
355 r#"
356/*
357 hi$0 there
358*/
359"#,
360 r#"
361// hi there
362"#,
363 );
364 }
365
366 #[test]
367 fn inner_doc_block_to_lines() {
368 check_assist(
369 convert_comment_block,
370 r#"
371/*!
372 hi$0 there
373*/
374"#,
375 r#"
376//! hi there
377"#,
378 );
379 }
380
381 #[test]
382 fn block_to_lines_indent() {
383 check_assist(
384 convert_comment_block,
385 r#"
386fn main() {
387 /*!
388 hi$0 there
389
390 ```
391 code_sample
392 ```
393 */
394}
395"#,
396 r#"
397fn main() {
398 //! hi there
399 //!
400 //! ```
401 //! code_sample
402 //! ```
403}
404"#,
405 );
406 }
407
408 #[test]
409 fn end_of_line_block_to_line() {
410 check_assist_not_applicable(
411 convert_comment_block,
412 r#"
413fn main() {
414 foo(); /* end-of-line$0 comment */
415}
416"#,
417 );
418 }
419}
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs
index 98f3dc6ca..312ac7ac4 100644
--- a/crates/ide_assists/src/handlers/extract_variable.rs
+++ b/crates/ide_assists/src/handlers/extract_variable.rs
@@ -8,7 +8,7 @@ use syntax::{
8}; 8};
9use test_utils::mark; 9use test_utils::mark;
10 10
11use crate::{AssistContext, AssistId, AssistKind, Assists}; 11use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
12 12
13// Assist: extract_variable 13// Assist: extract_variable
14// 14//
@@ -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 => "var_name".to_string(), 57 None => suggest_name::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()),
@@ -274,8 +274,8 @@ fn foo() {
274"#, 274"#,
275 r#" 275 r#"
276fn foo() { 276fn foo() {
277 let $0var_name = bar(1 + 1); 277 let $0bar = bar(1 + 1);
278 var_name 278 bar
279} 279}
280"#, 280"#,
281 ) 281 )
@@ -401,8 +401,8 @@ fn main() {
401", 401",
402 " 402 "
403fn main() { 403fn main() {
404 let $0var_name = bar.foo(); 404 let $0foo = bar.foo();
405 let v = var_name; 405 let v = foo;
406} 406}
407", 407",
408 ); 408 );
@@ -557,6 +557,202 @@ fn main() {
557 } 557 }
558 558
559 #[test] 559 #[test]
560 fn extract_var_name_from_type() {
561 check_assist(
562 extract_variable,
563 r#"
564struct Test(i32);
565
566fn foo() -> Test {
567 $0{ Test(10) }$0
568}
569"#,
570 r#"
571struct Test(i32);
572
573fn foo() -> Test {
574 let $0test = { Test(10) };
575 test
576}
577"#,
578 )
579 }
580
581 #[test]
582 fn extract_var_name_from_parameter() {
583 check_assist(
584 extract_variable,
585 r#"
586fn bar(test: u32, size: u32)
587
588fn foo() {
589 bar(1, $01+1$0);
590}
591"#,
592 r#"
593fn bar(test: u32, size: u32)
594
595fn foo() {
596 let $0size = 1+1;
597 bar(1, size);
598}
599"#,
600 )
601 }
602
603 #[test]
604 fn extract_var_parameter_name_has_precedence_over_type() {
605 check_assist(
606 extract_variable,
607 r#"
608struct TextSize(u32);
609fn bar(test: u32, size: TextSize)
610
611fn foo() {
612 bar(1, $0{ TextSize(1+1) }$0);
613}
614"#,
615 r#"
616struct TextSize(u32);
617fn bar(test: u32, size: TextSize)
618
619fn foo() {
620 let $0size = { TextSize(1+1) };
621 bar(1, size);
622}
623"#,
624 )
625 }
626
627 #[test]
628 fn extract_var_name_from_function() {
629 check_assist(
630 extract_variable,
631 r#"
632fn is_required(test: u32, size: u32) -> bool
633
634fn foo() -> bool {
635 $0is_required(1, 2)$0
636}
637"#,
638 r#"
639fn is_required(test: u32, size: u32) -> bool
640
641fn foo() -> bool {
642 let $0is_required = is_required(1, 2);
643 is_required
644}
645"#,
646 )
647 }
648
649 #[test]
650 fn extract_var_name_from_method() {
651 check_assist(
652 extract_variable,
653 r#"
654struct S;
655impl S {
656 fn bar(&self, n: u32) -> u32 { n }
657}
658
659fn foo() -> u32 {
660 $0S.bar(1)$0
661}
662"#,
663 r#"
664struct S;
665impl S {
666 fn bar(&self, n: u32) -> u32 { n }
667}
668
669fn foo() -> u32 {
670 let $0bar = S.bar(1);
671 bar
672}
673"#,
674 )
675 }
676
677 #[test]
678 fn extract_var_name_from_method_param() {
679 check_assist(
680 extract_variable,
681 r#"
682struct S;
683impl S {
684 fn bar(&self, n: u32, size: u32) { n }
685}
686
687fn foo() {
688 S.bar($01 + 1$0, 2)
689}
690"#,
691 r#"
692struct S;
693impl S {
694 fn bar(&self, n: u32, size: u32) { n }
695}
696
697fn foo() {
698 let $0n = 1 + 1;
699 S.bar(n, 2)
700}
701"#,
702 )
703 }
704
705 #[test]
706 fn extract_var_name_from_ufcs_method_param() {
707 check_assist(
708 extract_variable,
709 r#"
710struct S;
711impl S {
712 fn bar(&self, n: u32, size: u32) { n }
713}
714
715fn foo() {
716 S::bar(&S, $01 + 1$0, 2)
717}
718"#,
719 r#"
720struct S;
721impl S {
722 fn bar(&self, n: u32, size: u32) { n }
723}
724
725fn foo() {
726 let $0n = 1 + 1;
727 S::bar(&S, n, 2)
728}
729"#,
730 )
731 }
732
733 #[test]
734 fn extract_var_parameter_name_has_precedence_over_function() {
735 check_assist(
736 extract_variable,
737 r#"
738fn bar(test: u32, size: u32)
739
740fn foo() {
741 bar(1, $0symbol_size(1, 2)$0);
742}
743"#,
744 r#"
745fn bar(test: u32, size: u32)
746
747fn foo() {
748 let $0size = symbol_size(1, 2);
749 bar(1, size);
750}
751"#,
752 )
753 }
754
755 #[test]
560 fn test_extract_var_for_return_not_applicable() { 756 fn test_extract_var_for_return_not_applicable() {
561 check_assist_not_applicable(extract_variable, "fn foo() { $0return$0; } "); 757 check_assist_not_applicable(extract_variable, "fn foo() { $0return$0; } ");
562 } 758 }