diff options
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r-- | crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | 135 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/pull_assignment_up.rs | 50 |
2 files changed, 160 insertions, 25 deletions
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs index 66f274fa7..8e2178391 100644 --- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -151,20 +151,37 @@ fn create_struct_def( | |||
151 | field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, | 151 | field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, |
152 | visibility: Option<ast::Visibility>, | 152 | visibility: Option<ast::Visibility>, |
153 | ) -> ast::Struct { | 153 | ) -> ast::Struct { |
154 | let pub_vis = Some(make::visibility_pub()); | 154 | let pub_vis = make::visibility_pub(); |
155 | |||
156 | let insert_pub = |node: &'_ SyntaxNode| { | ||
157 | let pub_vis = pub_vis.clone_for_update(); | ||
158 | ted::insert(ted::Position::before(node), pub_vis.syntax()); | ||
159 | }; | ||
160 | |||
161 | // for fields without any existing visibility, use pub visibility | ||
155 | let field_list = match field_list { | 162 | let field_list = match field_list { |
156 | Either::Left(field_list) => { | 163 | Either::Left(field_list) => { |
157 | make::record_field_list(field_list.fields().flat_map(|field| { | 164 | let field_list = field_list.clone_for_update(); |
158 | Some(make::record_field(pub_vis.clone(), field.name()?, field.ty()?)) | 165 | |
159 | })) | 166 | field_list |
160 | .into() | 167 | .fields() |
168 | .filter(|field| field.visibility().is_none()) | ||
169 | .filter_map(|field| field.name()) | ||
170 | .for_each(|it| insert_pub(it.syntax())); | ||
171 | |||
172 | field_list.into() | ||
161 | } | 173 | } |
162 | Either::Right(field_list) => make::tuple_field_list( | 174 | Either::Right(field_list) => { |
175 | let field_list = field_list.clone_for_update(); | ||
176 | |||
163 | field_list | 177 | field_list |
164 | .fields() | 178 | .fields() |
165 | .flat_map(|field| Some(make::tuple_field(pub_vis.clone(), field.ty()?))), | 179 | .filter(|field| field.visibility().is_none()) |
166 | ) | 180 | .filter_map(|field| field.ty()) |
167 | .into(), | 181 | .for_each(|it| insert_pub(it.syntax())); |
182 | |||
183 | field_list.into() | ||
184 | } | ||
168 | }; | 185 | }; |
169 | 186 | ||
170 | make::struct_(visibility, variant_name, None, field_list).clone_for_update() | 187 | make::struct_(visibility, variant_name, None, field_list).clone_for_update() |
@@ -295,6 +312,106 @@ enum A { One(One) }"#, | |||
295 | } | 312 | } |
296 | 313 | ||
297 | #[test] | 314 | #[test] |
315 | fn test_extract_struct_keep_comments_and_attrs_one_field_named() { | ||
316 | check_assist( | ||
317 | extract_struct_from_enum_variant, | ||
318 | r#" | ||
319 | enum A { | ||
320 | $0One { | ||
321 | // leading comment | ||
322 | /// doc comment | ||
323 | #[an_attr] | ||
324 | foo: u32 | ||
325 | // trailing comment | ||
326 | } | ||
327 | }"#, | ||
328 | r#" | ||
329 | struct One{ | ||
330 | // leading comment | ||
331 | /// doc comment | ||
332 | #[an_attr] | ||
333 | pub foo: u32 | ||
334 | // trailing comment | ||
335 | } | ||
336 | |||
337 | enum A { | ||
338 | One(One) | ||
339 | }"#, | ||
340 | ); | ||
341 | } | ||
342 | |||
343 | #[test] | ||
344 | fn test_extract_struct_keep_comments_and_attrs_several_fields_named() { | ||
345 | check_assist( | ||
346 | extract_struct_from_enum_variant, | ||
347 | r#" | ||
348 | enum A { | ||
349 | $0One { | ||
350 | // comment | ||
351 | /// doc | ||
352 | #[attr] | ||
353 | foo: u32, | ||
354 | // comment | ||
355 | #[attr] | ||
356 | /// doc | ||
357 | bar: u32 | ||
358 | } | ||
359 | }"#, | ||
360 | r#" | ||
361 | struct One{ | ||
362 | // comment | ||
363 | /// doc | ||
364 | #[attr] | ||
365 | pub foo: u32, | ||
366 | // comment | ||
367 | #[attr] | ||
368 | /// doc | ||
369 | pub bar: u32 | ||
370 | } | ||
371 | |||
372 | enum A { | ||
373 | One(One) | ||
374 | }"#, | ||
375 | ); | ||
376 | } | ||
377 | |||
378 | #[test] | ||
379 | fn test_extract_struct_keep_comments_and_attrs_several_fields_tuple() { | ||
380 | check_assist( | ||
381 | extract_struct_from_enum_variant, | ||
382 | "enum A { $0One(/* comment */ #[attr] u32, /* another */ u32 /* tail */) }", | ||
383 | r#" | ||
384 | struct One(/* comment */ #[attr] pub u32, /* another */ pub u32 /* tail */); | ||
385 | |||
386 | enum A { One(One) }"#, | ||
387 | ); | ||
388 | } | ||
389 | |||
390 | #[test] | ||
391 | fn test_extract_struct_keep_existing_visibility_named() { | ||
392 | check_assist( | ||
393 | extract_struct_from_enum_variant, | ||
394 | "enum A { $0One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } }", | ||
395 | r#" | ||
396 | struct One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, pub d: u32 } | ||
397 | |||
398 | enum A { One(One) }"#, | ||
399 | ); | ||
400 | } | ||
401 | |||
402 | #[test] | ||
403 | fn test_extract_struct_keep_existing_visibility_tuple() { | ||
404 | check_assist( | ||
405 | extract_struct_from_enum_variant, | ||
406 | "enum A { $0One(pub u32, pub(crate) u32, pub(super) u32, u32) }", | ||
407 | r#" | ||
408 | struct One(pub u32, pub(crate) u32, pub(super) u32, pub u32); | ||
409 | |||
410 | enum A { One(One) }"#, | ||
411 | ); | ||
412 | } | ||
413 | |||
414 | #[test] | ||
298 | fn test_extract_enum_variant_name_value_namespace() { | 415 | fn test_extract_enum_variant_name_value_namespace() { |
299 | check_assist( | 416 | check_assist( |
300 | extract_struct_from_enum_variant, | 417 | extract_struct_from_enum_variant, |
diff --git a/crates/ide_assists/src/handlers/pull_assignment_up.rs b/crates/ide_assists/src/handlers/pull_assignment_up.rs index 28d14b9c3..3128faa68 100644 --- a/crates/ide_assists/src/handlers/pull_assignment_up.rs +++ b/crates/ide_assists/src/handlers/pull_assignment_up.rs | |||
@@ -60,6 +60,12 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
60 | return None; | 60 | return None; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | if let Some(parent) = tgt.syntax().parent() { | ||
64 | if matches!(parent.kind(), syntax::SyntaxKind::BIN_EXPR | syntax::SyntaxKind::LET_STMT) { | ||
65 | return None; | ||
66 | } | ||
67 | } | ||
68 | |||
63 | acc.add( | 69 | acc.add( |
64 | AssistId("pull_assignment_up", AssistKind::RefactorExtract), | 70 | AssistId("pull_assignment_up", AssistKind::RefactorExtract), |
65 | "Pull assignment up", | 71 | "Pull assignment up", |
@@ -74,7 +80,13 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
74 | let tgt = edit.make_ast_mut(tgt); | 80 | let tgt = edit.make_ast_mut(tgt); |
75 | 81 | ||
76 | for (stmt, rhs) in assignments { | 82 | for (stmt, rhs) in assignments { |
77 | ted::replace(stmt.syntax(), rhs.syntax()); | 83 | let mut stmt = stmt.syntax().clone(); |
84 | if let Some(parent) = stmt.parent() { | ||
85 | if ast::ExprStmt::cast(parent.clone()).is_some() { | ||
86 | stmt = parent.clone(); | ||
87 | } | ||
88 | } | ||
89 | ted::replace(stmt, rhs.syntax()); | ||
78 | } | 90 | } |
79 | let assign_expr = make::expr_assignment(collector.common_lhs, tgt.clone()); | 91 | let assign_expr = make::expr_assignment(collector.common_lhs, tgt.clone()); |
80 | let assign_stmt = make::expr_stmt(assign_expr); | 92 | let assign_stmt = make::expr_stmt(assign_expr); |
@@ -87,7 +99,7 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
87 | struct AssignmentsCollector<'a> { | 99 | struct AssignmentsCollector<'a> { |
88 | sema: &'a hir::Semantics<'a, ide_db::RootDatabase>, | 100 | sema: &'a hir::Semantics<'a, ide_db::RootDatabase>, |
89 | common_lhs: ast::Expr, | 101 | common_lhs: ast::Expr, |
90 | assignments: Vec<(ast::ExprStmt, ast::Expr)>, | 102 | assignments: Vec<(ast::BinExpr, ast::Expr)>, |
91 | } | 103 | } |
92 | 104 | ||
93 | impl<'a> AssignmentsCollector<'a> { | 105 | impl<'a> AssignmentsCollector<'a> { |
@@ -95,6 +107,7 @@ impl<'a> AssignmentsCollector<'a> { | |||
95 | for arm in match_expr.match_arm_list()?.arms() { | 107 | for arm in match_expr.match_arm_list()?.arms() { |
96 | match arm.expr()? { | 108 | match arm.expr()? { |
97 | ast::Expr::BlockExpr(block) => self.collect_block(&block)?, | 109 | ast::Expr::BlockExpr(block) => self.collect_block(&block)?, |
110 | ast::Expr::BinExpr(expr) => self.collect_expr(&expr)?, | ||
98 | _ => return None, | 111 | _ => return None, |
99 | } | 112 | } |
100 | } | 113 | } |
@@ -114,24 +127,30 @@ impl<'a> AssignmentsCollector<'a> { | |||
114 | } | 127 | } |
115 | } | 128 | } |
116 | fn collect_block(&mut self, block: &ast::BlockExpr) -> Option<()> { | 129 | fn collect_block(&mut self, block: &ast::BlockExpr) -> Option<()> { |
117 | if block.tail_expr().is_some() { | 130 | let last_expr = block.tail_expr().or_else(|| { |
118 | return None; | 131 | if let ast::Stmt::ExprStmt(stmt) = block.statements().last()? { |
119 | } | 132 | stmt.expr() |
120 | 133 | } else { | |
121 | let last_stmt = block.statements().last()?; | 134 | None |
122 | if let ast::Stmt::ExprStmt(stmt) = last_stmt { | ||
123 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { | ||
124 | if expr.op_kind()? == ast::BinOp::Assignment | ||
125 | && is_equivalent(self.sema, &expr.lhs()?, &self.common_lhs) | ||
126 | { | ||
127 | self.assignments.push((stmt, expr.rhs()?)); | ||
128 | return Some(()); | ||
129 | } | ||
130 | } | 135 | } |
136 | })?; | ||
137 | |||
138 | if let ast::Expr::BinExpr(expr) = last_expr { | ||
139 | return self.collect_expr(&expr); | ||
131 | } | 140 | } |
132 | 141 | ||
133 | None | 142 | None |
134 | } | 143 | } |
144 | |||
145 | fn collect_expr(&mut self, expr: &ast::BinExpr) -> Option<()> { | ||
146 | if expr.op_kind()? == ast::BinOp::Assignment | ||
147 | && is_equivalent(self.sema, &expr.lhs()?, &self.common_lhs) | ||
148 | { | ||
149 | self.assignments.push((expr.clone(), expr.rhs()?)); | ||
150 | return Some(()); | ||
151 | } | ||
152 | None | ||
153 | } | ||
135 | } | 154 | } |
136 | 155 | ||
137 | fn is_equivalent( | 156 | fn is_equivalent( |
@@ -241,7 +260,6 @@ fn foo() { | |||
241 | } | 260 | } |
242 | 261 | ||
243 | #[test] | 262 | #[test] |
244 | #[ignore] | ||
245 | fn test_pull_assignment_up_assignment_expressions() { | 263 | fn test_pull_assignment_up_assignment_expressions() { |
246 | check_assist( | 264 | check_assist( |
247 | pull_assignment_up, | 265 | pull_assignment_up, |