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("delim", Self::DELIM_STR);
|
||||||
lint.set_arg("item", msg);
|
lint.set_arg("item", msg);
|
||||||
if let Some((lo, hi)) = spans {
|
if let Some((lo, hi)) = spans {
|
||||||
let replacement = vec![
|
let sm = cx.sess().source_map();
|
||||||
(lo, if keep_space.0 { " ".into() } else { "".into() }),
|
let lo_replace =
|
||||||
(hi, if keep_space.1 { " ".into() } else { "".into() }),
|
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(
|
lint.multipart_suggestion(
|
||||||
fluent::suggestion,
|
fluent::suggestion,
|
||||||
replacement,
|
replacement,
|
||||||
|
@ -765,6 +779,7 @@ impl UnusedParens {
|
||||||
value: &ast::Pat,
|
value: &ast::Pat,
|
||||||
avoid_or: bool,
|
avoid_or: bool,
|
||||||
avoid_mut: bool,
|
avoid_mut: bool,
|
||||||
|
keep_space: (bool, bool),
|
||||||
) {
|
) {
|
||||||
use ast::{BindingAnnotation, PatKind};
|
use ast::{BindingAnnotation, PatKind};
|
||||||
|
|
||||||
|
@ -789,7 +804,7 @@ impl UnusedParens {
|
||||||
} else {
|
} else {
|
||||||
None
|
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) {
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
|
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
|
// 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
|
// 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) {
|
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
|
||||||
use ast::{Mutability, PatKind::*};
|
use ast::{Mutability, PatKind::*};
|
||||||
|
let keep_space = (false, false);
|
||||||
match &p.kind {
|
match &p.kind {
|
||||||
// Do not lint on `(..)` as that will result in the other arms being useless.
|
// Do not lint on `(..)` as that will result in the other arms being useless.
|
||||||
Paren(_)
|
Paren(_)
|
||||||
|
@ -849,33 +865,33 @@ impl EarlyLintPass for UnusedParens {
|
||||||
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
||||||
// These are list-like patterns; parens can always be removed.
|
// These are list-like patterns; parens can always be removed.
|
||||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
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 {
|
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.
|
// 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.
|
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
||||||
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
// 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) {
|
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
|
||||||
if let StmtKind::Local(ref local) = s.kind {
|
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)
|
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
|
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) {
|
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) {
|
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
|
||||||
|
|
|
@ -1165,10 +1165,12 @@ pub(crate) struct ParenthesesInForHead {
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
|
#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
|
||||||
pub(crate) struct ParenthesesInForHeadSugg {
|
pub(crate) struct ParenthesesInForHeadSugg {
|
||||||
#[suggestion_part(code = "")]
|
#[suggestion_part(code = "{left_snippet}")]
|
||||||
pub left: Span,
|
pub left: Span,
|
||||||
#[suggestion_part(code = "")]
|
pub left_snippet: String,
|
||||||
|
#[suggestion_part(code = "{right_snippet}")]
|
||||||
pub right: Span,
|
pub right: Span,
|
||||||
|
pub right_snippet: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
|
|
@ -1653,15 +1653,29 @@ impl<'a> Parser<'a> {
|
||||||
(token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
|
(token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
|
||||||
self.bump();
|
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 {
|
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 e.g. `for (x) in y)` this would replace `(x) in y)`
|
||||||
// with `x) in y)` which is syntactically invalid.
|
// with `x) in y)` which is syntactically invalid.
|
||||||
// However, this is prevented before we get here.
|
// However, this is prevented before we get here.
|
||||||
sugg: ParenthesesInForHeadSugg {
|
sugg: ParenthesesInForHeadSugg { left, right, left_snippet, right_snippet },
|
||||||
left: begin_par_sp,
|
|
||||||
right: self.prev_token.span,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
|
// 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
Add a link
Reference in a new issue