aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/add_derive.rs6
-rw-r--r--crates/ra_assists/src/add_impl.rs8
-rw-r--r--crates/ra_assists/src/add_missing_impl_members.rs15
-rw-r--r--crates/ra_assists/src/assist_ctx.rs16
-rw-r--r--crates/ra_assists/src/auto_import.rs13
-rw-r--r--crates/ra_assists/src/change_visibility.rs10
-rw-r--r--crates/ra_assists/src/flip_binexpr.rs2
-rw-r--r--crates/ra_assists/src/flip_comma.rs10
-rw-r--r--crates/ra_assists/src/inline_local_variable.rs432
-rw-r--r--crates/ra_assists/src/introduce_variable.rs28
-rw-r--r--crates/ra_assists/src/remove_dbg.rs6
-rw-r--r--crates/ra_assists/src/replace_if_let_with_match.rs4
-rw-r--r--crates/ra_assists/src/split_import.rs4
13 files changed, 451 insertions, 103 deletions
diff --git a/crates/ra_assists/src/add_derive.rs b/crates/ra_assists/src/add_derive.rs
index e91b5eb8d..0c4cf2615 100644
--- a/crates/ra_assists/src/add_derive.rs
+++ b/crates/ra_assists/src/add_derive.rs
@@ -33,8 +33,10 @@ pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
33 33
34// Insert `derive` after doc comments. 34// Insert `derive` after doc comments.
35fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> { 35fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> {
36 let non_ws_child = 36 let non_ws_child = nominal
37 nominal.syntax().children().find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; 37 .syntax()
38 .children_with_tokens()
39 .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
38 Some(non_ws_child.range().start()) 40 Some(non_ws_child.range().start())
39} 41}
40 42
diff --git a/crates/ra_assists/src/add_impl.rs b/crates/ra_assists/src/add_impl.rs
index b292f188d..fa1c85890 100644
--- a/crates/ra_assists/src/add_impl.rs
+++ b/crates/ra_assists/src/add_impl.rs
@@ -1,7 +1,7 @@
1use join_to_string::join; 1use join_to_string::join;
2use hir::db::HirDatabase; 2use hir::db::HirDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, 4 ast::{self, AstNode, NameOwner, TypeParamsOwner},
5 TextUnit, 5 TextUnit,
6}; 6};
7 7
@@ -22,8 +22,10 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 buf.push_str(" "); 22 buf.push_str(" ");
23 buf.push_str(name.text().as_str()); 23 buf.push_str(name.text().as_str());
24 if let Some(type_params) = type_params { 24 if let Some(type_params) = type_params {
25 let lifetime_params = 25 let lifetime_params = type_params
26 type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text()); 26 .lifetime_params()
27 .filter_map(|it| it.lifetime_token())
28 .map(|it| it.text());
27 let type_params = 29 let type_params =
28 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); 30 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text());
29 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); 31 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs
index e13f54c4f..19a2d05bc 100644
--- a/crates/ra_assists/src/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/add_missing_impl_members.rs
@@ -1,9 +1,11 @@
1use std::fmt::Write;
2
1use crate::{Assist, AssistId, AssistCtx}; 3use crate::{Assist, AssistId, AssistCtx};
2 4
3use hir::Resolver; 5use hir::Resolver;
4use hir::db::HirDatabase; 6use hir::db::HirDatabase;
5use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; 7use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc};
6use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner}; 8use ra_syntax::ast::{self, AstNode, AstToken, FnDef, ImplItem, ImplItemKind, NameOwner};
7use ra_db::FilePosition; 9use ra_db::FilePosition;
8use ra_fmt::{leading_indent, reindent}; 10use ra_fmt::{leading_indent, reindent};
9 11
@@ -91,8 +93,9 @@ fn add_missing_impl_members_inner(
91 }; 93 };
92 94
93 let changed_range = { 95 let changed_range = {
94 let children = impl_item_list.syntax().children(); 96 let children = impl_item_list.syntax().children_with_tokens();
95 let last_whitespace = children.filter_map(ast::Whitespace::cast).last(); 97 let last_whitespace =
98 children.filter_map(|it| ast::Whitespace::cast(it.as_token()?)).last();
96 99
97 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| { 100 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| {
98 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}"); 101 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}");
@@ -134,13 +137,13 @@ fn resolve_target_trait_def(
134fn build_func_body(def: &ast::FnDef) -> String { 137fn build_func_body(def: &ast::FnDef) -> String {
135 let mut buf = String::new(); 138 let mut buf = String::new();
136 139
137 for child in def.syntax().children() { 140 for child in def.syntax().children_with_tokens() {
138 match (child.prev_sibling().map(|c| c.kind()), child.kind()) { 141 match (child.prev_sibling_or_token().map(|c| c.kind()), child.kind()) {
139 (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"), 142 (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"),
140 (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {} 143 (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {}
141 (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE) 144 (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE)
142 | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {} 145 | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {}
143 _ => child.text().push_to(&mut buf), 146 _ => write!(buf, "{}", child).unwrap(),
144 }; 147 };
145 } 148 }
146 149
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 4ad21c74b..e80e35738 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -2,8 +2,8 @@ use hir::db::HirDatabase;
2use ra_text_edit::TextEditBuilder; 2use ra_text_edit::TextEditBuilder;
3use ra_db::FileRange; 3use ra_db::FileRange;
4use ra_syntax::{ 4use ra_syntax::{
5 SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, 5 SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, SyntaxElement, SyntaxToken,
6 algo::{find_leaf_at_offset, find_node_at_offset, find_covering_node, LeafAtOffset}, 6 algo::{find_token_at_offset, find_node_at_offset, find_covering_element, TokenAtOffset},
7}; 7};
8use ra_fmt::{leading_indent, reindent}; 8use ra_fmt::{leading_indent, reindent};
9 9
@@ -104,15 +104,19 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
104 Some(self.assist) 104 Some(self.assist)
105 } 105 }
106 106
107 pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset<&'a SyntaxNode> { 107 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken<'a>> {
108 find_leaf_at_offset(self.source_file.syntax(), self.frange.range.start()) 108 find_token_at_offset(self.source_file.syntax(), self.frange.range.start())
109 } 109 }
110 110
111 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> { 111 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> {
112 find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) 112 find_node_at_offset(self.source_file.syntax(), self.frange.range.start())
113 } 113 }
114 pub(crate) fn covering_node(&self) -> &'a SyntaxNode { 114 pub(crate) fn covering_element(&self) -> SyntaxElement<'a> {
115 find_covering_node(self.source_file.syntax(), self.frange.range) 115 find_covering_element(self.source_file.syntax(), self.frange.range)
116 }
117
118 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement<'a> {
119 find_covering_element(self.source_file.syntax(), range)
116 } 120 }
117} 121}
118 122
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index 685dbed06..3fdf6b0d9 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -21,7 +21,7 @@ fn collect_path_segments_raw<'a>(
21) -> Option<usize> { 21) -> Option<usize> {
22 let oldlen = segments.len(); 22 let oldlen = segments.len();
23 loop { 23 loop {
24 let mut children = path.syntax().children(); 24 let mut children = path.syntax().children_with_tokens();
25 let (first, second, third) = ( 25 let (first, second, third) = (
26 children.next().map(|n| (n, n.kind())), 26 children.next().map(|n| (n, n.kind())),
27 children.next().map(|n| (n, n.kind())), 27 children.next().map(|n| (n, n.kind())),
@@ -29,11 +29,11 @@ fn collect_path_segments_raw<'a>(
29 ); 29 );
30 match (first, second, third) { 30 match (first, second, third) {
31 (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => { 31 (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => {
32 path = ast::Path::cast(subpath)?; 32 path = ast::Path::cast(subpath.as_node()?)?;
33 segments.push(ast::PathSegment::cast(segment)?); 33 segments.push(ast::PathSegment::cast(segment.as_node()?)?);
34 } 34 }
35 (Some((segment, PATH_SEGMENT)), _, _) => { 35 (Some((segment, PATH_SEGMENT)), _, _) => {
36 segments.push(ast::PathSegment::cast(segment)?); 36 segments.push(ast::PathSegment::cast(segment.as_node()?)?);
37 break; 37 break;
38 } 38 }
39 (_, _, _) => return None, 39 (_, _, _) => return None,
@@ -514,8 +514,7 @@ fn apply_auto_import<'a>(
514} 514}
515 515
516pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 516pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
517 let node = ctx.covering_node(); 517 let path: &ast::Path = ctx.node_at_offset()?;
518 let path = node.ancestors().find_map(ast::Path::cast)?;
519 // We don't want to mess with use statements 518 // We don't want to mess with use statements
520 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { 519 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
521 return None; 520 return None;
@@ -537,7 +536,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
537 ); 536 );
538 } 537 }
539 } else { 538 } else {
540 let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; 539 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?;
541 ctx.add_action( 540 ctx.add_action(
542 AssistId("auto_import"), 541 AssistId("auto_import"),
543 format!("import {} in the current file", fmt_segments(&segments)), 542 format!("import {} in the current file", fmt_segments(&segments)),
diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs
index 50c1be5ae..c63470726 100644
--- a/crates/ra_assists/src/change_visibility.rs
+++ b/crates/ra_assists/src/change_visibility.rs
@@ -15,13 +15,13 @@ pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
15} 15}
16 16
17fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 17fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 let item_keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() { 18 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
19 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true, 19 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
20 _ => false, 20 _ => false,
21 }); 21 });
22 22
23 let (offset, target) = if let Some(keyword) = item_keyword { 23 let (offset, target) = if let Some(keyword) = item_keyword {
24 let parent = keyword.parent()?; 24 let parent = keyword.parent();
25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; 25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
26 // Parent is not a definition, can't add visibility 26 // Parent is not a definition, can't add visibility
27 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 27 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
@@ -33,8 +33,8 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
33 } 33 }
34 (vis_offset(parent), keyword.range()) 34 (vis_offset(parent), keyword.range())
35 } else { 35 } else {
36 let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?; 36 let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?;
37 let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?; 37 let field = ident.parent().ancestors().find_map(ast::NamedFieldDef::cast)?;
38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() { 38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() {
39 return None; 39 return None;
40 } 40 }
@@ -51,7 +51,7 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
51} 51}
52 52
53fn vis_offset(node: &SyntaxNode) -> TextUnit { 53fn vis_offset(node: &SyntaxNode) -> TextUnit {
54 node.children() 54 node.children_with_tokens()
55 .skip_while(|it| match it.kind() { 55 .skip_while(|it| match it.kind() {
56 WHITESPACE | COMMENT | ATTR => true, 56 WHITESPACE | COMMENT | ATTR => true,
57 _ => false, 57 _ => false,
diff --git a/crates/ra_assists/src/flip_binexpr.rs b/crates/ra_assists/src/flip_binexpr.rs
index ec377642e..02d27f66d 100644
--- a/crates/ra_assists/src/flip_binexpr.rs
+++ b/crates/ra_assists/src/flip_binexpr.rs
@@ -8,7 +8,7 @@ pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis
8 let expr = ctx.node_at_offset::<BinExpr>()?; 8 let expr = ctx.node_at_offset::<BinExpr>()?;
9 let lhs = expr.lhs()?.syntax(); 9 let lhs = expr.lhs()?.syntax();
10 let rhs = expr.rhs()?.syntax(); 10 let rhs = expr.rhs()?.syntax();
11 let op_range = expr.op()?.range(); 11 let op_range = expr.op_token()?.range();
12 // The assist should be applied only if the cursor is on the operator 12 // The assist should be applied only if the cursor is on the operator
13 let cursor_in_range = ctx.frange.range.is_subrange(&op_range); 13 let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
14 if !cursor_in_range { 14 if !cursor_in_range {
diff --git a/crates/ra_assists/src/flip_comma.rs b/crates/ra_assists/src/flip_comma.rs
index 6b98cac68..a9b108111 100644
--- a/crates/ra_assists/src/flip_comma.rs
+++ b/crates/ra_assists/src/flip_comma.rs
@@ -8,13 +8,13 @@ use ra_syntax::{
8use crate::{AssistCtx, Assist, AssistId}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; 11 let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == COMMA)?;
12 let prev = non_trivia_sibling(comma, Direction::Prev)?; 12 let prev = non_trivia_sibling(comma.into(), Direction::Prev)?;
13 let next = non_trivia_sibling(comma, Direction::Next)?; 13 let next = non_trivia_sibling(comma.into(), Direction::Next)?;
14 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { 14 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| {
15 edit.target(comma.range()); 15 edit.target(comma.range());
16 edit.replace(prev.range(), next.text()); 16 edit.replace(prev.range(), next.to_string());
17 edit.replace(next.range(), prev.text()); 17 edit.replace(next.range(), prev.to_string());
18 }); 18 });
19 19
20 ctx.build() 20 ctx.build()
diff --git a/crates/ra_assists/src/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs
index bd3cdb970..950c2910b 100644
--- a/crates/ra_assists/src/inline_local_variable.rs
+++ b/crates/ra_assists/src/inline_local_variable.rs
@@ -1,7 +1,11 @@
1use hir::db::HirDatabase; 1use hir::{
2use hir::source_binder::function_from_child_node; 2 db::HirDatabase,
3use ra_syntax::{ast::{self, AstNode}, TextRange}; 3 source_binder::function_from_child_node,
4use ra_syntax::ast::{PatKind, ExprKind}; 4};
5use ra_syntax::{
6 ast::{self, AstNode, AstToken, PatKind, ExprKind},
7 TextRange,
8};
5 9
6use crate::{Assist, AssistCtx, AssistId}; 10use crate::{Assist, AssistCtx, AssistId};
7use crate::assist_ctx::AssistBuilder; 11use crate::assist_ctx::AssistBuilder;
@@ -15,61 +19,77 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
15 if bind_pat.is_mutable() { 19 if bind_pat.is_mutable() {
16 return None; 20 return None;
17 } 21 }
18 let initializer = let_stmt.initializer()?; 22 let initializer_expr = let_stmt.initializer();
19 let wrap_in_parens = match initializer.kind() { 23 let delete_range = if let Some(whitespace) = let_stmt
20 ExprKind::LambdaExpr(_) 24 .syntax()
21 | ExprKind::IfExpr(_) 25 .next_sibling_or_token()
22 | ExprKind::LoopExpr(_) 26 .and_then(|it| ast::Whitespace::cast(it.as_token()?))
23 | ExprKind::ForExpr(_)
24 | ExprKind::WhileExpr(_)
25 | ExprKind::ContinueExpr(_)
26 | ExprKind::BreakExpr(_)
27 | ExprKind::Label(_)
28 | ExprKind::ReturnExpr(_)
29 | ExprKind::MatchExpr(_)
30 | ExprKind::StructLit(_)
31 | ExprKind::CastExpr(_)
32 | ExprKind::PrefixExpr(_)
33 | ExprKind::RangeExpr(_)
34 | ExprKind::BinExpr(_) => true,
35 ExprKind::CallExpr(_)
36 | ExprKind::IndexExpr(_)
37 | ExprKind::MethodCallExpr(_)
38 | ExprKind::FieldExpr(_)
39 | ExprKind::TryExpr(_)
40 | ExprKind::RefExpr(_)
41 | ExprKind::Literal(_)
42 | ExprKind::TupleExpr(_)
43 | ExprKind::ArrayExpr(_)
44 | ExprKind::ParenExpr(_)
45 | ExprKind::PathExpr(_)
46 | ExprKind::BlockExpr(_) => false,
47 };
48
49 let delete_range = if let Some(whitespace) =
50 let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast)
51 { 27 {
52 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) 28 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
53 } else { 29 } else {
54 let_stmt.syntax().range() 30 let_stmt.syntax().range()
55 }; 31 };
56 32
57 let init_str = if wrap_in_parens {
58 format!("({})", initializer.syntax().text().to_string())
59 } else {
60 initializer.syntax().text().to_string()
61 };
62 let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?; 33 let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?;
63 let scope = function.scopes(ctx.db); 34 let scope = function.scopes(ctx.db);
64 let refs = scope.find_all_refs(bind_pat); 35 let refs = scope.find_all_refs(bind_pat);
65 36
37 let mut wrap_in_parens = vec![true; refs.len()];
38
39 for (i, desc) in refs.iter().enumerate() {
40 let usage_node = ctx
41 .covering_node_for_range(desc.range)
42 .ancestors()
43 .find_map(|node| ast::PathExpr::cast(node))?;
44 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
45 let usage_parent = match usage_parent_option {
46 Some(u) => u,
47 None => {
48 wrap_in_parens[i] = false;
49 continue;
50 }
51 };
52
53 wrap_in_parens[i] = match (initializer_expr?.kind(), usage_parent.kind()) {
54 (ExprKind::CallExpr(_), _)
55 | (ExprKind::IndexExpr(_), _)
56 | (ExprKind::MethodCallExpr(_), _)
57 | (ExprKind::FieldExpr(_), _)
58 | (ExprKind::TryExpr(_), _)
59 | (ExprKind::RefExpr(_), _)
60 | (ExprKind::Literal(_), _)
61 | (ExprKind::TupleExpr(_), _)
62 | (ExprKind::ArrayExpr(_), _)
63 | (ExprKind::ParenExpr(_), _)
64 | (ExprKind::PathExpr(_), _)
65 | (ExprKind::BlockExpr(_), _)
66 | (_, ExprKind::CallExpr(_))
67 | (_, ExprKind::TupleExpr(_))
68 | (_, ExprKind::ArrayExpr(_))
69 | (_, ExprKind::ParenExpr(_))
70 | (_, ExprKind::ForExpr(_))
71 | (_, ExprKind::WhileExpr(_))
72 | (_, ExprKind::BreakExpr(_))
73 | (_, ExprKind::ReturnExpr(_))
74 | (_, ExprKind::MatchExpr(_)) => false,
75 _ => true,
76 };
77 }
78
79 let init_str = initializer_expr?.syntax().text().to_string();
80 let init_in_paren = format!("({})", &init_str);
81
66 ctx.add_action( 82 ctx.add_action(
67 AssistId("inline_local_variable"), 83 AssistId("inline_local_variable"),
68 "inline local variable", 84 "inline local variable",
69 move |edit: &mut AssistBuilder| { 85 move |edit: &mut AssistBuilder| {
70 edit.delete(delete_range); 86 edit.delete(delete_range);
71 for desc in refs { 87 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
72 edit.replace(desc.range, init_str.clone()) 88 if should_wrap {
89 edit.replace(desc.range, init_in_paren.clone())
90 } else {
91 edit.replace(desc.range, init_str.clone())
92 }
73 } 93 }
74 edit.set_cursor(delete_range.start()) 94 edit.set_cursor(delete_range.start())
75 }, 95 },
@@ -147,7 +167,7 @@ fn foo() {
147 167
148 } 168 }
149 let b = (1 + 1) * 10; 169 let b = (1 + 1) * 10;
150 bar((1 + 1)); 170 bar(1 + 1);
151}", 171}",
152 ); 172 );
153 } 173 }
@@ -215,7 +235,7 @@ fn foo() {
215 235
216 } 236 }
217 let b = (bar(1) as u64) * 10; 237 let b = (bar(1) as u64) * 10;
218 bar((bar(1) as u64)); 238 bar(bar(1) as u64);
219}", 239}",
220 ); 240 );
221 } 241 }
@@ -295,4 +315,324 @@ fn foo() {
295}", 315}",
296 ); 316 );
297 } 317 }
318
319 #[test]
320 fn test_call_expr() {
321 check_assist(
322 inline_local_varialbe,
323 "
324fn foo() {
325 let a<|> = bar(10 + 1);
326 let b = a * 10;
327 let c = a as usize;
328}",
329 "
330fn foo() {
331 <|>let b = bar(10 + 1) * 10;
332 let c = bar(10 + 1) as usize;
333}",
334 );
335 }
336
337 #[test]
338 fn test_index_expr() {
339 check_assist(
340 inline_local_varialbe,
341 "
342fn foo() {
343 let x = vec![1, 2, 3];
344 let a<|> = x[0];
345 let b = a * 10;
346 let c = a as usize;
347}",
348 "
349fn foo() {
350 let x = vec![1, 2, 3];
351 <|>let b = x[0] * 10;
352 let c = x[0] as usize;
353}",
354 );
355 }
356
357 #[test]
358 fn test_method_call_expr() {
359 check_assist(
360 inline_local_varialbe,
361 "
362fn foo() {
363 let bar = vec![1];
364 let a<|> = bar.len();
365 let b = a * 10;
366 let c = a as usize;
367}",
368 "
369fn foo() {
370 let bar = vec![1];
371 <|>let b = bar.len() * 10;
372 let c = bar.len() as usize;
373}",
374 );
375 }
376
377 #[test]
378 fn test_field_expr() {
379 check_assist(
380 inline_local_varialbe,
381 "
382struct Bar {
383 foo: usize
384}
385
386fn foo() {
387 let bar = Bar { foo: 1 };
388 let a<|> = bar.foo;
389 let b = a * 10;
390 let c = a as usize;
391}",
392 "
393struct Bar {
394 foo: usize
395}
396
397fn foo() {
398 let bar = Bar { foo: 1 };
399 <|>let b = bar.foo * 10;
400 let c = bar.foo as usize;
401}",
402 );
403 }
404
405 #[test]
406 fn test_try_expr() {
407 check_assist(
408 inline_local_varialbe,
409 "
410fn foo() -> Option<usize> {
411 let bar = Some(1);
412 let a<|> = bar?;
413 let b = a * 10;
414 let c = a as usize;
415 None
416}",
417 "
418fn foo() -> Option<usize> {
419 let bar = Some(1);
420 <|>let b = bar? * 10;
421 let c = bar? as usize;
422 None
423}",
424 );
425 }
426
427 #[test]
428 fn test_ref_expr() {
429 check_assist(
430 inline_local_varialbe,
431 "
432fn foo() {
433 let bar = 10;
434 let a<|> = &bar;
435 let b = a * 10;
436}",
437 "
438fn foo() {
439 let bar = 10;
440 <|>let b = &bar * 10;
441}",
442 );
443 }
444
445 #[test]
446 fn test_tuple_expr() {
447 check_assist(
448 inline_local_varialbe,
449 "
450fn foo() {
451 let a<|> = (10, 20);
452 let b = a[0];
453}",
454 "
455fn foo() {
456 <|>let b = (10, 20)[0];
457}",
458 );
459 }
460
461 #[test]
462 fn test_array_expr() {
463 check_assist(
464 inline_local_varialbe,
465 "
466fn foo() {
467 let a<|> = [1, 2, 3];
468 let b = a.len();
469}",
470 "
471fn foo() {
472 <|>let b = [1, 2, 3].len();
473}",
474 );
475 }
476
477 #[test]
478 fn test_paren() {
479 check_assist(
480 inline_local_varialbe,
481 "
482fn foo() {
483 let a<|> = (10 + 20);
484 let b = a * 10;
485 let c = a as usize;
486}",
487 "
488fn foo() {
489 <|>let b = (10 + 20) * 10;
490 let c = (10 + 20) as usize;
491}",
492 );
493 }
494
495 #[test]
496 fn test_path_expr() {
497 check_assist(
498 inline_local_varialbe,
499 "
500fn foo() {
501 let d = 10;
502 let a<|> = d;
503 let b = a * 10;
504 let c = a as usize;
505}",
506 "
507fn foo() {
508 let d = 10;
509 <|>let b = d * 10;
510 let c = d as usize;
511}",
512 );
513 }
514
515 #[test]
516 fn test_block_expr() {
517 check_assist(
518 inline_local_varialbe,
519 "
520fn foo() {
521 let a<|> = { 10 };
522 let b = a * 10;
523 let c = a as usize;
524}",
525 "
526fn foo() {
527 <|>let b = { 10 } * 10;
528 let c = { 10 } as usize;
529}",
530 );
531 }
532
533 #[test]
534 fn test_used_in_different_expr1() {
535 check_assist(
536 inline_local_varialbe,
537 "
538fn foo() {
539 let a<|> = 10 + 20;
540 let b = a * 10;
541 let c = (a, 20);
542 let d = [a, 10];
543 let e = (a);
544}",
545 "
546fn foo() {
547 <|>let b = (10 + 20) * 10;
548 let c = (10 + 20, 20);
549 let d = [10 + 20, 10];
550 let e = (10 + 20);
551}",
552 );
553 }
554
555 #[test]
556 fn test_used_in_for_expr() {
557 check_assist(
558 inline_local_varialbe,
559 "
560fn foo() {
561 let a<|> = vec![10, 20];
562 for i in a {}
563}",
564 "
565fn foo() {
566 <|>for i in vec![10, 20] {}
567}",
568 );
569 }
570
571 #[test]
572 fn test_used_in_while_expr() {
573 check_assist(
574 inline_local_varialbe,
575 "
576fn foo() {
577 let a<|> = 1 > 0;
578 while a {}
579}",
580 "
581fn foo() {
582 <|>while 1 > 0 {}
583}",
584 );
585 }
586
587 #[test]
588 fn test_used_in_break_expr() {
589 check_assist(
590 inline_local_varialbe,
591 "
592fn foo() {
593 let a<|> = 1 + 1;
594 loop {
595 break a;
596 }
597}",
598 "
599fn foo() {
600 <|>loop {
601 break 1 + 1;
602 }
603}",
604 );
605 }
606
607 #[test]
608 fn test_used_in_return_expr() {
609 check_assist(
610 inline_local_varialbe,
611 "
612fn foo() {
613 let a<|> = 1 > 0;
614 return a;
615}",
616 "
617fn foo() {
618 <|>return 1 > 0;
619}",
620 );
621 }
622
623 #[test]
624 fn test_used_in_match_expr() {
625 check_assist(
626 inline_local_varialbe,
627 "
628fn foo() {
629 let a<|> = 1 > 0;
630 match a {}
631}",
632 "
633fn foo() {
634 <|>match 1 > 0 {}
635}",
636 );
637 }
298} 638}
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs
index 353bc4105..fb7333c8c 100644
--- a/crates/ra_assists/src/introduce_variable.rs
+++ b/crates/ra_assists/src/introduce_variable.rs
@@ -2,9 +2,8 @@ use test_utils::tested_by;
2use hir::db::HirDatabase; 2use hir::db::HirDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 SyntaxKind::{ 5 SyntaxNode, TextUnit,
6 WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT 6 SyntaxKind::{WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT},
7 }, SyntaxNode, TextUnit,
8}; 7};
9 8
10use crate::{AssistCtx, Assist, AssistId}; 9use crate::{AssistCtx, Assist, AssistId};
@@ -13,14 +12,14 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
13 if ctx.frange.range.is_empty() { 12 if ctx.frange.range.is_empty() {
14 return None; 13 return None;
15 } 14 }
16 let node = ctx.covering_node(); 15 let node = ctx.covering_element();
17 if node.kind() == COMMENT { 16 if node.kind() == COMMENT {
18 tested_by!(introduce_var_in_comment_is_not_applicable); 17 tested_by!(introduce_var_in_comment_is_not_applicable);
19 return None; 18 return None;
20 } 19 }
21 let expr = node.ancestors().find_map(valid_target_expr)?; 20 let expr = node.ancestors().find_map(valid_target_expr)?;
22 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; 21 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?;
23 let indent = anchor_stmt.prev_sibling()?; 22 let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?;
24 if indent.kind() != WHITESPACE { 23 if indent.kind() != WHITESPACE {
25 return None; 24 return None;
26 } 25 }
@@ -54,16 +53,15 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
54 // We want to maintain the indent level, 53 // We want to maintain the indent level,
55 // but we do not want to duplicate possible 54 // but we do not want to duplicate possible
56 // extra newlines in the indent block 55 // extra newlines in the indent block
57 for chunk in indent.text().chunks() { 56 let text = indent.text();
58 if chunk.starts_with("\r\n") { 57 if text.starts_with("\r\n") {
59 buf.push_str("\r\n"); 58 buf.push_str("\r\n");
60 buf.push_str(chunk.trim_start_matches("\r\n")); 59 buf.push_str(text.trim_start_matches("\r\n"));
61 } else if chunk.starts_with("\n") { 60 } else if text.starts_with("\n") {
62 buf.push_str("\n"); 61 buf.push_str("\n");
63 buf.push_str(chunk.trim_start_matches("\n")); 62 buf.push_str(text.trim_start_matches("\n"));
64 } else { 63 } else {
65 buf.push_str(chunk); 64 buf.push_str(text);
66 }
67 } 65 }
68 66
69 edit.target(expr.syntax().range()); 67 edit.target(expr.syntax().range());
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs
index 6ea48d909..ae9958f11 100644
--- a/crates/ra_assists/src/remove_dbg.rs
+++ b/crates/ra_assists/src/remove_dbg.rs
@@ -62,15 +62,15 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
62 let name_ref = path.segment()?.name_ref()?; 62 let name_ref = path.segment()?.name_ref()?;
63 63
64 // Make sure it is actually a dbg-macro call, dbg followed by ! 64 // Make sure it is actually a dbg-macro call, dbg followed by !
65 let excl = path.syntax().next_sibling()?; 65 let excl = path.syntax().next_sibling_or_token()?;
66 66
67 if name_ref.text() != macro_name || excl.kind() != EXCL { 67 if name_ref.text() != macro_name || excl.kind() != EXCL {
68 return None; 68 return None;
69 } 69 }
70 70
71 let node = macro_call.token_tree()?.syntax(); 71 let node = macro_call.token_tree()?.syntax();
72 let first_child = node.first_child()?; 72 let first_child = node.first_child_or_token()?;
73 let last_child = node.last_child()?; 73 let last_child = node.last_child_or_token()?;
74 74
75 match (first_child.kind(), last_child.kind()) { 75 match (first_child.kind(), last_child.kind()) {
76 (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true), 76 (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true),
diff --git a/crates/ra_assists/src/replace_if_let_with_match.rs b/crates/ra_assists/src/replace_if_let_with_match.rs
index 230573499..2b451f08d 100644
--- a/crates/ra_assists/src/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/replace_if_let_with_match.rs
@@ -11,8 +11,8 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) ->
11 let expr = cond.expr()?; 11 let expr = cond.expr()?;
12 let then_block = if_expr.then_branch()?; 12 let then_block = if_expr.then_branch()?;
13 let else_block = match if_expr.else_branch()? { 13 let else_block = match if_expr.else_branch()? {
14 ast::ElseBranchFlavor::Block(it) => it, 14 ast::ElseBranch::Block(it) => it,
15 ast::ElseBranchFlavor::IfExpr(_) => return None, 15 ast::ElseBranch::IfExpr(_) => return None,
16 }; 16 };
17 17
18 ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { 18 ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| {
diff --git a/crates/ra_assists/src/split_import.rs b/crates/ra_assists/src/split_import.rs
index dd5be4e91..4bf1852db 100644
--- a/crates/ra_assists/src/split_import.rs
+++ b/crates/ra_assists/src/split_import.rs
@@ -8,8 +8,8 @@ use ra_syntax::{
8use crate::{AssistCtx, Assist, AssistId}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; 11 let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?;
12 let path = colon_colon.parent().and_then(ast::Path::cast)?; 12 let path = ast::Path::cast(colon_colon.parent())?;
13 let top_path = generate(Some(path), |it| it.parent_path()).last()?; 13 let top_path = generate(Some(path), |it| it.parent_path()).last()?;
14 14
15 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast); 15 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast);