Unnamed repository; edit this file 'description' to name the repository.
Remove `match_ast!` macro call
Add node about uncommenting tuple in macro call
BooksBaum 2021-08-19
parent b1ebb82 · commit 2c27adc
-rw-r--r--crates/ide_assists/src/handlers/destructure_tuple_binding.rs153
1 files changed, 80 insertions, 73 deletions
diff --git a/crates/ide_assists/src/handlers/destructure_tuple_binding.rs b/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
index 0b7c54b20b..eebeb2c4a5 100644
--- a/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
+++ b/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
@@ -227,6 +227,11 @@ fn edit_tuple_usage(
// no index access -> make invalid -> requires handling by user
// -> put usage in block comment
+ //
+ // Note: For macro invocations this might result in still valid code:
+ // When a macro accepts the tuple as argument, as well as no arguments at all,
+ // uncommenting the tuple still leaves the macro call working (see `tests::in_macro_call::empty_macro`).
+ // But this is an unlikely case. Usually the resulting macro call will become erroneous.
builder.insert(usage.range.start(), "/*");
builder.insert(usage.range.end(), "*/");
}
@@ -322,89 +327,91 @@ fn handle_ref_field_usage(ctx: &AssistContext, field_expr: &FieldExpr) -> RefDat
let mut ref_data =
RefData { range: s.text_range(), needs_deref: true, needs_parentheses: true };
- let parent = match s.parent() {
- Some(parent) => parent,
+ let parent = match s.parent().map(ast::Expr::cast) {
+ Some(Some(parent)) => parent,
+ Some(None) => {
+ ref_data.needs_parentheses = false;
+ return ref_data;
+ }
None => return ref_data,
};
- match_ast! {
- match parent {
- ast::ParenExpr(it) => {
- // already parens in place -> don't replace
- ref_data.needs_parentheses = false;
- // there might be a ref outside: `&(t.0)` -> can be removed
- if let Some(it) = it.syntax().parent().and_then(ast::RefExpr::cast) {
- ref_data.needs_deref = false;
- ref_data.range = it.syntax().text_range();
- }
- },
- ast::RefExpr(it) => {
- // `&*` -> cancel each other out
+ match parent {
+ ast::Expr::ParenExpr(it) => {
+ // already parens in place -> don't replace
+ ref_data.needs_parentheses = false;
+ // there might be a ref outside: `&(t.0)` -> can be removed
+ if let Some(it) = it.syntax().parent().and_then(ast::RefExpr::cast) {
ref_data.needs_deref = false;
- ref_data.needs_parentheses = false;
- // might be surrounded by parens -> can be removed too
- match it.syntax().parent().and_then(ast::ParenExpr::cast) {
- Some(parent) => ref_data.range = parent.syntax().text_range(),
- None => ref_data.range = it.syntax().text_range(),
- };
- },
- // higher precedence than deref `*`
- // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
- // -> requires parentheses
- ast::PathExpr(_it) => {},
- ast::MethodCallExpr(it) => {
- // `field_expr` is `self_param` (otherwise it would be in `ArgList`)
+ ref_data.range = it.syntax().text_range();
+ }
+ }
+ ast::Expr::RefExpr(it) => {
+ // `&*` -> cancel each other out
+ ref_data.needs_deref = false;
+ ref_data.needs_parentheses = false;
+ // might be surrounded by parens -> can be removed too
+ match it.syntax().parent().and_then(ast::ParenExpr::cast) {
+ Some(parent) => ref_data.range = parent.syntax().text_range(),
+ None => ref_data.range = it.syntax().text_range(),
+ };
+ }
+ // higher precedence than deref `*`
+ // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
+ // -> requires parentheses
+ ast::Expr::PathExpr(_it) => {}
+ ast::Expr::MethodCallExpr(it) => {
+ // `field_expr` is `self_param` (otherwise it would be in `ArgList`)
+
+ // test if there's already auto-ref in place (`value` -> `&value`)
+ // -> no method accepting `self`, but `&self` -> no need for deref
+ //
+ // other combinations (`&value` -> `value`, `&&value` -> `&value`, `&value` -> `&&value`) might or might not be able to auto-ref/deref,
+ // but there might be trait implementations an added `&` might resolve to
+ // -> ONLY handle auto-ref from `value` to `&value`
+ fn is_auto_ref(ctx: &AssistContext, call_expr: &MethodCallExpr) -> bool {
+ fn impl_(ctx: &AssistContext, call_expr: &MethodCallExpr) -> Option<bool> {
+ let rec = call_expr.receiver()?;
+ let rec_ty = ctx.sema.type_of_expr(&rec)?.adjusted();
+ // input must be actual value
+ if rec_ty.is_reference() {
+ return Some(false);
+ }
- // test if there's already auto-ref in place (`value` -> `&value`)
- // -> no method accepting `self`, but `&self` -> no need for deref
- //
- // other combinations (`&value` -> `value`, `&&value` -> `&value`, `&value` -> `&&value`) might or might not be able to auto-ref/deref,
- // but there might be trait implementations an added `&` might resolve to
- // -> ONLY handle auto-ref from `value` to `&value`
- fn is_auto_ref(ctx: &AssistContext, call_expr: &MethodCallExpr) -> bool {
- fn impl_(ctx: &AssistContext, call_expr: &MethodCallExpr) -> Option<bool> {
- let rec = call_expr.receiver()?;
- let rec_ty = ctx.sema.type_of_expr(&rec)?.adjusted();
- // input must be actual value
- if rec_ty.is_reference() {
- return Some(false);
- }
-
- // doesn't resolve trait impl
- let f = ctx.sema.resolve_method_call(call_expr)?;
- let self_param = f.self_param(ctx.db())?;
- // self must be ref
- match self_param.access(ctx.db()) {
- hir::Access::Shared | hir::Access::Exclusive => Some(true),
- hir::Access::Owned => Some(false),
- }
+ // doesn't resolve trait impl
+ let f = ctx.sema.resolve_method_call(call_expr)?;
+ let self_param = f.self_param(ctx.db())?;
+ // self must be ref
+ match self_param.access(ctx.db()) {
+ hir::Access::Shared | hir::Access::Exclusive => Some(true),
+ hir::Access::Owned => Some(false),
}
- impl_(ctx, call_expr).unwrap_or(false)
}
+ impl_(ctx, call_expr).unwrap_or(false)
+ }
- if is_auto_ref(ctx, &it) {
- ref_data.needs_deref = false;
- ref_data.needs_parentheses = false;
- }
- },
- ast::FieldExpr(_it) => {
- // `t.0.my_field`
- ref_data.needs_deref = false;
- ref_data.needs_parentheses = false;
- },
- ast::IndexExpr(_it) => {
- // `t.0[1]`
+ if is_auto_ref(ctx, &it) {
ref_data.needs_deref = false;
ref_data.needs_parentheses = false;
- },
- ast::TryExpr(_it) => {
- // `t.0?`
- // requires deref and parens: `(*_0)`
- },
- // lower precedence than deref `*` -> no parens
- _ => {
- ref_data.needs_parentheses = false;
- },
+ }
+ }
+ ast::Expr::FieldExpr(_it) => {
+ // `t.0.my_field`
+ ref_data.needs_deref = false;
+ ref_data.needs_parentheses = false;
+ }
+ ast::Expr::IndexExpr(_it) => {
+ // `t.0[1]`
+ ref_data.needs_deref = false;
+ ref_data.needs_parentheses = false;
+ }
+ ast::Expr::TryExpr(_it) => {
+ // `t.0?`
+ // requires deref and parens: `(*_0)`
+ }
+ // lower precedence than deref `*` -> no parens
+ _ => {
+ ref_data.needs_parentheses = false;
}
};