Rollup merge of #103468 - chenyukang:yukang/fix-103435-extra-parentheses, r=estebank
Fix unused lint and parser caring about spaces to won't produce invalid code Fixes #103435
This commit is contained in:
commit
fd5ff82f28
6 changed files with 149 additions and 20 deletions
|
@ -565,10 +565,24 @@ trait UnusedDelimLint {
|
|||
lint.set_arg("delim", Self::DELIM_STR);
|
||||
lint.set_arg("item", msg);
|
||||
if let Some((lo, hi)) = spans {
|
||||
let replacement = vec![
|
||||
(lo, if keep_space.0 { " ".into() } else { "".into() }),
|
||||
(hi, if keep_space.1 { " ".into() } else { "".into() }),
|
||||
];
|
||||
let sm = cx.sess().source_map();
|
||||
let lo_replace =
|
||||
if keep_space.0 &&
|
||||
let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(" ") {
|
||||
" ".to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let hi_replace =
|
||||
if keep_space.1 &&
|
||||
let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(" ") {
|
||||
" ".to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let replacement = vec![(lo, lo_replace), (hi, hi_replace)];
|
||||
lint.multipart_suggestion(
|
||||
fluent::suggestion,
|
||||
replacement,
|
||||
|
@ -765,6 +779,7 @@ impl UnusedParens {
|
|||
value: &ast::Pat,
|
||||
avoid_or: bool,
|
||||
avoid_mut: bool,
|
||||
keep_space: (bool, bool),
|
||||
) {
|
||||
use ast::{BindingAnnotation, PatKind};
|
||||
|
||||
|
@ -789,7 +804,7 @@ impl UnusedParens {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
|
||||
self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -798,7 +813,7 @@ impl EarlyLintPass for UnusedParens {
|
|||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
match e.kind {
|
||||
ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
|
||||
self.check_unused_parens_pat(cx, pat, false, false);
|
||||
self.check_unused_parens_pat(cx, pat, false, false, (true, true));
|
||||
}
|
||||
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
|
||||
// handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
|
||||
|
@ -842,6 +857,7 @@ impl EarlyLintPass for UnusedParens {
|
|||
|
||||
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
|
||||
use ast::{Mutability, PatKind::*};
|
||||
let keep_space = (false, false);
|
||||
match &p.kind {
|
||||
// Do not lint on `(..)` as that will result in the other arms being useless.
|
||||
Paren(_)
|
||||
|
@ -849,33 +865,33 @@ impl EarlyLintPass for UnusedParens {
|
|||
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
||||
// These are list-like patterns; parens can always be removed.
|
||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
||||
self.check_unused_parens_pat(cx, p, false, false);
|
||||
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
||||
},
|
||||
Struct(_, _, fps, _) => for f in fps {
|
||||
self.check_unused_parens_pat(cx, &f.pat, false, false);
|
||||
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
|
||||
},
|
||||
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
|
||||
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
|
||||
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
||||
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
||||
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
||||
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not),
|
||||
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
||||
if let StmtKind::Local(ref local) = s.kind {
|
||||
self.check_unused_parens_pat(cx, &local.pat, true, false);
|
||||
self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false));
|
||||
}
|
||||
|
||||
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
|
||||
}
|
||||
|
||||
fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
|
||||
self.check_unused_parens_pat(cx, ¶m.pat, true, false);
|
||||
self.check_unused_parens_pat(cx, ¶m.pat, true, false, (false, false));
|
||||
}
|
||||
|
||||
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
|
||||
self.check_unused_parens_pat(cx, &arm.pat, false, false);
|
||||
self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false));
|
||||
}
|
||||
|
||||
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
|
||||
|
|
|
@ -1165,10 +1165,12 @@ pub(crate) struct ParenthesesInForHead {
|
|||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
|
||||
pub(crate) struct ParenthesesInForHeadSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
#[suggestion_part(code = "{left_snippet}")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = "")]
|
||||
pub left_snippet: String,
|
||||
#[suggestion_part(code = "{right_snippet}")]
|
||||
pub right: Span,
|
||||
pub right_snippet: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
@ -1653,15 +1653,29 @@ impl<'a> Parser<'a> {
|
|||
(token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
|
||||
self.bump();
|
||||
|
||||
let sm = self.sess.source_map();
|
||||
let left = begin_par_sp;
|
||||
let right = self.prev_token.span;
|
||||
let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) &&
|
||||
!snip.ends_with(" ") {
|
||||
" ".to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) &&
|
||||
!snip.starts_with(" ") {
|
||||
" ".to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
self.sess.emit_err(ParenthesesInForHead {
|
||||
span: vec![begin_par_sp, self.prev_token.span],
|
||||
span: vec![left, right],
|
||||
// With e.g. `for (x) in y)` this would replace `(x) in y)`
|
||||
// with `x) in y)` which is syntactically invalid.
|
||||
// However, this is prevented before we get here.
|
||||
sugg: ParenthesesInForHeadSugg {
|
||||
left: begin_par_sp,
|
||||
right: self.prev_token.span,
|
||||
},
|
||||
sugg: ParenthesesInForHeadSugg { left, right, left_snippet, right_snippet },
|
||||
});
|
||||
|
||||
// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
|
||||
|
|
18
src/test/ui/lint/issue-103435-extra-parentheses.fixed
Normal file
18
src/test/ui/lint/issue-103435-extra-parentheses.fixed
Normal file
|
@ -0,0 +1,18 @@
|
|||
// run-rustfix
|
||||
#![deny(unused_parens)]
|
||||
|
||||
fn main() {
|
||||
if let Some(_) = Some(1) {}
|
||||
//~^ ERROR unnecessary parentheses around pattern
|
||||
|
||||
for _x in 1..10 {}
|
||||
//~^ ERROR unnecessary parentheses around pattern
|
||||
|
||||
if 2 == 1 {}
|
||||
//~^ ERROR unnecessary parentheses around `if` condition
|
||||
|
||||
// reported by parser
|
||||
for _x in 1..10 {}
|
||||
//~^ ERROR expected one of
|
||||
//~| ERROR unexpected parentheses surrounding
|
||||
}
|
18
src/test/ui/lint/issue-103435-extra-parentheses.rs
Normal file
18
src/test/ui/lint/issue-103435-extra-parentheses.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// run-rustfix
|
||||
#![deny(unused_parens)]
|
||||
|
||||
fn main() {
|
||||
if let(Some(_))= Some(1) {}
|
||||
//~^ ERROR unnecessary parentheses around pattern
|
||||
|
||||
for(_x)in 1..10 {}
|
||||
//~^ ERROR unnecessary parentheses around pattern
|
||||
|
||||
if(2 == 1){}
|
||||
//~^ ERROR unnecessary parentheses around `if` condition
|
||||
|
||||
// reported by parser
|
||||
for(_x in 1..10){}
|
||||
//~^ ERROR expected one of
|
||||
//~| ERROR unexpected parentheses surrounding
|
||||
}
|
61
src/test/ui/lint/issue-103435-extra-parentheses.stderr
Normal file
61
src/test/ui/lint/issue-103435-extra-parentheses.stderr
Normal file
|
@ -0,0 +1,61 @@
|
|||
error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
|
||||
--> $DIR/issue-103435-extra-parentheses.rs:15:12
|
||||
|
|
||||
LL | for(_x in 1..10){}
|
||||
| ^^ expected one of `)`, `,`, `@`, or `|`
|
||||
|
||||
error: unexpected parentheses surrounding `for` loop head
|
||||
--> $DIR/issue-103435-extra-parentheses.rs:15:8
|
||||
|
|
||||
LL | for(_x in 1..10){}
|
||||
| ^ ^
|
||||
|
|
||||
help: remove parentheses in `for` loop
|
||||
|
|
||||
LL - for(_x in 1..10){}
|
||||
LL + for _x in 1..10 {}
|
||||
|
|
||||
|
||||
error: unnecessary parentheses around pattern
|
||||
--> $DIR/issue-103435-extra-parentheses.rs:5:11
|
||||
|
|
||||
LL | if let(Some(_))= Some(1) {}
|
||||
| ^ ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-103435-extra-parentheses.rs:2:9
|
||||
|
|
||||
LL | #![deny(unused_parens)]
|
||||
| ^^^^^^^^^^^^^
|
||||
help: remove these parentheses
|
||||
|
|
||||
LL - if let(Some(_))= Some(1) {}
|
||||
LL + if let Some(_) = Some(1) {}
|
||||
|
|
||||
|
||||
error: unnecessary parentheses around pattern
|
||||
--> $DIR/issue-103435-extra-parentheses.rs:8:8
|
||||
|
|
||||
LL | for(_x)in 1..10 {}
|
||||
| ^ ^
|
||||
|
|
||||
help: remove these parentheses
|
||||
|
|
||||
LL - for(_x)in 1..10 {}
|
||||
LL + for _x in 1..10 {}
|
||||
|
|
||||
|
||||
error: unnecessary parentheses around `if` condition
|
||||
--> $DIR/issue-103435-extra-parentheses.rs:11:7
|
||||
|
|
||||
LL | if(2 == 1){}
|
||||
| ^ ^
|
||||
|
|
||||
help: remove these parentheses
|
||||
|
|
||||
LL - if(2 == 1){}
|
||||
LL + if 2 == 1 {}
|
||||
|
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
Loading…
Add table
Reference in a new issue