Skip to content

Commit

Permalink
Merge pull request #36 from TogetherGame/custom_lints_1.74.0
Browse files Browse the repository at this point in the history
limit [`unconstrained_numeric_literal`] to simple local binding with lit
  • Loading branch information
surechen authored May 16, 2024
2 parents 7d384b0 + 12e4ff5 commit 5fc198c
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 265 deletions.
87 changes: 27 additions & 60 deletions clippy_lints/src/guidelines/unconstrained_numeric_literal.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,51 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_lint_allowed;
use clippy_utils::source::snippet_opt;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Local, TyKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_span::Span;

use super::UNCONSTRAINED_NUMERIC_LITERAL;

pub(super) fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
if !is_lint_allowed(cx, UNCONSTRAINED_NUMERIC_LITERAL, local.hir_id)
&& let Some(init) = local.init
&& let ExprKind::Lit(lit) = init.kind
&& !in_external_macro(cx.sess(), lit.span)
&& (lit.node.is_numeric() && lit.node.is_unsuffixed())
&& local_has_implicit_ty(local)
{
let mut visitor = LitVisitor::new(cx);
visitor.visit_expr(init);

// The type could be wildcard (`_`), therefore we need to include its span for suggestion.
let span = if let Some(ty) = local.ty {
local.pat.span.to(ty.span)
} else {
local.pat.span
};

if !visitor.unconstrained_lit_spans.is_empty() {
span_lint_and_then(
cx,
UNCONSTRAINED_NUMERIC_LITERAL,
span,
"type of this numeric variable is unconstrained",
|diag| {
let sugg = format!(
"{}: {}",
snippet_opt(cx, local.pat.span).unwrap_or("_".to_string()),
ty_suggestion(cx, init),
);
diag.span_suggestion(
span,
"either add suffix to above numeric literal(s) or label the type explicitly",
sugg,
Applicability::MachineApplicable
);
diag.span_note(
MultiSpan::from_spans(visitor.unconstrained_lit_spans),
"unconstrained numeric literals defined here",
);
}
);
}
span_lint_and_then(
cx,
UNCONSTRAINED_NUMERIC_LITERAL,
span,
"type of this numeric variable is unconstrained",
|diag| {
let sugg = format!(
"{}: {}",
snippet_opt(cx, local.pat.span).unwrap_or("_".to_string()),
ty_suggestion(cx, init),
);
diag.span_suggestion(
span,
"either add suffix to above numeric literal(s) or label the type explicitly",
sugg,
Applicability::MachineApplicable
);
diag.span_note(
lit.span,
"unconstrained numeric literals defined here",
);
}
);
}
}

Expand All @@ -61,35 +57,6 @@ fn local_has_implicit_ty(local: &Local<'_>) -> bool {
}
}

struct LitVisitor<'hir, 'tcx> {
cx: &'hir LateContext<'tcx>,
unconstrained_lit_spans: Vec<Span>,
}

impl<'hir, 'tcx> LitVisitor<'hir, 'tcx> {
fn new(cx: &'hir LateContext<'tcx>) -> Self {
Self {
cx,
unconstrained_lit_spans: vec![],
}
}
}

impl<'hir, 'tcx> Visitor<'hir> for LitVisitor<'hir, 'tcx> {
fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
if let ExprKind::Lit(lit) = ex.kind {
if lit.node.is_numeric() && lit.node.is_unsuffixed() && !in_external_macro(self.cx.sess(), lit.span) {
self.unconstrained_lit_spans.push(lit.span);
}
} else {
walk_expr(self, ex);
}
}

// Don't visit local in this visitor, `Local`s are handled in `check_local` call.
fn visit_local(&mut self, _: &'hir Local<'hir>) {}
}

