diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a44ffdd3d4..6ef338b819d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3280,6 +3280,7 @@ Released 2018-09-13 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions +[`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops diff --git a/clippy_lints/src/as_underscore.rs b/clippy_lints/src/as_underscore.rs new file mode 100644 index 00000000000..464be4218dd --- /dev/null +++ b/clippy_lints/src/as_underscore.rs @@ -0,0 +1,74 @@ +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, TyKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Check for the usage of `as _` conversion using inferred type. + /// + /// ### Why is this bad? + /// The conversion might include lossy conversion and dangerous cast that might go + /// undetected du to the type being inferred. + /// + /// The lint is allowed by default as using `_` is less wordy than always specifying the type. + /// + /// ### Example + /// ```rust + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as _); + /// ``` + /// Use instead: + /// ```rust + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as usize); + /// ``` + #[clippy::version = "1.63.0"] + pub AS_UNDERSCORE, + restriction, + "detects `as _` conversion" +} +declare_lint_pass!(AsUnderscore => [AS_UNDERSCORE]); + +impl<'tcx> LateLintPass<'tcx> for AsUnderscore { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if in_external_macro(cx.sess(), expr.span) { + return; + } + + if let ExprKind::Cast(_, ty) = expr.kind && let TyKind::Infer = ty.kind { + + let ty_resolved = cx.typeck_results().expr_ty(expr); + if let ty::Error(_) = ty_resolved.kind() { + span_lint_and_help( + cx, + AS_UNDERSCORE, + expr.span, + "using `as _` conversion", + None, + "consider giving the type explicitly", + ); + } else { + span_lint_and_then( + cx, + AS_UNDERSCORE, + expr.span, + "using `as _` conversion", + |diag| { + diag.span_suggestion( + ty.span, + "consider giving the type explicitly", + format!("{}", ty_resolved), + Applicability::MachineApplicable, + ); + } + ); + } + } + } +} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 29bfc660d29..f2e0083dea6 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -37,6 +37,7 @@ almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, as_conversions::AS_CONVERSIONS, + as_underscore::AS_UNDERSCORE, asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, assertions_on_constants::ASSERTIONS_ON_CONSTANTS, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 304b595541a..aaa83402ccc 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -4,6 +4,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(as_conversions::AS_CONVERSIONS), + LintId::of(as_underscore::AS_UNDERSCORE), LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6c3d7594f5c..235a998f753 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -171,6 +171,7 @@ macro_rules! declare_clippy_lint { mod almost_complete_letter_range; mod approx_const; mod as_conversions; +mod as_underscore; mod asm_syntax; mod assertions_on_constants; mod assign_ops; @@ -919,6 +920,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch)); + store.register_late_pass(|| Box::new(as_underscore::AsUnderscore)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/as_underscore.fixed b/tests/ui/as_underscore.fixed new file mode 100644 index 00000000000..948f6d8e6b1 --- /dev/null +++ b/tests/ui/as_underscore.fixed @@ -0,0 +1,13 @@ +// run-rustfix + +#![warn(clippy::as_underscore)] + +fn foo(_n: usize) {} + +fn main() { + let n: u16 = 256; + foo(n as usize); + + let n = 0_u128; + let _n: u8 = n as u8; +} diff --git a/tests/ui/as_underscore.rs b/tests/ui/as_underscore.rs new file mode 100644 index 00000000000..97785ed08a8 --- /dev/null +++ b/tests/ui/as_underscore.rs @@ -0,0 +1,13 @@ +// run-rustfix + +#![warn(clippy::as_underscore)] + +fn foo(_n: usize) {} + +fn main() { + let n: u16 = 256; + foo(n as _); + + let n = 0_u128; + let _n: u8 = n as _; +} diff --git a/tests/ui/as_underscore.stderr b/tests/ui/as_underscore.stderr new file mode 100644 index 00000000000..d7cd58d965a --- /dev/null +++ b/tests/ui/as_underscore.stderr @@ -0,0 +1,20 @@ +error: using `as _` conversion + --> $DIR/as_underscore.rs:9:9 + | +LL | foo(n as _); + | ^^^^^- + | | + | help: consider giving the type explicitly: `usize` + | + = note: `-D clippy::as-underscore` implied by `-D warnings` + +error: using `as _` conversion + --> $DIR/as_underscore.rs:12:18 + | +LL | let _n: u8 = n as _; + | ^^^^^- + | | + | help: consider giving the type explicitly: `u8` + +error: aborting due to 2 previous errors +