diff options
Diffstat (limited to 'crates/assists')
-rw-r--r-- | crates/assists/src/ast_transform.rs | 3 | ||||
-rw-r--r-- | crates/assists/src/handlers/extract_assignment.rs | 400 | ||||
-rw-r--r-- | crates/assists/src/handlers/fill_match_arms.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/handlers/fix_visibility.rs | 27 | ||||
-rw-r--r-- | crates/assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/tests/generated.rs | 29 | ||||
-rw-r--r-- | crates/assists/src/utils.rs | 14 |
7 files changed, 457 insertions, 20 deletions
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs index da94e9987..4a3ed7783 100644 --- a/crates/assists/src/ast_transform.rs +++ b/crates/assists/src/ast_transform.rs | |||
@@ -204,7 +204,8 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> { | |||
204 | } | 204 | } |
205 | PathResolution::Local(_) | 205 | PathResolution::Local(_) |
206 | | PathResolution::TypeParam(_) | 206 | | PathResolution::TypeParam(_) |
207 | | PathResolution::SelfType(_) => None, | 207 | | PathResolution::SelfType(_) |
208 | | PathResolution::ConstParam(_) => None, | ||
208 | PathResolution::Macro(_) => None, | 209 | PathResolution::Macro(_) => None, |
209 | PathResolution::AssocItem(_) => None, | 210 | PathResolution::AssocItem(_) => None, |
210 | } | 211 | } |
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/extract_assignment.rs new file mode 100644 index 000000000..ae99598c0 --- /dev/null +++ b/crates/assists/src/handlers/extract_assignment.rs | |||
@@ -0,0 +1,400 @@ | |||
1 | use syntax::{ | ||
2 | ast::{self, edit::AstNodeEdit, make}, | ||
3 | AstNode, | ||
4 | }; | ||
5 | use test_utils::mark; | ||
6 | |||
7 | use crate::{ | ||
8 | assist_context::{AssistContext, Assists}, | ||
9 | AssistId, AssistKind, | ||
10 | }; | ||
11 | |||
12 | // Assist: extract_assignment | ||
13 | // | ||
14 | // Extracts variable assigment to outside an if or match statement. | ||
15 | // | ||
16 | // ``` | ||
17 | // fn main() { | ||
18 | // let mut foo = 6; | ||
19 | // | ||
20 | // if true { | ||
21 | // <|>foo = 5; | ||
22 | // } else { | ||
23 | // foo = 4; | ||
24 | // } | ||
25 | // } | ||
26 | // ``` | ||
27 | // -> | ||
28 | // ``` | ||
29 | // fn main() { | ||
30 | // let mut foo = 6; | ||
31 | // | ||
32 | // foo = if true { | ||
33 | // 5 | ||
34 | // } else { | ||
35 | // 4 | ||
36 | // }; | ||
37 | // } | ||
38 | // ``` | ||
39 | pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
40 | let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; | ||
41 | let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { | ||
42 | assign_expr.lhs()? | ||
43 | } else { | ||
44 | return None; | ||
45 | }; | ||
46 | |||
47 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { | ||
48 | ( | ||
49 | ast::Expr::cast(if_expr.syntax().to_owned())?, | ||
50 | exprify_if(&if_expr, &ctx.sema, &name_expr)?.indent(if_expr.indent_level()), | ||
51 | ) | ||
52 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { | ||
53 | ( | ||
54 | ast::Expr::cast(match_expr.syntax().to_owned())?, | ||
55 | exprify_match(&match_expr, &ctx.sema, &name_expr)?, | ||
56 | ) | ||
57 | } else { | ||
58 | return None; | ||
59 | }; | ||
60 | |||
61 | let expr_stmt = make::expr_stmt(new_stmt); | ||
62 | |||
63 | acc.add( | ||
64 | AssistId("extract_assignment", AssistKind::RefactorExtract), | ||
65 | "Extract assignment", | ||
66 | old_stmt.syntax().text_range(), | ||
67 | move |edit| { | ||
68 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); | ||
69 | }, | ||
70 | ) | ||
71 | } | ||
72 | |||
73 | fn exprify_match( | ||
74 | match_expr: &ast::MatchExpr, | ||
75 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
76 | name: &ast::Expr, | ||
77 | ) -> Option<ast::Expr> { | ||
78 | let new_arm_list = match_expr | ||
79 | .match_arm_list()? | ||
80 | .arms() | ||
81 | .map(|arm| { | ||
82 | if let ast::Expr::BlockExpr(block) = arm.expr()? { | ||
83 | let new_block = exprify_block(&block, sema, name)?.indent(block.indent_level()); | ||
84 | Some(arm.replace_descendant(block, new_block)) | ||
85 | } else { | ||
86 | None | ||
87 | } | ||
88 | }) | ||
89 | .collect::<Option<Vec<_>>>()?; | ||
90 | let new_arm_list = match_expr | ||
91 | .match_arm_list()? | ||
92 | .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list)); | ||
93 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) | ||
94 | } | ||
95 | |||
96 | fn exprify_if( | ||
97 | statement: &ast::IfExpr, | ||
98 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
99 | name: &ast::Expr, | ||
100 | ) -> Option<ast::Expr> { | ||
101 | let then_branch = exprify_block(&statement.then_branch()?, sema, name)?; | ||
102 | let else_branch = match statement.else_branch()? { | ||
103 | ast::ElseBranch::Block(ref block) => { | ||
104 | ast::ElseBranch::Block(exprify_block(block, sema, name)?) | ||
105 | } | ||
106 | ast::ElseBranch::IfExpr(expr) => { | ||
107 | mark::hit!(test_extract_assigment_chained_if); | ||
108 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( | ||
109 | exprify_if(&expr, sema, name)?.syntax().to_owned(), | ||
110 | )?) | ||
111 | } | ||
112 | }; | ||
113 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) | ||
114 | } | ||
115 | |||
116 | fn exprify_block( | ||
117 | block: &ast::BlockExpr, | ||
118 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
119 | name: &ast::Expr, | ||
120 | ) -> Option<ast::BlockExpr> { | ||
121 | if block.expr().is_some() { | ||
122 | return None; | ||
123 | } | ||
124 | |||
125 | let mut stmts: Vec<_> = block.statements().collect(); | ||
126 | let stmt = stmts.pop()?; | ||
127 | |||
128 | if let ast::Stmt::ExprStmt(stmt) = stmt { | ||
129 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { | ||
130 | if expr.op_kind()? == ast::BinOp::Assignment && is_equivalent(sema, &expr.lhs()?, name) | ||
131 | { | ||
132 | // The last statement in the block is an assignment to the name we want | ||
133 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | None | ||
138 | } | ||
139 | |||
140 | fn is_equivalent( | ||
141 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
142 | expr0: &ast::Expr, | ||
143 | expr1: &ast::Expr, | ||
144 | ) -> bool { | ||
145 | match (expr0, expr1) { | ||
146 | (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { | ||
147 | mark::hit!(test_extract_assignment_field_assignment); | ||
148 | sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) | ||
149 | } | ||
150 | (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { | ||
151 | let path0 = path0.path(); | ||
152 | let path1 = path1.path(); | ||
153 | if let (Some(path0), Some(path1)) = (path0, path1) { | ||
154 | sema.resolve_path(&path0) == sema.resolve_path(&path1) | ||
155 | } else { | ||
156 | false | ||
157 | } | ||
158 | } | ||
159 | _ => false, | ||
160 | } | ||
161 | } | ||
162 | |||
163 | #[cfg(test)] | ||
164 | mod tests { | ||
165 | use super::*; | ||
166 | |||
167 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
168 | |||
169 | #[test] | ||
170 | fn test_extract_assignment_if() { | ||
171 | check_assist( | ||
172 | extract_assigment, | ||
173 | r#" | ||
174 | fn foo() { | ||
175 | let mut a = 1; | ||
176 | |||
177 | if true { | ||
178 | <|>a = 2; | ||
179 | } else { | ||
180 | a = 3; | ||
181 | } | ||
182 | }"#, | ||
183 | r#" | ||
184 | fn foo() { | ||
185 | let mut a = 1; | ||
186 | |||
187 | a = if true { | ||
188 | 2 | ||
189 | } else { | ||
190 | 3 | ||
191 | }; | ||
192 | }"#, | ||
193 | ); | ||
194 | } | ||
195 | |||
196 | #[test] | ||
197 | fn test_extract_assignment_match() { | ||
198 | check_assist( | ||
199 | extract_assigment, | ||
200 | r#" | ||
201 | fn foo() { | ||
202 | let mut a = 1; | ||
203 | |||
204 | match 1 { | ||
205 | 1 => { | ||
206 | <|>a = 2; | ||
207 | }, | ||
208 | 2 => { | ||
209 | a = 3; | ||
210 | }, | ||
211 | 3 => { | ||
212 | a = 4; | ||
213 | } | ||
214 | } | ||
215 | }"#, | ||
216 | r#" | ||
217 | fn foo() { | ||
218 | let mut a = 1; | ||
219 | |||
220 | a = match 1 { | ||
221 | 1 => { | ||
222 | 2 | ||
223 | }, | ||
224 | 2 => { | ||
225 | 3 | ||
226 | }, | ||
227 | 3 => { | ||
228 | 4 | ||
229 | } | ||
230 | }; | ||
231 | }"#, | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn test_extract_assignment_not_last_not_applicable() { | ||
237 | check_assist_not_applicable( | ||
238 | extract_assigment, | ||
239 | r#" | ||
240 | fn foo() { | ||
241 | let mut a = 1; | ||
242 | |||
243 | if true { | ||
244 | <|>a = 2; | ||
245 | b = a; | ||
246 | } else { | ||
247 | a = 3; | ||
248 | } | ||
249 | }"#, | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | #[test] | ||
254 | fn test_extract_assignment_chained_if() { | ||
255 | mark::check!(test_extract_assigment_chained_if); | ||
256 | check_assist( | ||
257 | extract_assigment, | ||
258 | r#" | ||
259 | fn foo() { | ||
260 | let mut a = 1; | ||
261 | |||
262 | if true { | ||
263 | <|>a = 2; | ||
264 | } else if false { | ||
265 | a = 3; | ||
266 | } else { | ||
267 | a = 4; | ||
268 | } | ||
269 | }"#, | ||
270 | r#" | ||
271 | fn foo() { | ||
272 | let mut a = 1; | ||
273 | |||
274 | a = if true { | ||
275 | 2 | ||
276 | } else if false { | ||
277 | 3 | ||
278 | } else { | ||
279 | 4 | ||
280 | }; | ||
281 | }"#, | ||
282 | ); | ||
283 | } | ||
284 | |||
285 | #[test] | ||
286 | fn test_extract_assigment_retains_stmts() { | ||
287 | check_assist( | ||
288 | extract_assigment, | ||
289 | r#" | ||
290 | fn foo() { | ||
291 | let mut a = 1; | ||
292 | |||
293 | if true { | ||
294 | let b = 2; | ||
295 | <|>a = 2; | ||
296 | } else { | ||
297 | let b = 3; | ||
298 | a = 3; | ||
299 | } | ||
300 | }"#, | ||
301 | r#" | ||
302 | fn foo() { | ||
303 | let mut a = 1; | ||
304 | |||
305 | a = if true { | ||
306 | let b = 2; | ||
307 | 2 | ||
308 | } else { | ||
309 | let b = 3; | ||
310 | 3 | ||
311 | }; | ||
312 | }"#, | ||
313 | ) | ||
314 | } | ||
315 | |||
316 | #[test] | ||
317 | fn extract_assignment_let_stmt_not_applicable() { | ||
318 | check_assist_not_applicable( | ||
319 | extract_assigment, | ||
320 | r#" | ||
321 | fn foo() { | ||
322 | let mut a = 1; | ||
323 | |||
324 | let b = if true { | ||
325 | <|>a = 2 | ||
326 | } else { | ||
327 | a = 3 | ||
328 | }; | ||
329 | }"#, | ||
330 | ) | ||
331 | } | ||
332 | |||
333 | #[test] | ||
334 | fn extract_assignment_if_missing_assigment_not_applicable() { | ||
335 | check_assist_not_applicable( | ||
336 | extract_assigment, | ||
337 | r#" | ||
338 | fn foo() { | ||
339 | let mut a = 1; | ||
340 | |||
341 | if true { | ||
342 | <|>a = 2; | ||
343 | } else {} | ||
344 | }"#, | ||
345 | ) | ||
346 | } | ||
347 | |||
348 | #[test] | ||
349 | fn extract_assignment_match_missing_assigment_not_applicable() { | ||
350 | check_assist_not_applicable( | ||
351 | extract_assigment, | ||
352 | r#" | ||
353 | fn foo() { | ||
354 | let mut a = 1; | ||
355 | |||
356 | match 1 { | ||
357 | 1 => { | ||
358 | <|>a = 2; | ||
359 | }, | ||
360 | 2 => { | ||
361 | a = 3; | ||
362 | }, | ||
363 | 3 => {}, | ||
364 | } | ||
365 | }"#, | ||
366 | ) | ||
367 | } | ||
368 | |||
369 | #[test] | ||
370 | fn test_extract_assignment_field_assignment() { | ||
371 | mark::check!(test_extract_assignment_field_assignment); | ||
372 | check_assist( | ||
373 | extract_assigment, | ||
374 | r#" | ||
375 | struct A(usize); | ||
376 | |||
377 | fn foo() { | ||
378 | let mut a = A(1); | ||
379 | |||
380 | if true { | ||
381 | <|>a.0 = 2; | ||
382 | } else { | ||
383 | a.0 = 3; | ||
384 | } | ||
385 | }"#, | ||
386 | r#" | ||
387 | struct A(usize); | ||
388 | |||
389 | fn foo() { | ||
390 | let mut a = A(1); | ||
391 | |||
392 | a.0 = if true { | ||
393 | 2 | ||
394 | } else { | ||
395 | 3 | ||
396 | }; | ||
397 | }"#, | ||
398 | ) | ||
399 | } | ||
400 | } | ||
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs index cb60a3128..f9a62b9fa 100644 --- a/crates/assists/src/handlers/fill_match_arms.rs +++ b/crates/assists/src/handlers/fill_match_arms.rs | |||
@@ -196,7 +196,7 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio | |||
196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); | 196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); |
197 | 197 | ||
198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
199 | let pat: ast::Pat = match var.source(db).value.kind() { | 199 | let pat: ast::Pat = match var.source(db)?.value.kind() { |
200 | ast::StructKind::Tuple(field_list) => { | 200 | ast::StructKind::Tuple(field_list) => { |
201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); | 201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); |
202 | make::tuple_struct_pat(path, pats).into() | 202 | make::tuple_struct_pat(path, pats).into() |
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs index 8558a8ff0..de1e8f0bf 100644 --- a/crates/assists/src/handlers/fix_visibility.rs +++ b/crates/assists/src/handlers/fix_visibility.rs | |||
@@ -97,7 +97,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> | |||
97 | let parent_name = parent.name(ctx.db()); | 97 | let parent_name = parent.name(ctx.db()); |
98 | let target_module = parent.module(ctx.db()); | 98 | let target_module = parent.module(ctx.db()); |
99 | 99 | ||
100 | let in_file_source = record_field_def.source(ctx.db()); | 100 | #[allow(deprecated)] |
101 | let in_file_source = record_field_def.source(ctx.db())?; | ||
101 | let (offset, current_visibility, target) = match in_file_source.value { | 102 | let (offset, current_visibility, target) = match in_file_source.value { |
102 | hir::FieldSource::Named(it) => { | 103 | hir::FieldSource::Named(it) => { |
103 | let s = it.syntax(); | 104 | let s = it.syntax(); |
@@ -145,53 +146,53 @@ fn target_data_for_def( | |||
145 | fn offset_target_and_file_id<S, Ast>( | 146 | fn offset_target_and_file_id<S, Ast>( |
146 | db: &dyn HirDatabase, | 147 | db: &dyn HirDatabase, |
147 | x: S, | 148 | x: S, |
148 | ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId) | 149 | ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)> |
149 | where | 150 | where |
150 | S: HasSource<Ast = Ast>, | 151 | S: HasSource<Ast = Ast>, |
151 | Ast: AstNode + ast::VisibilityOwner, | 152 | Ast: AstNode + ast::VisibilityOwner, |
152 | { | 153 | { |
153 | let source = x.source(db); | 154 | let source = x.source(db)?; |
154 | let in_file_syntax = source.syntax(); | 155 | let in_file_syntax = source.syntax(); |
155 | let file_id = in_file_syntax.file_id; | 156 | let file_id = in_file_syntax.file_id; |
156 | let syntax = in_file_syntax.value; | 157 | let syntax = in_file_syntax.value; |
157 | let current_visibility = source.value.visibility(); | 158 | let current_visibility = source.value.visibility(); |
158 | ( | 159 | Some(( |
159 | vis_offset(syntax), | 160 | vis_offset(syntax), |
160 | current_visibility, | 161 | current_visibility, |
161 | syntax.text_range(), | 162 | syntax.text_range(), |
162 | file_id.original_file(db.upcast()), | 163 | file_id.original_file(db.upcast()), |
163 | ) | 164 | )) |
164 | } | 165 | } |
165 | 166 | ||
166 | let target_name; | 167 | let target_name; |
167 | let (offset, current_visibility, target, target_file) = match def { | 168 | let (offset, current_visibility, target, target_file) = match def { |
168 | hir::ModuleDef::Function(f) => { | 169 | hir::ModuleDef::Function(f) => { |
169 | target_name = Some(f.name(db)); | 170 | target_name = Some(f.name(db)); |
170 | offset_target_and_file_id(db, f) | 171 | offset_target_and_file_id(db, f)? |
171 | } | 172 | } |
172 | hir::ModuleDef::Adt(adt) => { | 173 | hir::ModuleDef::Adt(adt) => { |
173 | target_name = Some(adt.name(db)); | 174 | target_name = Some(adt.name(db)); |
174 | match adt { | 175 | match adt { |
175 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s), | 176 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?, |
176 | hir::Adt::Union(u) => offset_target_and_file_id(db, u), | 177 | hir::Adt::Union(u) => offset_target_and_file_id(db, u)?, |
177 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e), | 178 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?, |
178 | } | 179 | } |
179 | } | 180 | } |
180 | hir::ModuleDef::Const(c) => { | 181 | hir::ModuleDef::Const(c) => { |
181 | target_name = c.name(db); | 182 | target_name = c.name(db); |
182 | offset_target_and_file_id(db, c) | 183 | offset_target_and_file_id(db, c)? |
183 | } | 184 | } |
184 | hir::ModuleDef::Static(s) => { | 185 | hir::ModuleDef::Static(s) => { |
185 | target_name = s.name(db); | 186 | target_name = s.name(db); |
186 | offset_target_and_file_id(db, s) | 187 | offset_target_and_file_id(db, s)? |
187 | } | 188 | } |
188 | hir::ModuleDef::Trait(t) => { | 189 | hir::ModuleDef::Trait(t) => { |
189 | target_name = Some(t.name(db)); | 190 | target_name = Some(t.name(db)); |
190 | offset_target_and_file_id(db, t) | 191 | offset_target_and_file_id(db, t)? |
191 | } | 192 | } |
192 | hir::ModuleDef::TypeAlias(t) => { | 193 | hir::ModuleDef::TypeAlias(t) => { |
193 | target_name = Some(t.name(db)); | 194 | target_name = Some(t.name(db)); |
194 | offset_target_and_file_id(db, t) | 195 | offset_target_and_file_id(db, t)? |
195 | } | 196 | } |
196 | hir::ModuleDef::Module(m) => { | 197 | hir::ModuleDef::Module(m) => { |
197 | target_name = m.name(db); | 198 | target_name = m.name(db); |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index fdec886e9..212464f85 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -116,6 +116,7 @@ mod handlers { | |||
116 | mod convert_integer_literal; | 116 | mod convert_integer_literal; |
117 | mod early_return; | 117 | mod early_return; |
118 | mod expand_glob_import; | 118 | mod expand_glob_import; |
119 | mod extract_assignment; | ||
119 | mod extract_module_to_file; | 120 | mod extract_module_to_file; |
120 | mod extract_struct_from_enum_variant; | 121 | mod extract_struct_from_enum_variant; |
121 | mod extract_variable; | 122 | mod extract_variable; |
@@ -167,6 +168,7 @@ mod handlers { | |||
167 | convert_integer_literal::convert_integer_literal, | 168 | convert_integer_literal::convert_integer_literal, |
168 | early_return::convert_to_guarded_return, | 169 | early_return::convert_to_guarded_return, |
169 | expand_glob_import::expand_glob_import, | 170 | expand_glob_import::expand_glob_import, |
171 | extract_assignment::extract_assigment, | ||
170 | extract_module_to_file::extract_module_to_file, | 172 | extract_module_to_file::extract_module_to_file, |
171 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 173 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
172 | extract_variable::extract_variable, | 174 | extract_variable::extract_variable, |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index d3dfe24e7..b91a816e8 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -238,6 +238,35 @@ fn qux(bar: Bar, baz: Baz) {} | |||
238 | } | 238 | } |
239 | 239 | ||
240 | #[test] | 240 | #[test] |
241 | fn doctest_extract_assignment() { | ||
242 | check_doc_test( | ||
243 | "extract_assignment", | ||
244 | r#####" | ||
245 | fn main() { | ||
246 | let mut foo = 6; | ||
247 | |||
248 | if true { | ||
249 | <|>foo = 5; | ||
250 | } else { | ||
251 | foo = 4; | ||
252 | } | ||
253 | } | ||
254 | "#####, | ||
255 | r#####" | ||
256 | fn main() { | ||
257 | let mut foo = 6; | ||
258 | |||
259 | foo = if true { | ||
260 | 5 | ||
261 | } else { | ||
262 | 4 | ||
263 | }; | ||
264 | } | ||
265 | "#####, | ||
266 | ) | ||
267 | } | ||
268 | |||
269 | #[test] | ||
241 | fn doctest_extract_module_to_file() { | 270 | fn doctest_extract_module_to_file() { |
242 | check_doc_test( | 271 | check_doc_test( |
243 | "extract_module_to_file", | 272 | "extract_module_to_file", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index d41084b59..b05596446 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -94,14 +94,18 @@ pub fn filter_assoc_items( | |||
94 | ast::AssocItem::MacroCall(_) => None, | 94 | ast::AssocItem::MacroCall(_) => None, |
95 | } | 95 | } |
96 | .is_some() | 96 | .is_some() |
97 | }; | 97 | } |
98 | 98 | ||
99 | items | 99 | items |
100 | .iter() | 100 | .iter() |
101 | .map(|i| match i { | 101 | // Note: This throws away items with no source. |
102 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value), | 102 | .filter_map(|i| { |
103 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value), | 103 | let item = match i { |
104 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value), | 104 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db)?.value), |
105 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db)?.value), | ||
106 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db)?.value), | ||
107 | }; | ||
108 | Some(item) | ||
105 | }) | 109 | }) |
106 | .filter(has_def_name) | 110 | .filter(has_def_name) |
107 | .filter(|it| match it { | 111 | .filter(|it| match it { |