fn ty_suggestion(cx: &LateContext<'_>, init: &Expr<'_>) -> String {
let ty = cx.typeck_results().expr_ty(init);
ty.to_string()
Expand Down
33 changes: 1 addition & 32 deletions tests/ui/guidelines/unconstrained_numeric_literal.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,6 @@ mod basic_expr {
//~| NOTE: `-D clippy::unconstrained-numeric-literal` implied by `-D warnings`
let x: f64 = 22.0;
//~^ ERROR: type of this numeric variable is unconstrained
let x: [i32; 3] = [1, 2, 3];
//~^ ERROR: type of this numeric variable is unconstrained
let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
//~^ ERROR: type of this numeric variable is unconstrained
let x: (f64, i32, f64) = if true { (1.0, 2, 3.0) } else { (3.0, 4, 5.0) };
//~^ ERROR: type of this numeric variable is unconstrained
let x: i32 = match 1 {
//~^ ERROR: type of this numeric variable is unconstrained
1 => 1,
_ => 2,
};
// Has type annotation but it's a wildcard.
let x: i32 = 1;
//~^ ERROR: type of this numeric variable is unconstrained
Expand All @@ -39,14 +28,7 @@ mod basic_expr {

mod nested_local {
fn test() {
let x: i32 = {
//~^ ERROR: type of this numeric variable is unconstrained
let y: i32 = 1;
//~^ ERROR: type of this numeric variable is unconstrained
1
};

let x: i32 = {
let x = {
let y: i32 = 1;
//~^ ERROR: type of this numeric variable is unconstrained
1
Expand Down Expand Up @@ -79,17 +61,4 @@ fn check_expect_suppression() {
let x = 21;
}

#[allow(clippy::useless_vec)]
fn check_vac_macro() {
let x: std::vec::Vec<i32> = vec![1, 2, 3];
//~^ ERROR: type of this numeric variable is unconstrained
let x: std::vec::Vec<f64> = vec![1.0];
//~^ ERROR: type of this numeric variable is unconstrained

let y = vec![1_i32, 2_i32];
let y = vec![0_u8, 1_u8];
let y = vec![2.0_f64, 3.0_f64];
let y: Vec<i32> = vec![1, 2];
}

fn main() {}
31 changes: 0 additions & 31 deletions tests/ui/guidelines/unconstrained_numeric_literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,6 @@ mod basic_expr {
//~| NOTE: `-D clippy::unconstrained-numeric-literal` implied by `-D warnings`
let x = 22.0;
//~^ ERROR: type of this numeric variable is unconstrained
let x = [1, 2, 3];
//~^ ERROR: type of this numeric variable is unconstrained
let x = if true { (1, 2) } else { (3, 4) };
//~^ ERROR: type of this numeric variable is unconstrained
let x = if true { (1.0, 2, 3.0) } else { (3.0, 4, 5.0) };
//~^ ERROR: type of this numeric variable is unconstrained
let x = match 1 {
//~^ ERROR: type of this numeric variable is unconstrained
1 => 1,
_ => 2,
};
// Has type annotation but it's a wildcard.
let x: _ = 1;
//~^ ERROR: type of this numeric variable is unconstrained
Expand All @@ -40,13 +29,6 @@ mod basic_expr {
mod nested_local {
fn test() {
let x = {
//~^ ERROR: type of this numeric variable is unconstrained
let y = 1;
//~^ ERROR: type of this numeric variable is unconstrained
1
};

let x: i32 = {
let y = 1;
//~^ ERROR: type of this numeric variable is unconstrained
1
Expand Down Expand Up @@ -79,17 +61,4 @@ fn check_expect_suppression() {
let x = 21;
}

#[allow(clippy::useless_vec)]
fn check_vac_macro() {
let x = vec![1, 2, 3];
//~^ ERROR: type of this numeric variable is unconstrained
let x = vec![1.0];
//~^ ERROR: type of this numeric variable is unconstrained

let y = vec![1_i32, 2_i32];
let y = vec![0_u8, 1_u8];
let y = vec![2.0_f64, 3.0_f64];
let y: Vec<i32> = vec![1, 2];
}

fn main() {}
Loading

0 comments on commit 5fc198c

Please sign in to comment.