aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-07-19 09:24:41 +0100
committerAleksey Kladov <[email protected]>2019-07-19 11:16:25 +0100
commit0343c4a815a0e82d5e55e76a01d21b0f7a00ff5b (patch)
tree126bafdfcbcb04741b87876d6204c449113d96b5 /crates/ra_assists
parente2b28f5bb8043e92b10f6a40696131007fc9dfe2 (diff)
migrate ra_assists to the new AST
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/add_derive.rs2
-rw-r--r--crates/ra_assists/src/add_explicit_type.rs2
-rw-r--r--crates/ra_assists/src/add_impl.rs6
-rw-r--r--crates/ra_assists/src/add_missing_impl_members.rs46
-rw-r--r--crates/ra_assists/src/assist_ctx.rs14
-rw-r--r--crates/ra_assists/src/ast_editor.rs123
-rw-r--r--crates/ra_assists/src/auto_import.rs143
-rw-r--r--crates/ra_assists/src/change_visibility.rs4
-rw-r--r--crates/ra_assists/src/fill_match_arms.rs4
-rw-r--r--crates/ra_assists/src/flip_binexpr.rs4
-rw-r--r--crates/ra_assists/src/flip_comma.rs4
-rw-r--r--crates/ra_assists/src/inline_local_variable.rs10
-rw-r--r--crates/ra_assists/src/introduce_variable.rs24
-rw-r--r--crates/ra_assists/src/move_guard.rs10
-rw-r--r--crates/ra_assists/src/remove_dbg.rs6
-rw-r--r--crates/ra_assists/src/replace_if_let_with_match.rs13
16 files changed, 212 insertions, 203 deletions
diff --git a/crates/ra_assists/src/add_derive.rs b/crates/ra_assists/src/add_derive.rs
index bf7d55d6d..f19196f53 100644
--- a/crates/ra_assists/src/add_derive.rs
+++ b/crates/ra_assists/src/add_derive.rs
@@ -9,7 +9,7 @@ use crate::{Assist, AssistCtx, AssistId};
9 9
10pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let nominal = ctx.node_at_offset::<ast::NominalDef>()?; 11 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
12 let node_start = derive_insertion_offset(nominal)?; 12 let node_start = derive_insertion_offset(&nominal)?;
13 ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { 13 ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| {
14 let derive_attr = nominal 14 let derive_attr = nominal
15 .attrs() 15 .attrs()
diff --git a/crates/ra_assists/src/add_explicit_type.rs b/crates/ra_assists/src/add_explicit_type.rs
index bb47a32f0..a69cfc8e3 100644
--- a/crates/ra_assists/src/add_explicit_type.rs
+++ b/crates/ra_assists/src/add_explicit_type.rs
@@ -27,7 +27,7 @@ pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<
27 // Infer type 27 // Infer type
28 let db = ctx.db; 28 let db = ctx.db;
29 let analyzer = hir::SourceAnalyzer::new(db, ctx.frange.file_id, stmt.syntax(), None); 29 let analyzer = hir::SourceAnalyzer::new(db, ctx.frange.file_id, stmt.syntax(), None);
30 let ty = analyzer.type_of(db, expr)?; 30 let ty = analyzer.type_of(db, &expr)?;
31 // Assist not applicable if the type is unknown 31 // Assist not applicable if the type is unknown
32 if is_unknown(&ty) { 32 if is_unknown(&ty) {
33 return None; 33 return None;
diff --git a/crates/ra_assists/src/add_impl.rs b/crates/ra_assists/src/add_impl.rs
index b81922c1d..cebc19539 100644
--- a/crates/ra_assists/src/add_impl.rs
+++ b/crates/ra_assists/src/add_impl.rs
@@ -16,7 +16,7 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
16 let start_offset = nominal.syntax().range().end(); 16 let start_offset = nominal.syntax().range().end();
17 let mut buf = String::new(); 17 let mut buf = String::new();
18 buf.push_str("\n\nimpl"); 18 buf.push_str("\n\nimpl");
19 if let Some(type_params) = type_params { 19 if let Some(type_params) = &type_params {
20 type_params.syntax().text().push_to(&mut buf); 20 type_params.syntax().text().push_to(&mut buf);
21 } 21 }
22 buf.push_str(" "); 22 buf.push_str(" ");
@@ -25,9 +25,9 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
25 let lifetime_params = type_params 25 let lifetime_params = type_params
26 .lifetime_params() 26 .lifetime_params()
27 .filter_map(|it| it.lifetime_token()) 27 .filter_map(|it| it.lifetime_token())
28 .map(|it| it.text()); 28 .map(|it| it.text().clone());
29 let type_params = 29 let type_params =
30 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().clone());
31 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);
32 } 32 }
33 buf.push_str(" {\n"); 33 buf.push_str(" {\n");
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs
index 6ffdad0b1..b992a4dc8 100644
--- a/crates/ra_assists/src/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/add_missing_impl_members.rs
@@ -5,8 +5,8 @@ use crate::{
5 5
6use hir::{db::HirDatabase, HasSource}; 6use hir::{db::HirDatabase, HasSource};
7use ra_db::FilePosition; 7use ra_db::FilePosition;
8use ra_syntax::ast::{self, AstNode, ImplItem, ImplItemKind, NameOwner}; 8use ra_syntax::ast::{self, AstNode, ImplItemKind, NameOwner};
9use ra_syntax::{SmolStr, TreeArc}; 9use ra_syntax::SmolStr;
10 10
11#[derive(PartialEq)] 11#[derive(PartialEq)]
12enum AddMissingImplMembersMode { 12enum AddMissingImplMembersMode {
@@ -46,16 +46,16 @@ fn add_missing_impl_members_inner(
46 let position = FilePosition { file_id, offset: impl_node.syntax().range().start() }; 46 let position = FilePosition { file_id, offset: impl_node.syntax().range().start() };
47 let analyzer = hir::SourceAnalyzer::new(ctx.db, position.file_id, impl_node.syntax(), None); 47 let analyzer = hir::SourceAnalyzer::new(ctx.db, position.file_id, impl_node.syntax(), None);
48 48
49 resolve_target_trait_def(ctx.db, &analyzer, impl_node)? 49 resolve_target_trait_def(ctx.db, &analyzer, &impl_node)?
50 }; 50 };
51 51
52 let def_name = |kind| -> Option<&SmolStr> { 52 let def_name = |kind| -> Option<SmolStr> {
53 match kind { 53 match kind {
54 ImplItemKind::FnDef(def) => def.name(), 54 ast::ImplItemKind::FnDef(def) => def.name(),
55 ImplItemKind::TypeAliasDef(def) => def.name(), 55 ast::ImplItemKind::TypeAliasDef(def) => def.name(),
56 ImplItemKind::ConstDef(def) => def.name(), 56 ast::ImplItemKind::ConstDef(def) => def.name(),
57 } 57 }
58 .map(ast::Name::text) 58 .map(|it| it.text().clone())
59 }; 59 };
60 60
61 let trait_items = trait_def.item_list()?.impl_items(); 61 let trait_items = trait_def.item_list()?.impl_items();
@@ -78,18 +78,13 @@ fn add_missing_impl_members_inner(
78 78
79 ctx.add_action(AssistId(assist_id), label, |edit| { 79 ctx.add_action(AssistId(assist_id), label, |edit| {
80 let n_existing_items = impl_item_list.impl_items().count(); 80 let n_existing_items = impl_item_list.impl_items().count();
81 let items: Vec<_> = missing_items 81 let items = missing_items.into_iter().map(|it| match it.kind() {
82 .into_iter() 82 ImplItemKind::FnDef(def) => strip_docstring(add_body(def).into()),
83 .map(|it| match it.kind() { 83 _ => strip_docstring(it),
84 ImplItemKind::FnDef(def) => { 84 });
85 strip_docstring(ImplItem::cast(add_body(def).syntax()).unwrap())
86 }
87 _ => strip_docstring(it),
88 })
89 .collect();
90 let mut ast_editor = AstEditor::new(impl_item_list); 85 let mut ast_editor = AstEditor::new(impl_item_list);
91 86
92 ast_editor.append_items(items.iter().map(|it| &**it)); 87 ast_editor.append_items(items);
93 88
94 let first_new_item = ast_editor.ast().impl_items().nth(n_existing_items).unwrap(); 89 let first_new_item = ast_editor.ast().impl_items().nth(n_existing_items).unwrap();
95 let cursor_position = first_new_item.syntax().range().start(); 90 let cursor_position = first_new_item.syntax().range().start();
@@ -101,14 +96,14 @@ fn add_missing_impl_members_inner(
101 ctx.build() 96 ctx.build()
102} 97}
103 98
104fn strip_docstring(item: &ast::ImplItem) -> TreeArc<ast::ImplItem> { 99fn strip_docstring(item: ast::ImplItem) -> ast::ImplItem {
105 let mut ast_editor = AstEditor::new(item); 100 let mut ast_editor = AstEditor::new(item);
106 ast_editor.strip_attrs_and_docs(); 101 ast_editor.strip_attrs_and_docs();
107 ast_editor.ast().to_owned() 102 ast_editor.ast().to_owned()
108} 103}
109 104
110fn add_body(fn_def: &ast::FnDef) -> TreeArc<ast::FnDef> { 105fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
111 let mut ast_editor = AstEditor::new(fn_def); 106 let mut ast_editor = AstEditor::new(fn_def.clone());
112 if fn_def.body().is_none() { 107 if fn_def.body().is_none() {
113 ast_editor.set_body(&AstBuilder::<ast::Block>::single_expr( 108 ast_editor.set_body(&AstBuilder::<ast::Block>::single_expr(
114 &AstBuilder::<ast::Expr>::unimplemented(), 109 &AstBuilder::<ast::Expr>::unimplemented(),
@@ -123,9 +118,12 @@ fn resolve_target_trait_def(
123 db: &impl HirDatabase, 118 db: &impl HirDatabase,
124 analyzer: &hir::SourceAnalyzer, 119 analyzer: &hir::SourceAnalyzer,
125 impl_block: &ast::ImplBlock, 120 impl_block: &ast::ImplBlock,
126) -> Option<TreeArc<ast::TraitDef>> { 121) -> Option<ast::TraitDef> {
127 let ast_path = 122 let ast_path = impl_block
128 impl_block.target_trait().map(AstNode::syntax).and_then(ast::PathType::cast)?.path()?; 123 .target_trait()
124 .map(|it| it.syntax().clone())
125 .and_then(ast::PathType::cast)?
126 .path()?;
129 127
130 match analyzer.resolve_path(db, &ast_path) { 128 match analyzer.resolve_path(db, &ast_path) {
131 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).ast), 129 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).ast),
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 34b207154..e52085f85 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -49,7 +49,7 @@ pub(crate) enum Assist {
49pub(crate) struct AssistCtx<'a, DB> { 49pub(crate) struct AssistCtx<'a, DB> {
50 pub(crate) db: &'a DB, 50 pub(crate) db: &'a DB,
51 pub(crate) frange: FileRange, 51 pub(crate) frange: FileRange,
52 source_file: &'a SourceFile, 52 source_file: SourceFile,
53 should_compute_edit: bool, 53 should_compute_edit: bool,
54 assist: Assist, 54 assist: Assist,
55} 55}
@@ -59,7 +59,7 @@ impl<'a, DB> Clone for AssistCtx<'a, DB> {
59 AssistCtx { 59 AssistCtx {
60 db: self.db, 60 db: self.db,
61 frange: self.frange, 61 frange: self.frange,
62 source_file: self.source_file, 62 source_file: self.source_file.clone(),
63 should_compute_edit: self.should_compute_edit, 63 should_compute_edit: self.should_compute_edit,
64 assist: self.assist.clone(), 64 assist: self.assist.clone(),
65 } 65 }
@@ -104,18 +104,18 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
104 Some(self.assist) 104 Some(self.assist)
105 } 105 }
106 106
107 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken<'a>> { 107 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
108 find_token_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<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_element(&self) -> SyntaxElement<'a> { 114 pub(crate) fn covering_element(&self) -> SyntaxElement {
115 find_covering_element(self.source_file.syntax(), self.frange.range) 115 find_covering_element(self.source_file.syntax(), self.frange.range)
116 } 116 }
117 117
118 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement<'a> { 118 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement {
119 find_covering_element(self.source_file.syntax(), range) 119 find_covering_element(self.source_file.syntax(), range)
120 } 120 }
121} 121}
@@ -139,7 +139,7 @@ impl AssistBuilder {
139 ) { 139 ) {
140 let mut replace_with = replace_with.into(); 140 let mut replace_with = replace_with.into();
141 if let Some(indent) = leading_indent(node) { 141 if let Some(indent) = leading_indent(node) {
142 replace_with = reindent(&replace_with, indent) 142 replace_with = reindent(&replace_with, &indent)
143 } 143 }
144 self.replace(node.range(), replace_with) 144 self.replace(node.range(), replace_with)
145 } 145 }
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 7b743c9f0..5fbcadfee 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -4,18 +4,18 @@ use arrayvec::ArrayVec;
4use hir::Name; 4use hir::Name;
5use ra_fmt::leading_indent; 5use ra_fmt::leading_indent;
6use ra_syntax::{ 6use ra_syntax::{
7 ast, AstNode, Direction, InsertPosition, SourceFile, SyntaxElement, SyntaxKind::*, TreeArc, T, 7 ast, AstNode, Direction, InsertPosition, SourceFile, SyntaxElement, SyntaxKind::*, T,
8}; 8};
9use ra_text_edit::TextEditBuilder; 9use ra_text_edit::TextEditBuilder;
10 10
11pub struct AstEditor<N: AstNode> { 11pub struct AstEditor<N: AstNode> {
12 original_ast: TreeArc<N>, 12 original_ast: N,
13 ast: TreeArc<N>, 13 ast: N,
14} 14}
15 15
16impl<N: AstNode> AstEditor<N> { 16impl<N: AstNode> AstEditor<N> {
17 pub fn new(node: &N) -> AstEditor<N> { 17 pub fn new(node: N) -> AstEditor<N> {
18 AstEditor { original_ast: node.to_owned(), ast: node.to_owned() } 18 AstEditor { original_ast: node.clone(), ast: node }
19 } 19 }
20 20
21 pub fn into_text_edit(self, builder: &mut TextEditBuilder) { 21 pub fn into_text_edit(self, builder: &mut TextEditBuilder) {
@@ -26,27 +26,27 @@ impl<N: AstNode> AstEditor<N> {
26 } 26 }
27 27
28 pub fn ast(&self) -> &N { 28 pub fn ast(&self) -> &N {
29 &*self.ast 29 &self.ast
30 } 30 }
31 31
32 #[must_use] 32 #[must_use]
33 fn insert_children<'a>( 33 fn insert_children(
34 &self, 34 &self,
35 position: InsertPosition<SyntaxElement<'_>>, 35 position: InsertPosition<SyntaxElement>,
36 to_insert: impl Iterator<Item = SyntaxElement<'a>>, 36 to_insert: impl Iterator<Item = SyntaxElement>,
37 ) -> TreeArc<N> { 37 ) -> N {
38 let new_syntax = self.ast().syntax().insert_children(position, to_insert); 38 let new_syntax = self.ast().syntax().insert_children(position, to_insert);
39 N::cast(&new_syntax).unwrap().to_owned() 39 N::cast(new_syntax).unwrap()
40 } 40 }
41 41
42 #[must_use] 42 #[must_use]
43 fn replace_children<'a>( 43 fn replace_children(
44 &self, 44 &self,
45 to_delete: RangeInclusive<SyntaxElement<'_>>, 45 to_delete: RangeInclusive<SyntaxElement>,
46 to_insert: impl Iterator<Item = SyntaxElement<'a>>, 46 to_insert: impl Iterator<Item = SyntaxElement>,
47 ) -> TreeArc<N> { 47 ) -> N {
48 let new_syntax = self.ast().syntax().replace_children(to_delete, to_insert); 48 let new_syntax = self.ast().syntax().replace_children(to_delete, to_insert);
49 N::cast(&new_syntax).unwrap().to_owned() 49 N::cast(new_syntax).unwrap()
50 } 50 }
51 51
52 fn do_make_multiline(&mut self) { 52 fn do_make_multiline(&mut self) {
@@ -66,16 +66,18 @@ impl<N: AstNode> AstEditor<N> {
66 if ws.text().contains('\n') { 66 if ws.text().contains('\n') {
67 return; 67 return;
68 } 68 }
69 Some(ws) 69 Some(ws.clone())
70 } 70 }
71 }; 71 };
72 72
73 let indent = leading_indent(self.ast().syntax()).unwrap_or(""); 73 let indent = leading_indent(self.ast().syntax()).unwrap_or("".into());
74 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 74 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
75 let to_insert = iter::once(ws.ws().into()); 75 let to_insert = iter::once(ws.ws().into());
76 self.ast = match existing_ws { 76 self.ast = match existing_ws {
77 None => self.insert_children(InsertPosition::After(l_curly), to_insert), 77 None => self.insert_children(InsertPosition::After(l_curly), to_insert),
78 Some(ws) => self.replace_children(RangeInclusive::new(ws.into(), ws.into()), to_insert), 78 Some(ws) => {
79 self.replace_children(RangeInclusive::new(ws.clone().into(), ws.into()), to_insert)
80 }
79 }; 81 };
80 } 82 }
81} 83}
@@ -95,7 +97,7 @@ impl AstEditor<ast::NamedFieldList> {
95 let space = if is_multiline { 97 let space = if is_multiline {
96 ws = tokens::WsBuilder::new(&format!( 98 ws = tokens::WsBuilder::new(&format!(
97 "\n{} ", 99 "\n{} ",
98 leading_indent(self.ast().syntax()).unwrap_or("") 100 leading_indent(self.ast().syntax()).unwrap_or("".into())
99 )); 101 ));
100 ws.ws() 102 ws.ws()
101 } else { 103 } else {
@@ -104,7 +106,7 @@ impl AstEditor<ast::NamedFieldList> {
104 106
105 let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new(); 107 let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new();
106 to_insert.push(space.into()); 108 to_insert.push(space.into());
107 to_insert.push(field.syntax().into()); 109 to_insert.push(field.syntax().clone().into());
108 to_insert.push(tokens::comma().into()); 110 to_insert.push(tokens::comma().into());
109 111
110 macro_rules! after_l_curly { 112 macro_rules! after_l_curly {
@@ -127,7 +129,7 @@ impl AstEditor<ast::NamedFieldList> {
127 InsertPosition::After(comma) 129 InsertPosition::After(comma)
128 } else { 130 } else {
129 to_insert.insert(0, tokens::comma().into()); 131 to_insert.insert(0, tokens::comma().into());
130 InsertPosition::After($anchor.syntax().into()) 132 InsertPosition::After($anchor.syntax().clone().into())
131 } 133 }
132 }; 134 };
133 }; 135 };
@@ -144,7 +146,9 @@ impl AstEditor<ast::NamedFieldList> {
144 None => after_l_curly!(), 146 None => after_l_curly!(),
145 } 147 }
146 } 148 }
147 InsertPosition::Before(anchor) => InsertPosition::Before(anchor.syntax().into()), 149 InsertPosition::Before(anchor) => {
150 InsertPosition::Before(anchor.syntax().clone().into())
151 }
148 InsertPosition::After(anchor) => after_field!(anchor), 152 InsertPosition::After(anchor) => after_field!(anchor),
149 }; 153 };
150 154
@@ -157,7 +161,7 @@ impl AstEditor<ast::NamedFieldList> {
157} 161}
158 162
159impl AstEditor<ast::ItemList> { 163impl AstEditor<ast::ItemList> {
160 pub fn append_items<'a>(&mut self, items: impl Iterator<Item = &'a ast::ImplItem>) { 164 pub fn append_items(&mut self, items: impl Iterator<Item = ast::ImplItem>) {
161 let n_existing_items = self.ast().impl_items().count(); 165 let n_existing_items = self.ast().impl_items().count();
162 if n_existing_items == 0 { 166 if n_existing_items == 0 {
163 self.do_make_multiline(); 167 self.do_make_multiline();
@@ -165,22 +169,23 @@ impl AstEditor<ast::ItemList> {
165 items.for_each(|it| self.append_item(it)); 169 items.for_each(|it| self.append_item(it));
166 } 170 }
167 171
168 pub fn append_item(&mut self, item: &ast::ImplItem) { 172 pub fn append_item(&mut self, item: ast::ImplItem) {
169 let (indent, position) = match self.ast().impl_items().last() { 173 let (indent, position) = match self.ast().impl_items().last() {
170 Some(it) => ( 174 Some(it) => (
171 leading_indent(it.syntax()).unwrap_or("").to_string(), 175 leading_indent(it.syntax()).unwrap_or_default().to_string(),
172 InsertPosition::After(it.syntax().into()), 176 InsertPosition::After(it.syntax().clone().into()),
173 ), 177 ),
174 None => match self.l_curly() { 178 None => match self.l_curly() {
175 Some(it) => ( 179 Some(it) => (
176 " ".to_string() + leading_indent(self.ast().syntax()).unwrap_or(""), 180 " ".to_string() + &leading_indent(self.ast().syntax()).unwrap_or_default(),
177 InsertPosition::After(it), 181 InsertPosition::After(it),
178 ), 182 ),
179 None => return, 183 None => return,
180 }, 184 },
181 }; 185 };
182 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 186 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
183 let to_insert: ArrayVec<[SyntaxElement; 2]> = [ws.ws().into(), item.syntax().into()].into(); 187 let to_insert: ArrayVec<[SyntaxElement; 2]> =
188 [ws.ws().into(), item.syntax().clone().into()].into();
184 self.ast = self.insert_children(position, to_insert.into_iter()); 189 self.ast = self.insert_children(position, to_insert.into_iter());
185 } 190 }
186 191
@@ -197,9 +202,9 @@ impl AstEditor<ast::ImplItem> {
197 .children_with_tokens() 202 .children_with_tokens()
198 .find(|it| it.kind() == ATTR || it.kind() == COMMENT) 203 .find(|it| it.kind() == ATTR || it.kind() == COMMENT)
199 { 204 {
200 let end = match start.next_sibling_or_token() { 205 let end = match &start.next_sibling_or_token() {
201 Some(el) if el.kind() == WHITESPACE => el, 206 Some(el) if el.kind() == WHITESPACE => el.clone(),
202 Some(_) | None => start, 207 Some(_) | None => start.clone(),
203 }; 208 };
204 self.ast = self.replace_children(RangeInclusive::new(start, end), iter::empty()); 209 self.ast = self.replace_children(RangeInclusive::new(start, end), iter::empty());
205 } 210 }
@@ -210,18 +215,18 @@ impl AstEditor<ast::FnDef> {
210 pub fn set_body(&mut self, body: &ast::Block) { 215 pub fn set_body(&mut self, body: &ast::Block) {
211 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); 216 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
212 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() { 217 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() {
213 old_body.syntax().into() 218 old_body.syntax().clone().into()
214 } else if let Some(semi) = self.ast().semicolon_token() { 219 } else if let Some(semi) = self.ast().semicolon_token() {
215 to_insert.push(tokens::single_space().into()); 220 to_insert.push(tokens::single_space().into());
216 semi.into() 221 semi.into()
217 } else { 222 } else {
218 to_insert.push(tokens::single_space().into()); 223 to_insert.push(tokens::single_space().into());
219 to_insert.push(body.syntax().into()); 224 to_insert.push(body.syntax().clone().into());
220 self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter()); 225 self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter());
221 return; 226 return;
222 }; 227 };
223 to_insert.push(body.syntax().into()); 228 to_insert.push(body.syntax().clone().into());
224 let replace_range = RangeInclusive::new(old_body_or_semi, old_body_or_semi); 229 let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi);
225 self.ast = self.replace_children(replace_range, to_insert.into_iter()) 230 self.ast = self.replace_children(replace_range, to_insert.into_iter())
226 } 231 }
227} 232}
@@ -231,15 +236,15 @@ pub struct AstBuilder<N: AstNode> {
231} 236}
232 237
233impl AstBuilder<ast::NamedField> { 238impl AstBuilder<ast::NamedField> {
234 pub fn from_name(name: &Name) -> TreeArc<ast::NamedField> { 239 pub fn from_name(name: &Name) -> ast::NamedField {
235 ast_node_from_file_text(&format!("fn f() {{ S {{ {}: (), }} }}", name)) 240 ast_node_from_file_text(&format!("fn f() {{ S {{ {}: (), }} }}", name))
236 } 241 }
237 242
238 fn from_text(text: &str) -> TreeArc<ast::NamedField> { 243 fn from_text(text: &str) -> ast::NamedField {
239 ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text)) 244 ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text))
240 } 245 }
241 246
242 pub fn from_pieces(name: &ast::NameRef, expr: Option<&ast::Expr>) -> TreeArc<ast::NamedField> { 247 pub fn from_pieces(name: &ast::NameRef, expr: Option<&ast::Expr>) -> ast::NamedField {
243 match expr { 248 match expr {
244 Some(expr) => Self::from_text(&format!("{}: {}", name.syntax(), expr.syntax())), 249 Some(expr) => Self::from_text(&format!("{}: {}", name.syntax(), expr.syntax())),
245 None => Self::from_text(&name.syntax().to_string()), 250 None => Self::from_text(&name.syntax().to_string()),
@@ -248,36 +253,36 @@ impl AstBuilder<ast::NamedField> {
248} 253}
249 254
250impl AstBuilder<ast::Block> { 255impl AstBuilder<ast::Block> {
251 fn from_text(text: &str) -> TreeArc<ast::Block> { 256 fn from_text(text: &str) -> ast::Block {
252 ast_node_from_file_text(&format!("fn f() {}", text)) 257 ast_node_from_file_text(&format!("fn f() {}", text))
253 } 258 }
254 259
255 pub fn single_expr(e: &ast::Expr) -> TreeArc<ast::Block> { 260 pub fn single_expr(e: &ast::Expr) -> ast::Block {
256 Self::from_text(&format!("{{ {} }}", e.syntax())) 261 Self::from_text(&format!("{{ {} }}", e.syntax()))
257 } 262 }
258} 263}
259 264
260impl AstBuilder<ast::Expr> { 265impl AstBuilder<ast::Expr> {
261 fn from_text(text: &str) -> TreeArc<ast::Expr> { 266 fn from_text(text: &str) -> ast::Expr {
262 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text)) 267 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text))
263 } 268 }
264 269
265 pub fn unit() -> TreeArc<ast::Expr> { 270 pub fn unit() -> ast::Expr {
266 Self::from_text("()") 271 Self::from_text("()")
267 } 272 }
268 273
269 pub fn unimplemented() -> TreeArc<ast::Expr> { 274 pub fn unimplemented() -> ast::Expr {
270 Self::from_text("unimplemented!()") 275 Self::from_text("unimplemented!()")
271 } 276 }
272} 277}
273 278
274impl AstBuilder<ast::NameRef> { 279impl AstBuilder<ast::NameRef> {
275 pub fn new(text: &str) -> TreeArc<ast::NameRef> { 280 pub fn new(text: &str) -> ast::NameRef {
276 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text)) 281 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text))
277 } 282 }
278} 283}
279 284
280fn ast_node_from_file_text<N: AstNode>(text: &str) -> TreeArc<N> { 285fn ast_node_from_file_text<N: AstNode>(text: &str) -> N {
281 let parse = SourceFile::parse(text); 286 let parse = SourceFile::parse(text);
282 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap().to_owned(); 287 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap().to_owned();
283 res 288 res
@@ -285,47 +290,49 @@ fn ast_node_from_file_text<N: AstNode>(text: &str) -> TreeArc<N> {
285 290
286mod tokens { 291mod tokens {
287 use once_cell::sync::Lazy; 292 use once_cell::sync::Lazy;
288 use ra_syntax::{AstNode, SourceFile, SyntaxKind::*, SyntaxToken, TreeArc, T}; 293 use ra_syntax::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
289 294
290 static SOURCE_FILE: Lazy<TreeArc<SourceFile>> = 295 static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;"));
291 Lazy::new(|| SourceFile::parse(",\n; ;").tree().to_owned());
292 296
293 pub(crate) fn comma() -> SyntaxToken<'static> { 297 pub(crate) fn comma() -> SyntaxToken {
294 SOURCE_FILE 298 SOURCE_FILE
299 .tree()
295 .syntax() 300 .syntax()
296 .descendants_with_tokens() 301 .descendants_with_tokens()
297 .filter_map(|it| it.as_token()) 302 .filter_map(|it| it.as_token().cloned())
298 .find(|it| it.kind() == T![,]) 303 .find(|it| it.kind() == T![,])
299 .unwrap() 304 .unwrap()
300 } 305 }
301 306
302 pub(crate) fn single_space() -> SyntaxToken<'static> { 307 pub(crate) fn single_space() -> SyntaxToken {
303 SOURCE_FILE 308 SOURCE_FILE
309 .tree()
304 .syntax() 310 .syntax()
305 .descendants_with_tokens() 311 .descendants_with_tokens()
306 .filter_map(|it| it.as_token()) 312 .filter_map(|it| it.as_token().cloned())
307 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ") 313 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
308 .unwrap() 314 .unwrap()
309 } 315 }
310 316
311 #[allow(unused)] 317 #[allow(unused)]
312 pub(crate) fn single_newline() -> SyntaxToken<'static> { 318 pub(crate) fn single_newline() -> SyntaxToken {
313 SOURCE_FILE 319 SOURCE_FILE
320 .tree()
314 .syntax() 321 .syntax()
315 .descendants_with_tokens() 322 .descendants_with_tokens()
316 .filter_map(|it| it.as_token()) 323 .filter_map(|it| it.as_token().cloned())
317 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n") 324 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
318 .unwrap() 325 .unwrap()
319 } 326 }
320 327
321 pub(crate) struct WsBuilder(TreeArc<SourceFile>); 328 pub(crate) struct WsBuilder(SourceFile);
322 329
323 impl WsBuilder { 330 impl WsBuilder {
324 pub(crate) fn new(text: &str) -> WsBuilder { 331 pub(crate) fn new(text: &str) -> WsBuilder {
325 WsBuilder(SourceFile::parse(text).ok().unwrap()) 332 WsBuilder(SourceFile::parse(text).ok().unwrap())
326 } 333 }
327 pub(crate) fn ws(&self) -> SyntaxToken<'_> { 334 pub(crate) fn ws(&self) -> SyntaxToken {
328 self.0.syntax().first_child_or_token().unwrap().as_token().unwrap() 335 self.0.syntax().first_child_or_token().unwrap().as_token().cloned().unwrap()
329 } 336 }
330 } 337 }
331 338
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index f8f37e852..0eb4bdb62 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -12,25 +12,25 @@ use ra_syntax::{
12 SyntaxNode, TextRange, T, 12 SyntaxNode, TextRange, T,
13}; 13};
14 14
15fn collect_path_segments_raw<'a>( 15fn collect_path_segments_raw(
16 segments: &mut Vec<&'a ast::PathSegment>, 16 segments: &mut Vec<ast::PathSegment>,
17 mut path: &'a ast::Path, 17 mut path: ast::Path,
18) -> Option<usize> { 18) -> Option<usize> {
19 let oldlen = segments.len(); 19 let oldlen = segments.len();
20 loop { 20 loop {
21 let mut children = path.syntax().children_with_tokens(); 21 let mut children = path.syntax().children_with_tokens();
22 let (first, second, third) = ( 22 let (first, second, third) = (
23 children.next().map(|n| (n, n.kind())), 23 children.next().map(|n| (n.clone(), n.kind())),
24 children.next().map(|n| (n, n.kind())), 24 children.next().map(|n| (n.clone(), n.kind())),
25 children.next().map(|n| (n, n.kind())), 25 children.next().map(|n| (n.clone(), n.kind())),
26 ); 26 );
27 match (first, second, third) { 27 match (first, second, third) {
28 (Some((subpath, PATH)), Some((_, T![::])), Some((segment, PATH_SEGMENT))) => { 28 (Some((subpath, PATH)), Some((_, T![::])), Some((segment, PATH_SEGMENT))) => {
29 path = ast::Path::cast(subpath.as_node()?)?; 29 path = ast::Path::cast(subpath.as_node()?.clone())?;
30 segments.push(ast::PathSegment::cast(segment.as_node()?)?); 30 segments.push(ast::PathSegment::cast(segment.as_node()?.clone())?);
31 } 31 }
32 (Some((segment, PATH_SEGMENT)), _, _) => { 32 (Some((segment, PATH_SEGMENT)), _, _) => {
33 segments.push(ast::PathSegment::cast(segment.as_node()?)?); 33 segments.push(ast::PathSegment::cast(segment.as_node()?.clone())?);
34 break; 34 break;
35 } 35 }
36 (_, _, _) => return None, 36 (_, _, _) => return None,
@@ -60,7 +60,7 @@ fn fmt_segments_raw(segments: &[SmolStr], buf: &mut String) {
60} 60}
61 61
62// Returns the numeber of common segments. 62// Returns the numeber of common segments.
63fn compare_path_segments(left: &[SmolStr], right: &[&ast::PathSegment]) -> usize { 63fn compare_path_segments(left: &[SmolStr], right: &[ast::PathSegment]) -> usize {
64 left.iter().zip(right).filter(|(l, r)| compare_path_segment(l, r)).count() 64 left.iter().zip(right).filter(|(l, r)| compare_path_segment(l, r)).count()
65} 65}
66 66
@@ -81,12 +81,12 @@ fn compare_path_segment_with_name(a: &SmolStr, b: &ast::Name) -> bool {
81 a == b.text() 81 a == b.text()
82} 82}
83 83
84#[derive(Copy, Clone)] 84#[derive(Clone)]
85enum ImportAction<'a> { 85enum ImportAction {
86 Nothing, 86 Nothing,
87 // Add a brand new use statement. 87 // Add a brand new use statement.
88 AddNewUse { 88 AddNewUse {
89 anchor: Option<&'a SyntaxNode>, // anchor node 89 anchor: Option<SyntaxNode>, // anchor node
90 add_after_anchor: bool, 90 add_after_anchor: bool,
91 }, 91 },
92 92
@@ -94,9 +94,9 @@ enum ImportAction<'a> {
94 AddNestedImport { 94 AddNestedImport {
95 // how may segments matched with the target path 95 // how may segments matched with the target path
96 common_segments: usize, 96 common_segments: usize,
97 path_to_split: &'a ast::Path, 97 path_to_split: ast::Path,
98 // the first segment of path_to_split we want to add into the new nested list 98 // the first segment of path_to_split we want to add into the new nested list
99 first_segment_to_split: Option<&'a ast::PathSegment>, 99 first_segment_to_split: Option<ast::PathSegment>,
100 // Wether to add 'self' in addition to the target path 100 // Wether to add 'self' in addition to the target path
101 add_self: bool, 101 add_self: bool,
102 }, 102 },
@@ -104,20 +104,20 @@ enum ImportAction<'a> {
104 AddInTreeList { 104 AddInTreeList {
105 common_segments: usize, 105 common_segments: usize,
106 // The UseTreeList where to add the target path 106 // The UseTreeList where to add the target path
107 tree_list: &'a ast::UseTreeList, 107 tree_list: ast::UseTreeList,
108 add_self: bool, 108 add_self: bool,
109 }, 109 },
110} 110}
111 111
112impl<'a> ImportAction<'a> { 112impl ImportAction {
113 fn add_new_use(anchor: Option<&'a SyntaxNode>, add_after_anchor: bool) -> Self { 113 fn add_new_use(anchor: Option<SyntaxNode>, add_after_anchor: bool) -> Self {
114 ImportAction::AddNewUse { anchor, add_after_anchor } 114 ImportAction::AddNewUse { anchor, add_after_anchor }
115 } 115 }
116 116
117 fn add_nested_import( 117 fn add_nested_import(
118 common_segments: usize, 118 common_segments: usize,
119 path_to_split: &'a ast::Path, 119 path_to_split: ast::Path,
120 first_segment_to_split: Option<&'a ast::PathSegment>, 120 first_segment_to_split: Option<ast::PathSegment>,
121 add_self: bool, 121 add_self: bool,
122 ) -> Self { 122 ) -> Self {
123 ImportAction::AddNestedImport { 123 ImportAction::AddNestedImport {
@@ -130,14 +130,14 @@ impl<'a> ImportAction<'a> {
130 130
131 fn add_in_tree_list( 131 fn add_in_tree_list(
132 common_segments: usize, 132 common_segments: usize,
133 tree_list: &'a ast::UseTreeList, 133 tree_list: ast::UseTreeList,
134 add_self: bool, 134 add_self: bool,
135 ) -> Self { 135 ) -> Self {
136 ImportAction::AddInTreeList { common_segments, tree_list, add_self } 136 ImportAction::AddInTreeList { common_segments, tree_list, add_self }
137 } 137 }
138 138
139 fn better<'b>(left: &'b ImportAction<'a>, right: &'b ImportAction<'a>) -> &'b ImportAction<'a> { 139 fn better(left: ImportAction, right: ImportAction) -> ImportAction {
140 if left.is_better(right) { 140 if left.is_better(&right) {
141 left 141 left
142 } else { 142 } else {
143 right 143 right
@@ -166,12 +166,12 @@ impl<'a> ImportAction<'a> {
166 166
167// Find out the best ImportAction to import target path against current_use_tree. 167// Find out the best ImportAction to import target path against current_use_tree.
168// If current_use_tree has a nested import the function gets called recursively on every UseTree inside a UseTreeList. 168// If current_use_tree has a nested import the function gets called recursively on every UseTree inside a UseTreeList.
169fn walk_use_tree_for_best_action<'a>( 169fn walk_use_tree_for_best_action(
170 current_path_segments: &mut Vec<&'a ast::PathSegment>, // buffer containing path segments 170 current_path_segments: &mut Vec<ast::PathSegment>, // buffer containing path segments
171 current_parent_use_tree_list: Option<&'a ast::UseTreeList>, // will be Some value if we are in a nested import 171 current_parent_use_tree_list: Option<ast::UseTreeList>, // will be Some value if we are in a nested import
172 current_use_tree: &'a ast::UseTree, // the use tree we are currently examinating 172 current_use_tree: ast::UseTree, // the use tree we are currently examinating
173 target: &[SmolStr], // the path we want to import 173 target: &[SmolStr], // the path we want to import
174) -> ImportAction<'a> { 174) -> ImportAction {
175 // We save the number of segments in the buffer so we can restore the correct segments 175 // We save the number of segments in the buffer so we can restore the correct segments
176 // before returning. Recursive call will add segments so we need to delete them. 176 // before returning. Recursive call will add segments so we need to delete them.
177 let prev_len = current_path_segments.len(); 177 let prev_len = current_path_segments.len();
@@ -188,32 +188,36 @@ fn walk_use_tree_for_best_action<'a>(
188 .syntax() 188 .syntax()
189 .ancestors() 189 .ancestors()
190 .find_map(ast::UseItem::cast) 190 .find_map(ast::UseItem::cast)
191 .map(AstNode::syntax), 191 .map(|it| it.syntax().clone()),
192 true, 192 true,
193 ); 193 );
194 } 194 }
195 }; 195 };
196 196
197 // This can happen only if current_use_tree is a direct child of a UseItem 197 // This can happen only if current_use_tree is a direct child of a UseItem
198 if let Some(name) = alias.and_then(ast::NameOwner::name) { 198 if let Some(name) = alias.and_then(|it| it.name()) {
199 if compare_path_segment_with_name(&target[0], name) { 199 if compare_path_segment_with_name(&target[0], &name) {
200 return ImportAction::Nothing; 200 return ImportAction::Nothing;
201 } 201 }
202 } 202 }
203 203
204 collect_path_segments_raw(current_path_segments, path); 204 collect_path_segments_raw(current_path_segments, path.clone());
205 205
206 // We compare only the new segments added in the line just above. 206 // We compare only the new segments added in the line just above.
207 // The first prev_len segments were already compared in 'parent' recursive calls. 207 // The first prev_len segments were already compared in 'parent' recursive calls.
208 let left = target.split_at(prev_len).1; 208 let left = target.split_at(prev_len).1;
209 let right = current_path_segments.split_at(prev_len).1; 209 let right = current_path_segments.split_at(prev_len).1;
210 let common = compare_path_segments(left, right); 210 let common = compare_path_segments(left, &right);
211 let mut action = match common { 211 let mut action = match common {
212 0 => ImportAction::add_new_use( 212 0 => ImportAction::add_new_use(
213 // e.g: target is std::fmt and we can have 213 // e.g: target is std::fmt and we can have
214 // use foo::bar 214 // use foo::bar
215 // We add a brand new use statement 215 // We add a brand new use statement
216 current_use_tree.syntax().ancestors().find_map(ast::UseItem::cast).map(AstNode::syntax), 216 current_use_tree
217 .syntax()
218 .ancestors()
219 .find_map(ast::UseItem::cast)
220 .map(|it| it.syntax().clone()),
217 true, 221 true,
218 ), 222 ),
219 common if common == left.len() && left.len() == right.len() => { 223 common if common == left.len() && left.len() == right.len() => {
@@ -223,9 +227,9 @@ fn walk_use_tree_for_best_action<'a>(
223 if let Some(list) = tree_list { 227 if let Some(list) = tree_list {
224 // In case 2 we need to add self to the nested list 228 // In case 2 we need to add self to the nested list
225 // unless it's already there 229 // unless it's already there
226 let has_self = list.use_trees().map(ast::UseTree::path).any(|p| { 230 let has_self = list.use_trees().map(|it| it.path()).any(|p| {
227 p.and_then(ast::Path::segment) 231 p.and_then(|it| it.segment())
228 .and_then(ast::PathSegment::kind) 232 .and_then(|it| it.kind())
229 .filter(|k| *k == ast::PathSegmentKind::SelfKw) 233 .filter(|k| *k == ast::PathSegmentKind::SelfKw)
230 .is_some() 234 .is_some()
231 }); 235 });
@@ -248,7 +252,7 @@ fn walk_use_tree_for_best_action<'a>(
248 ImportAction::add_nested_import( 252 ImportAction::add_nested_import(
249 prev_len + common, 253 prev_len + common,
250 path, 254 path,
251 Some(segments_to_split[0]), 255 Some(segments_to_split[0].clone()),
252 false, 256 false,
253 ) 257 )
254 } 258 }
@@ -263,14 +267,18 @@ fn walk_use_tree_for_best_action<'a>(
263 .syntax() 267 .syntax()
264 .ancestors() 268 .ancestors()
265 .find_map(ast::UseItem::cast) 269 .find_map(ast::UseItem::cast)
266 .map(AstNode::syntax), 270 .map(|it| it.syntax().clone()),
267 true, 271 true,
268 ); 272 );
269 if let Some(list) = tree_list { 273 if let Some(list) = tree_list {
270 // Case 2, check recursively if the path is already imported in the nested list 274 // Case 2, check recursively if the path is already imported in the nested list
271 for u in list.use_trees() { 275 for u in list.use_trees() {
272 let child_action = 276 let child_action = walk_use_tree_for_best_action(
273 walk_use_tree_for_best_action(current_path_segments, Some(list), u, target); 277 current_path_segments,
278 Some(list.clone()),
279 u,
280 target,
281 );
274 if child_action.is_better(&better_action) { 282 if child_action.is_better(&better_action) {
275 better_action = child_action; 283 better_action = child_action;
276 if let ImportAction::Nothing = better_action { 284 if let ImportAction::Nothing = better_action {
@@ -291,7 +299,7 @@ fn walk_use_tree_for_best_action<'a>(
291 ImportAction::add_nested_import( 299 ImportAction::add_nested_import(
292 prev_len + common, 300 prev_len + common,
293 path, 301 path,
294 Some(segments_to_split[0]), 302 Some(segments_to_split[0].clone()),
295 true, 303 true,
296 ) 304 )
297 } 305 }
@@ -302,7 +310,7 @@ fn walk_use_tree_for_best_action<'a>(
302 ImportAction::add_nested_import( 310 ImportAction::add_nested_import(
303 prev_len + common, 311 prev_len + common,
304 path, 312 path,
305 Some(segments_to_split[0]), 313 Some(segments_to_split[0].clone()),
306 false, 314 false,
307 ) 315 )
308 } 316 }
@@ -311,7 +319,7 @@ fn walk_use_tree_for_best_action<'a>(
311 319
312 // If we are inside a UseTreeList adding a use statement become adding to the existing 320 // If we are inside a UseTreeList adding a use statement become adding to the existing
313 // tree list. 321 // tree list.
314 action = match (current_parent_use_tree_list, action) { 322 action = match (current_parent_use_tree_list, action.clone()) {
315 (Some(use_tree_list), ImportAction::AddNewUse { .. }) => { 323 (Some(use_tree_list), ImportAction::AddNewUse { .. }) => {
316 ImportAction::add_in_tree_list(prev_len, use_tree_list, false) 324 ImportAction::add_in_tree_list(prev_len, use_tree_list, false)
317 } 325 }
@@ -323,19 +331,20 @@ fn walk_use_tree_for_best_action<'a>(
323 action 331 action
324} 332}
325 333
326fn best_action_for_target<'b, 'a: 'b>( 334fn best_action_for_target(
327 container: &'a SyntaxNode, 335 container: SyntaxNode,
328 anchor: &'a SyntaxNode, 336 anchor: SyntaxNode,
329 target: &'b [SmolStr], 337 target: &[SmolStr],
330) -> ImportAction<'a> { 338) -> ImportAction {
331 let mut storage = Vec::with_capacity(16); // this should be the only allocation 339 let mut storage = Vec::with_capacity(16); // this should be the only allocation
332 let best_action = container 340 let best_action = container
333 .children() 341 .children()
334 .filter_map(ast::UseItem::cast) 342 .filter_map(ast::UseItem::cast)
335 .filter_map(ast::UseItem::use_tree) 343 .filter_map(|it| it.use_tree())
336 .map(|u| walk_use_tree_for_best_action(&mut storage, None, u, target)) 344 .map(|u| walk_use_tree_for_best_action(&mut storage, None, u, target))
337 .fold(None, |best, a| { 345 .fold(None, |best, a| match best {
338 best.and_then(|best| Some(*ImportAction::better(&best, &a))).or_else(|| Some(a)) 346 Some(best) => Some(ImportAction::better(best, a)),
347 None => Some(a),
339 }); 348 });
340 349
341 match best_action { 350 match best_action {
@@ -386,7 +395,7 @@ fn make_assist(action: &ImportAction, target: &[SmolStr], edit: &mut TextEditBui
386} 395}
387 396
388fn make_assist_add_new_use( 397fn make_assist_add_new_use(
389 anchor: &Option<&SyntaxNode>, 398 anchor: &Option<SyntaxNode>,
390 after: bool, 399 after: bool,
391 target: &[SmolStr], 400 target: &[SmolStr],
392 edit: &mut TextEditBuilder, 401 edit: &mut TextEditBuilder,
@@ -396,7 +405,7 @@ fn make_assist_add_new_use(
396 let mut buf = String::new(); 405 let mut buf = String::new();
397 if after { 406 if after {
398 buf.push_str("\n"); 407 buf.push_str("\n");
399 if let Some(spaces) = indent { 408 if let Some(spaces) = &indent {
400 buf.push_str(spaces); 409 buf.push_str(spaces);
401 } 410 }
402 } 411 }
@@ -405,8 +414,8 @@ fn make_assist_add_new_use(
405 buf.push_str(";"); 414 buf.push_str(";");
406 if !after { 415 if !after {
407 buf.push_str("\n\n"); 416 buf.push_str("\n\n");
408 if let Some(spaces) = indent { 417 if let Some(spaces) = &indent {
409 buf.push_str(spaces); 418 buf.push_str(&spaces);
410 } 419 }
411 } 420 }
412 let position = if after { anchor.range().end() } else { anchor.range().start() }; 421 let position = if after { anchor.range().end() } else { anchor.range().start() };
@@ -444,7 +453,7 @@ fn make_assist_add_in_tree_list(
444 453
445fn make_assist_add_nested_import( 454fn make_assist_add_nested_import(
446 path: &ast::Path, 455 path: &ast::Path,
447 first_segment_to_split: &Option<&ast::PathSegment>, 456 first_segment_to_split: &Option<ast::PathSegment>,
448 target: &[SmolStr], 457 target: &[SmolStr],
449 add_self: bool, 458 add_self: bool,
450 edit: &mut TextEditBuilder, 459 edit: &mut TextEditBuilder,
@@ -482,7 +491,7 @@ fn apply_auto_import(
482 target: &[SmolStr], 491 target: &[SmolStr],
483 edit: &mut TextEditBuilder, 492 edit: &mut TextEditBuilder,
484) { 493) {
485 let action = best_action_for_target(container, path.syntax(), target); 494 let action = best_action_for_target(container.clone(), path.syntax().clone(), target);
486 make_assist(&action, target, edit); 495 make_assist(&action, target, edit);
487 if let Some(last) = path.segment() { 496 if let Some(last) = path.segment() {
488 // Here we are assuming the assist will provide a correct use statement 497 // Here we are assuming the assist will provide a correct use statement
@@ -522,26 +531,26 @@ pub fn auto_import_text_edit(
522 edit: &mut TextEditBuilder, 531 edit: &mut TextEditBuilder,
523) { 532) {
524 let container = position.ancestors().find_map(|n| { 533 let container = position.ancestors().find_map(|n| {
525 if let Some(module) = ast::Module::cast(n) { 534 if let Some(module) = ast::Module::cast(n.clone()) {
526 return module.item_list().map(ast::AstNode::syntax); 535 return module.item_list().map(|it| it.syntax().clone());
527 } 536 }
528 ast::SourceFile::cast(n).map(ast::AstNode::syntax) 537 ast::SourceFile::cast(n).map(|it| it.syntax().clone())
529 }); 538 });
530 539
531 if let Some(container) = container { 540 if let Some(container) = container {
532 let action = best_action_for_target(container, anchor, target); 541 let action = best_action_for_target(container, anchor.clone(), target);
533 make_assist(&action, target, edit); 542 make_assist(&action, target, edit);
534 } 543 }
535} 544}
536 545
537pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 546pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
538 let path: &ast::Path = ctx.node_at_offset()?; 547 let path: ast::Path = ctx.node_at_offset()?;
539 // We don't want to mess with use statements 548 // We don't want to mess with use statements
540 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { 549 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
541 return None; 550 return None;
542 } 551 }
543 552
544 let hir_path = hir::Path::from_ast(path)?; 553 let hir_path = hir::Path::from_ast(path.clone())?;
545 let segments = collect_hir_path_segments(&hir_path); 554 let segments = collect_hir_path_segments(&hir_path);
546 if segments.len() < 2 { 555 if segments.len() < 2 {
547 return None; 556 return None;
@@ -554,7 +563,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
554 format!("import {} in mod {}", fmt_segments(&segments), name.text()), 563 format!("import {} in mod {}", fmt_segments(&segments), name.text()),
555 |edit| { 564 |edit| {
556 let mut text_edit = TextEditBuilder::default(); 565 let mut text_edit = TextEditBuilder::default();
557 apply_auto_import(item_list.syntax(), path, &segments, &mut text_edit); 566 apply_auto_import(item_list.syntax(), &path, &segments, &mut text_edit);
558 edit.set_edit_builder(text_edit); 567 edit.set_edit_builder(text_edit);
559 }, 568 },
560 ); 569 );
@@ -566,7 +575,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
566 format!("import {} in the current file", fmt_segments(&segments)), 575 format!("import {} in the current file", fmt_segments(&segments)),
567 |edit| { 576 |edit| {
568 let mut text_edit = TextEditBuilder::default(); 577 let mut text_edit = TextEditBuilder::default();
569 apply_auto_import(current_file.syntax(), path, &segments, &mut text_edit); 578 apply_auto_import(current_file.syntax(), &path, &segments, &mut text_edit);
570 edit.set_edit_builder(text_edit); 579 edit.set_edit_builder(text_edit);
571 }, 580 },
572 ); 581 );
diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs
index 6cabba3e3..ab10d2aa4 100644
--- a/crates/ra_assists/src/change_visibility.rs
+++ b/crates/ra_assists/src/change_visibility.rs
@@ -35,7 +35,7 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
35 if parent.children().any(|child| child.kind() == VISIBILITY) { 35 if parent.children().any(|child| child.kind() == VISIBILITY) {
36 return None; 36 return None;
37 } 37 }
38 (vis_offset(parent), keyword.range()) 38 (vis_offset(&parent), keyword.range())
39 } else { 39 } else {
40 let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?; 40 let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?;
41 let field = ident.parent().ancestors().find_map(ast::NamedFieldDef::cast)?; 41 let field = ident.parent().ancestors().find_map(ast::NamedFieldDef::cast)?;
@@ -65,7 +65,7 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit {
65 .unwrap_or_else(|| node.range().start()) 65 .unwrap_or_else(|| node.range().start())
66} 66}
67 67
68fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> { 68fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> {
69 if vis.syntax().text() == "pub" { 69 if vis.syntax().text() == "pub" {
70 ctx.add_action(AssistId("change_visibility"), "change to pub(crate)", |edit| { 70 ctx.add_action(AssistId("change_visibility"), "change to pub(crate)", |edit| {
71 edit.target(vis.syntax().range()); 71 edit.target(vis.syntax().range());
diff --git a/crates/ra_assists/src/fill_match_arms.rs b/crates/ra_assists/src/fill_match_arms.rs
index deef166b5..b96806ac6 100644
--- a/crates/ra_assists/src/fill_match_arms.rs
+++ b/crates/ra_assists/src/fill_match_arms.rs
@@ -27,7 +27,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
27 let mut arm_iter = arm_list.arms(); 27 let mut arm_iter = arm_list.arms();
28 let first = arm_iter.next(); 28 let first = arm_iter.next();
29 29
30 match first { 30 match &first {
31 // If there arm list is empty or there is only one trivial arm, then proceed. 31 // If there arm list is empty or there is only one trivial arm, then proceed.
32 Some(arm) if is_trivial_arm(arm) => { 32 Some(arm) if is_trivial_arm(arm) => {
33 if arm_iter.next() != None { 33 if arm_iter.next() != None {
@@ -44,7 +44,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
44 44
45 let expr = match_expr.expr()?; 45 let expr = match_expr.expr()?;
46 let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, expr.syntax(), None); 46 let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, expr.syntax(), None);
47 let match_expr_ty = analyzer.type_of(ctx.db, expr)?; 47 let match_expr_ty = analyzer.type_of(ctx.db, &expr)?;
48 let enum_def = analyzer.autoderef(ctx.db, match_expr_ty).find_map(|ty| match ty.as_adt() { 48 let enum_def = analyzer.autoderef(ctx.db, match_expr_ty).find_map(|ty| match ty.as_adt() {
49 Some((AdtDef::Enum(e), _)) => Some(e), 49 Some((AdtDef::Enum(e), _)) => Some(e),
50 _ => None, 50 _ => None,
diff --git a/crates/ra_assists/src/flip_binexpr.rs b/crates/ra_assists/src/flip_binexpr.rs
index 5e41f9346..2e591ad3b 100644
--- a/crates/ra_assists/src/flip_binexpr.rs
+++ b/crates/ra_assists/src/flip_binexpr.rs
@@ -6,8 +6,8 @@ use crate::{Assist, AssistCtx, AssistId};
6/// Flip binary expression assist. 6/// Flip binary expression assist.
7pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 7pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
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().clone();
10 let rhs = expr.rhs()?.syntax(); 10 let rhs = expr.rhs()?.syntax().clone();
11 let op_range = expr.op_token()?.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);
diff --git a/crates/ra_assists/src/flip_comma.rs b/crates/ra_assists/src/flip_comma.rs
index d8dba779f..13016ae06 100644
--- a/crates/ra_assists/src/flip_comma.rs
+++ b/crates/ra_assists/src/flip_comma.rs
@@ -5,8 +5,8 @@ use crate::{Assist, AssistCtx, AssistId};
5 5
6pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 6pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
7 let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?; 7 let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?;
8 let prev = non_trivia_sibling(comma.into(), Direction::Prev)?; 8 let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?;
9 let next = non_trivia_sibling(comma.into(), Direction::Next)?; 9 let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?;
10 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { 10 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| {
11 edit.target(comma.range()); 11 edit.target(comma.range());
12 edit.replace(prev.range(), next.to_string()); 12 edit.replace(prev.range(), next.to_string());
diff --git a/crates/ra_assists/src/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs
index 554de8b46..3c17089de 100644
--- a/crates/ra_assists/src/inline_local_variable.rs
+++ b/crates/ra_assists/src/inline_local_variable.rs
@@ -16,18 +16,18 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
16 if bind_pat.is_mutable() { 16 if bind_pat.is_mutable() {
17 return None; 17 return None;
18 } 18 }
19 let initializer_expr = let_stmt.initializer(); 19 let initializer_expr = let_stmt.initializer()?;
20 let delete_range = if let Some(whitespace) = let_stmt 20 let delete_range = if let Some(whitespace) = let_stmt
21 .syntax() 21 .syntax()
22 .next_sibling_or_token() 22 .next_sibling_or_token()
23 .and_then(|it| ast::Whitespace::cast(it.as_token()?)) 23 .and_then(|it| ast::Whitespace::cast(it.as_token()?.clone()))
24 { 24 {
25 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) 25 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
26 } else { 26 } else {
27 let_stmt.syntax().range() 27 let_stmt.syntax().range()
28 }; 28 };
29 let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, bind_pat.syntax(), None); 29 let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, bind_pat.syntax(), None);
30 let refs = analyzer.find_all_refs(bind_pat); 30 let refs = analyzer.find_all_refs(&bind_pat);
31 31
32 let mut wrap_in_parens = vec![true; refs.len()]; 32 let mut wrap_in_parens = vec![true; refs.len()];
33 33
@@ -45,7 +45,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
45 } 45 }
46 }; 46 };
47 47
48 wrap_in_parens[i] = match (initializer_expr?.kind(), usage_parent.kind()) { 48 wrap_in_parens[i] = match (initializer_expr.kind(), usage_parent.kind()) {
49 (ExprKind::CallExpr(_), _) 49 (ExprKind::CallExpr(_), _)
50 | (ExprKind::IndexExpr(_), _) 50 | (ExprKind::IndexExpr(_), _)
51 | (ExprKind::MethodCallExpr(_), _) 51 | (ExprKind::MethodCallExpr(_), _)
@@ -71,7 +71,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
71 }; 71 };
72 } 72 }
73 73
74 let init_str = initializer_expr?.syntax().text().to_string(); 74 let init_str = initializer_expr.syntax().text().to_string();
75 let init_in_paren = format!("({})", &init_str); 75 let init_in_paren = format!("({})", &init_str);
76 76
77 ctx.add_action( 77 ctx.add_action(
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs
index f7f5ccafa..ce28132c9 100644
--- a/crates/ra_assists/src/introduce_variable.rs
+++ b/crates/ra_assists/src/introduce_variable.rs
@@ -20,8 +20,8 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
20 return None; 20 return None;
21 } 21 }
22 let expr = node.ancestors().find_map(valid_target_expr)?; 22 let expr = node.ancestors().find_map(valid_target_expr)?;
23 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; 23 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr.clone())?;
24 let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?; 24 let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?.clone();
25 if indent.kind() != WHITESPACE { 25 if indent.kind() != WHITESPACE {
26 return None; 26 return None;
27 } 27 }
@@ -37,9 +37,9 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
37 }; 37 };
38 38
39 expr.syntax().text().push_to(&mut buf); 39 expr.syntax().text().push_to(&mut buf);
40 let full_stmt = ast::ExprStmt::cast(anchor_stmt); 40 let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone());
41 let is_full_stmt = if let Some(expr_stmt) = full_stmt { 41 let is_full_stmt = if let Some(expr_stmt) = &full_stmt {
42 Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax()) 42 Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone())
43 } else { 43 } else {
44 false 44 false
45 }; 45 };
@@ -81,7 +81,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
81 81
82/// Check whether the node is a valid expression which can be extracted to a variable. 82/// Check whether the node is a valid expression which can be extracted to a variable.
83/// In general that's true for any expression, but in some cases that would produce invalid code. 83/// In general that's true for any expression, but in some cases that would produce invalid code.
84fn valid_target_expr(node: &SyntaxNode) -> Option<&ast::Expr> { 84fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
85 match node.kind() { 85 match node.kind() {
86 PATH_EXPR => None, 86 PATH_EXPR => None,
87 BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()), 87 BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
@@ -96,14 +96,10 @@ fn valid_target_expr(node: &SyntaxNode) -> Option<&ast::Expr> {
96/// to produce correct code. 96/// to produce correct code.
97/// It can be a statement, the last in a block expression or a wanna be block 97/// It can be a statement, the last in a block expression or a wanna be block
98/// expression like a lambda or match arm. 98/// expression like a lambda or match arm.
99fn anchor_stmt(expr: &ast::Expr) -> Option<(&SyntaxNode, bool)> { 99fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> {
100 expr.syntax().ancestors().find_map(|node| { 100 expr.syntax().ancestors().find_map(|node| {
101 if ast::Stmt::cast(node).is_some() {
102 return Some((node, false));
103 }
104
105 if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) { 101 if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) {
106 if expr.syntax() == node { 102 if expr.syntax() == &node {
107 tested_by!(test_introduce_var_last_expr); 103 tested_by!(test_introduce_var_last_expr);
108 return Some((node, false)); 104 return Some((node, false));
109 } 105 }
@@ -115,6 +111,10 @@ fn anchor_stmt(expr: &ast::Expr) -> Option<(&SyntaxNode, bool)> {
115 } 111 }
116 } 112 }
117 113
114 if ast::Stmt::cast(node.clone()).is_some() {
115 return Some((node, false));
116 }
117
118 None 118 None
119 }) 119 })
120} 120}
diff --git a/crates/ra_assists/src/move_guard.rs b/crates/ra_assists/src/move_guard.rs
index e1ce86a33..313c9ad18 100644
--- a/crates/ra_assists/src/move_guard.rs
+++ b/crates/ra_assists/src/move_guard.rs
@@ -18,9 +18,9 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op
18 18
19 ctx.add_action(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { 19 ctx.add_action(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| {
20 edit.target(guard.syntax().range()); 20 edit.target(guard.syntax().range());
21 let offseting_amount = match space_before_guard { 21 let offseting_amount = match &space_before_guard {
22 Some(SyntaxElement::Token(tok)) => { 22 Some(SyntaxElement::Token(tok)) => {
23 if let Some(_) = ast::Whitespace::cast(tok) { 23 if let Some(_) = ast::Whitespace::cast(tok.clone()) {
24 let ele = space_before_guard.unwrap().range(); 24 let ele = space_before_guard.unwrap().range();
25 edit.delete(ele); 25 edit.delete(ele);
26 ele.len() 26 ele.len()
@@ -39,11 +39,11 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op
39} 39}
40 40
41pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 41pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
42 let match_arm: &MatchArm = ctx.node_at_offset::<MatchArm>()?; 42 let match_arm: MatchArm = ctx.node_at_offset::<MatchArm>()?;
43 let last_match_pat = match_arm.pats().last()?; 43 let last_match_pat = match_arm.pats().last()?;
44 44
45 let arm_body = match_arm.expr()?; 45 let arm_body = match_arm.expr()?;
46 let if_expr: &IfExpr = IfExpr::cast(arm_body.syntax())?; 46 let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?;
47 let cond = if_expr.condition()?; 47 let cond = if_expr.condition()?;
48 let then_block = if_expr.then_branch()?; 48 let then_block = if_expr.then_branch()?;
49 49
@@ -65,7 +65,7 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>)
65 edit.target(if_expr.syntax().range()); 65 edit.target(if_expr.syntax().range());
66 let then_only_expr = then_block.statements().next().is_none(); 66 let then_only_expr = then_block.statements().next().is_none();
67 67
68 match then_block.expr() { 68 match &then_block.expr() {
69 Some(then_expr) if then_only_expr => { 69 Some(then_expr) if then_only_expr => {
70 edit.replace(if_expr.syntax().range(), then_expr.syntax().text()) 70 edit.replace(if_expr.syntax().range(), then_expr.syntax().text())
71 } 71 }
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs
index 5680f76ca..c330bc827 100644
--- a/crates/ra_assists/src/remove_dbg.rs
+++ b/crates/ra_assists/src/remove_dbg.rs
@@ -8,7 +8,7 @@ use ra_syntax::{
8pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 8pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
9 let macro_call = ctx.node_at_offset::<ast::MacroCall>()?; 9 let macro_call = ctx.node_at_offset::<ast::MacroCall>()?;
10 10
11 if !is_valid_macrocall(macro_call, "dbg")? { 11 if !is_valid_macrocall(&macro_call, "dbg")? {
12 return None; 12 return None;
13 } 13 }
14 14
@@ -35,7 +35,7 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
35 }; 35 };
36 36
37 let macro_content = { 37 let macro_content = {
38 let macro_args = macro_call.token_tree()?.syntax(); 38 let macro_args = macro_call.token_tree()?.syntax().clone();
39 let range = macro_args.range(); 39 let range = macro_args.range();
40 let start = range.start() + TextUnit::of_char('('); 40 let start = range.start() + TextUnit::of_char('(');
41 let end = range.end() - TextUnit::of_char(')'); 41 let end = range.end() - TextUnit::of_char(')');
@@ -65,7 +65,7 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
65 return None; 65 return None;
66 } 66 }
67 67
68 let node = macro_call.token_tree()?.syntax(); 68 let node = macro_call.token_tree()?.syntax().clone();
69 let first_child = node.first_child_or_token()?; 69 let first_child = node.first_child_or_token()?;
70 let last_child = node.last_child_or_token()?; 70 let last_child = node.last_child_or_token()?;
71 71
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 c2c7cf70b..5de6aa266 100644
--- a/crates/ra_assists/src/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/replace_if_let_with_match.rs
@@ -5,7 +5,7 @@ use ra_syntax::{ast, AstNode};
5use crate::{Assist, AssistCtx, AssistId}; 5use crate::{Assist, AssistCtx, AssistId};
6 6
7pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 7pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
8 let if_expr: &ast::IfExpr = ctx.node_at_offset()?; 8 let if_expr: ast::IfExpr = ctx.node_at_offset()?;
9 let cond = if_expr.condition()?; 9 let cond = if_expr.condition()?;
10 let pat = cond.pat()?; 10 let pat = cond.pat()?;
11 let expr = cond.expr()?; 11 let expr = cond.expr()?;
@@ -25,16 +25,11 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) ->
25 ctx.build() 25 ctx.build()
26} 26}
27 27
28fn build_match_expr( 28fn build_match_expr(expr: ast::Expr, pat1: ast::Pat, arm1: ast::Block, arm2: ast::Block) -> String {
29 expr: &ast::Expr,
30 pat1: &ast::Pat,
31 arm1: &ast::Block,
32 arm2: &ast::Block,
33) -> String {
34 let mut buf = String::new(); 29 let mut buf = String::new();
35 buf.push_str(&format!("match {} {{\n", expr.syntax().text())); 30 buf.push_str(&format!("match {} {{\n", expr.syntax().text()));
36 buf.push_str(&format!(" {} => {}\n", pat1.syntax().text(), format_arm(arm1))); 31 buf.push_str(&format!(" {} => {}\n", pat1.syntax().text(), format_arm(&arm1)));
37 buf.push_str(&format!(" _ => {}\n", format_arm(arm2))); 32 buf.push_str(&format!(" _ => {}\n", format_arm(&arm2)));
38 buf.push_str("}"); 33 buf.push_str("}");
39 buf 34 buf
40} 35}