diagnostics: avoid wrong `unused_parens` on `x as (T) < y`

This commit is contained in:
Michael Howell 2023-08-31 19:11:58 -07:00
parent 91942134c6
commit 62835c9531
5 changed files with 189 additions and 1 deletions

View File

@ -228,6 +228,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
}) => self.check_id(closure_id),
_ => {}
}
lint_callback!(self, check_expr_post, e);
}
fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) {

View File

@ -153,6 +153,7 @@ macro_rules! early_lint_methods {
fn check_pat(a: &ast::Pat);
fn check_pat_post(a: &ast::Pat);
fn check_expr(a: &ast::Expr);
fn check_expr_post(a: &ast::Expr);
fn check_ty(a: &ast::Ty);
fn check_generic_arg(a: &ast::GenericArg);
fn check_generic_param(a: &ast::GenericParam);

View File

@ -955,11 +955,14 @@ declare_lint! {
pub struct UnusedParens {
with_self_ty_parens: bool,
/// `1 as (i32) < 2` parses to ExprKind::Lt
/// `1 as i32 < 2` parses to i32::<2[missing angle bracket]
parens_in_cast_in_lt: Vec<ast::NodeId>,
}
impl UnusedParens {
pub fn new() -> Self {
Self { with_self_ty_parens: false }
Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() }
}
}
@ -1055,6 +1058,14 @@ impl UnusedParens {
impl EarlyLintPass for UnusedParens {
#[inline]
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
if let ExprKind::Binary(op, lhs, _rhs) = &e.kind &&
(op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) &&
let ExprKind::Cast(_expr, ty) = &lhs.kind &&
let ast::TyKind::Paren(_) = &ty.kind
{
self.parens_in_cast_in_lt.push(ty.id);
}
match e.kind {
ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
self.check_unused_parens_pat(cx, pat, false, false, (true, true));
@ -1101,6 +1112,17 @@ impl EarlyLintPass for UnusedParens {
<Self as UnusedDelimLint>::check_expr(self, cx, e)
}
fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) {
if let ExprKind::Binary(op, lhs, _rhs) = &e.kind &&
(op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) &&
let ExprKind::Cast(_expr, ty) = &lhs.kind &&
let ast::TyKind::Paren(_) = &ty.kind
{
let id = self.parens_in_cast_in_lt.pop().expect("check_expr and check_expr_post must balance");
assert_eq!(id, ty.id, "check_expr and check_expr_post is a depth-first tree traversal");
}
}
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
use ast::{Mutability, PatKind::*};
let keep_space = (false, false);
@ -1141,6 +1163,11 @@ impl EarlyLintPass for UnusedParens {
}
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
if let ast::TyKind::Paren(_) = ty.kind &&
Some(&ty.id) == self.parens_in_cast_in_lt.last()
{
return;
}
match &ty.kind {
ast::TyKind::Array(_, len) => {
self.check_unused_delims_expr(

View File

@ -0,0 +1,32 @@
// check-pass
#![warn(unused_parens)]
fn id<T>(t: T) -> T { t }
fn main() {
// This should not warn
let _ = 1 as (i32) < 2;
let _ = id(1 as (i32) < 2);
let _ = id(1 as i32)
as (i32) < 2;
// These should warn
let _ = 1 as ((i32)) < 2; //~WARN unnecessary parentheses
let _ = 1 as (i32); //~WARN unnecessary parentheses
let _ = 1 as (i32) > 2; //~WARN unnecessary parentheses
let _ = id(1 as (i32)) //~WARN unnecessary parentheses
as (i32) < 2;
let _ = id(1 as (i32)) < 2; //~WARN unnecessary parentheses
// This should not warn
let _ = 1 as (i32) << 2;
let _ = id(1 as (i32) << 2);
let _ = id(1 as i32)
as (i32) << 2;
// These should warn
let _ = 1 as ((i32)) << 2; //~WARN unnecessary parentheses
let _ = 1 as (i32); //~WARN unnecessary parentheses
let _ = 1 as (i32) >> 2; //~WARN unnecessary parentheses
let _ = id(1 as (i32)) //~WARN unnecessary parentheses
as (i32) << 2;
let _ = id(1 as (i32)) << 2; //~WARN unnecessary parentheses
}

View File

@ -0,0 +1,127 @@
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:13:19
|
LL | let _ = 1 as ((i32)) < 2;
| ^ ^
|
note: the lint level is defined here
--> $DIR/unused-parens-issue-106413.rs:2:9
|
LL | #![warn(unused_parens)]
| ^^^^^^^^^^^^^
help: remove these parentheses
|
LL - let _ = 1 as ((i32)) < 2;
LL + let _ = 1 as (i32) < 2;
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:14:18
|
LL | let _ = 1 as (i32);
| ^ ^
|
help: remove these parentheses
|
LL - let _ = 1 as (i32);
LL + let _ = 1 as i32;
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:15:18
|
LL | let _ = 1 as (i32) > 2;
| ^ ^
|
help: remove these parentheses
|
LL - let _ = 1 as (i32) > 2;
LL + let _ = 1 as i32 > 2;
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:16:21
|
LL | let _ = id(1 as (i32))
| ^ ^
|
help: remove these parentheses
|
LL - let _ = id(1 as (i32))
LL + let _ = id(1 as i32)
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:18:21
|
LL | let _ = id(1 as (i32)) < 2;
| ^ ^
|
help: remove these parentheses
|
LL - let _ = id(1 as (i32)) < 2;
LL + let _ = id(1 as i32) < 2;
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:26:19
|
LL | let _ = 1 as ((i32)) << 2;
| ^ ^
|
help: remove these parentheses
|
LL - let _ = 1 as ((i32)) << 2;
LL + let _ = 1 as (i32) << 2;
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:27:18
|
LL | let _ = 1 as (i32);
| ^ ^
|
help: remove these parentheses
|
LL - let _ = 1 as (i32);
LL + let _ = 1 as i32;
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:28:18
|
LL | let _ = 1 as (i32) >> 2;
| ^ ^
|
help: remove these parentheses
|
LL - let _ = 1 as (i32) >> 2;
LL + let _ = 1 as i32 >> 2;
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:29:21
|
LL | let _ = id(1 as (i32))
| ^ ^
|
help: remove these parentheses
|
LL - let _ = id(1 as (i32))
LL + let _ = id(1 as i32)
|
warning: unnecessary parentheses around type
--> $DIR/unused-parens-issue-106413.rs:31:21
|
LL | let _ = id(1 as (i32)) << 2;
| ^ ^
|
help: remove these parentheses
|
LL - let _ = id(1 as (i32)) << 2;
LL + let _ = id(1 as i32) << 2;
|
warning: 10 warnings emitted