From 9ec8888b91322284859ef7414760bb837bcad393 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko Date: Fri, 15 Nov 2019 22:27:07 +0300 Subject: [PATCH] implemented `as_conversions` lint actuall add files add better example and change pedantic to restriction --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/as_conversions.rs | 56 ++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 +++ src/lintlist/mod.rs | 9 ++++- tests/ui/as_conversions.rs | 7 ++++ tests/ui/as_conversions.stderr | 27 ++++++++++++++ tests/ui/types.fixed | 2 +- tests/ui/types.rs | 2 +- 9 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 clippy_lints/src/as_conversions.rs create mode 100644 tests/ui/as_conversions.rs create mode 100644 tests/ui/as_conversions.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index f21174c0bce..4e747524e9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -929,6 +929,7 @@ Released 2018-09-13 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`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 [`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/README.md b/README.md index d467e05257b..e8818412e90 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 337 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 338 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs new file mode 100644 index 00000000000..ee6357359d1 --- /dev/null +++ b/clippy_lints/src/as_conversions.rs @@ -0,0 +1,56 @@ +use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint}; +use syntax::ast::*; + +use crate::utils::span_help_and_lint; + +declare_clippy_lint! { + /// **What it does:** Checks for usage of `as` conversions. + /// + /// **Why is this bad?** `as` conversions will perform many kinds of + /// conversions, including silently lossy conversions and dangerous coercions. + /// There are cases when it makes sense to use `as`, so the lint is + /// Allow by default. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// let a: u32; + /// ... + /// f(a as u16); + /// ``` + /// + /// Usually better represents the semantics you expect: + /// ```rust,ignore + /// f(a.try_into()?); + /// ``` + /// or + /// ```rust,ignore + /// f(a.try_into().expect("Unexpected u16 overflow in f")); + /// ``` + /// + pub AS_CONVERSIONS, + restriction, + "using a potentially dangerous silent `as` conversion" +} + +declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); + +impl EarlyLintPass for AsConversions { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if in_external_macro(cx.sess(), expr.span) { + return; + } + + if let ExprKind::Cast(_, _) = expr.kind { + span_help_and_lint( + cx, + AS_CONVERSIONS, + expr.span, + "using a potentially dangerous silent `as` conversion", + "consider using a safe wrapper for this conversion", + ); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c8954aef2ba..32518405855 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -155,6 +155,7 @@ mod utils; // begin lints modules, do not remove this comment, it’s used in `update_lints` pub mod approx_const; pub mod arithmetic; +pub mod as_conversions; pub mod assertions_on_constants; pub mod assign_ops; pub mod attrs; @@ -448,6 +449,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &approx_const::APPROX_CONSTANT, &arithmetic::FLOAT_ARITHMETIC, &arithmetic::INTEGER_ARITHMETIC, + &as_conversions::AS_CONVERSIONS, &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, @@ -959,10 +961,12 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); + store.register_early_pass(|| box as_conversions::AsConversions); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), + LintId::of(&as_conversions::AS_CONVERSIONS), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&exit::EXIT), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9b258ffb610..6b7a93f5819 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 337] = [ +pub const ALL_LINTS: [Lint; 338] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -28,6 +28,13 @@ pub const ALL_LINTS: [Lint; 337] = [ deprecation: None, module: "approx_const", }, + Lint { + name: "as_conversions", + group: "restriction", + desc: "using a potentially dangerous silent `as` conversion", + deprecation: None, + module: "as_conversions", + }, Lint { name: "assertions_on_constants", group: "style", diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs new file mode 100644 index 00000000000..e01ba0c64df --- /dev/null +++ b/tests/ui/as_conversions.rs @@ -0,0 +1,7 @@ +#[warn(clippy::as_conversions)] + +fn main() { + let i = 0u32 as u64; + + let j = &i as *const u64 as *mut u64; +} diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr new file mode 100644 index 00000000000..312d3a7460e --- /dev/null +++ b/tests/ui/as_conversions.stderr @@ -0,0 +1,27 @@ +error: using a potentially dangerous silent `as` conversion + --> $DIR/as_conversions.rs:4:13 + | +LL | let i = 0u32 as u64; + | ^^^^^^^^^^^ + | + = note: `-D clippy::as-conversions` implied by `-D warnings` + = help: consider using a safe wrapper for this conversion + +error: using a potentially dangerous silent `as` conversion + --> $DIR/as_conversions.rs:6:13 + | +LL | let j = &i as *const u64 as *mut u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a safe wrapper for this conversion + +error: using a potentially dangerous silent `as` conversion + --> $DIR/as_conversions.rs:6:13 + | +LL | let j = &i as *const u64 as *mut u64; + | ^^^^^^^^^^^^^^^^ + | + = help: consider using a safe wrapper for this conversion + +error: aborting due to 3 previous errors + diff --git a/tests/ui/types.fixed b/tests/ui/types.fixed index b1622e45f3b..417da42edf1 100644 --- a/tests/ui/types.fixed +++ b/tests/ui/types.fixed @@ -1,7 +1,7 @@ // run-rustfix #![allow(dead_code, unused_variables)] -#![warn(clippy::all, clippy::pedantic)] +#![warn(clippy::cast_lossless)] // should not warn on lossy casting in constant types // because not supported yet diff --git a/tests/ui/types.rs b/tests/ui/types.rs index 30463f9e2a1..b16e9e538b1 100644 --- a/tests/ui/types.rs +++ b/tests/ui/types.rs @@ -1,7 +1,7 @@ // run-rustfix #![allow(dead_code, unused_variables)] -#![warn(clippy::all, clippy::pedantic)] +#![warn(clippy::cast_lossless)] // should not warn on lossy casting in constant types // because not supported yet