From 4ea246b0b353daf6ea87e20cfbe51abe90875b21 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 19 Aug 2019 22:24:07 -0400 Subject: [PATCH 1/2] use a structured suggestion for char-lit-as-u8 --- clippy_lints/src/types.rs | 46 +++++++++++++--------- tests/ui/char_lit_as_u8.rs | 4 +- tests/ui/char_lit_as_u8.stderr | 7 ++-- tests/ui/char_lit_as_u8_suggestions.fixed | 10 +++++ tests/ui/char_lit_as_u8_suggestions.rs | 10 +++++ tests/ui/char_lit_as_u8_suggestions.stderr | 35 ++++++++++++++++ 6 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 tests/ui/char_lit_as_u8_suggestions.fixed create mode 100644 tests/ui/char_lit_as_u8_suggestions.rs create mode 100644 tests/ui/char_lit_as_u8_suggestions.stderr diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 28d337d3cd6..f11bcf25aec 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -15,7 +15,7 @@ use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_errors::Applicability; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; -use syntax::ast::{FloatTy, IntTy, UintTy}; +use syntax::ast::{FloatTy, IntTy, LitIntType, LitKind, UintTy}; use syntax::errors::DiagnosticBuilder; use syntax::source_map::Span; use syntax::symbol::sym; @@ -1122,7 +1122,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Casts { let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr)); lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to); if let ExprKind::Lit(ref lit) = ex.node { - use syntax::ast::{LitIntType, LitKind}; if let LitKind::Int(n, _) = lit.node { if cast_to.is_floating_point() { let from_nbits = 128 - n.leading_zeros(); @@ -1473,29 +1472,40 @@ declare_clippy_lint! { /// ``` pub CHAR_LIT_AS_U8, complexity, - "casting a character literal to u8" + "casting a character literal to u8 truncates" } declare_lint_pass!(CharLitAsU8 => [CHAR_LIT_AS_U8]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CharLitAsU8 { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - use syntax::ast::LitKind; + if_chain! { + if !expr.span.from_expansion(); + if let ExprKind::Cast(e, _) = &expr.node; + if let ExprKind::Lit(l) = &e.node; + if let LitKind::Char(c) = l.node; + if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).sty; + then { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability); - if let ExprKind::Cast(ref e, _) = expr.node { - if let ExprKind::Lit(ref l) = e.node { - if let LitKind::Char(_) = l.node { - if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).sty && !expr.span.from_expansion() { - let msg = "casting character literal to u8. `char`s \ - are 4 bytes wide in rust, so casting to u8 \ - truncates them"; - let help = format!( - "Consider using a byte literal instead:\nb{}", - snippet(cx, e.span, "'x'") - ); - span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help); - } - } + span_lint_and_then( + cx, + CHAR_LIT_AS_U8, + expr.span, + "casting a character literal to `u8` truncates", + |db| { + db.note("`char` is four bytes wide, but `u8` is a single byte"); + + if c.is_ascii() { + db.span_suggestion( + expr.span, + "use a byte literal instead", + format!("b{}", snippet), + applicability, + ); + } + }); } } } diff --git a/tests/ui/char_lit_as_u8.rs b/tests/ui/char_lit_as_u8.rs index 211cbfe98f3..0a53a3d6490 100644 --- a/tests/ui/char_lit_as_u8.rs +++ b/tests/ui/char_lit_as_u8.rs @@ -1,5 +1,5 @@ #![warn(clippy::char_lit_as_u8)] -#![allow(unused_variables)] + fn main() { - let c = 'a' as u8; + let _ = '❤' as u8; // no suggestion, since a byte literal won't work. } diff --git a/tests/ui/char_lit_as_u8.stderr b/tests/ui/char_lit_as_u8.stderr index 52f29a3f553..b9836d2f255 100644 --- a/tests/ui/char_lit_as_u8.stderr +++ b/tests/ui/char_lit_as_u8.stderr @@ -1,12 +1,11 @@ -error: casting character literal to u8. `char`s are 4 bytes wide in rust, so casting to u8 truncates them +error: casting a character literal to `u8` truncates --> $DIR/char_lit_as_u8.rs:4:13 | -LL | let c = 'a' as u8; +LL | let _ = '❤' as u8; // no suggestion, since a byte literal won't work. | ^^^^^^^^^ | = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` - = help: Consider using a byte literal instead: - b'a' + = note: `char` is four bytes wide, but `u8` is a single byte error: aborting due to previous error diff --git a/tests/ui/char_lit_as_u8_suggestions.fixed b/tests/ui/char_lit_as_u8_suggestions.fixed new file mode 100644 index 00000000000..3dc3cb4e757 --- /dev/null +++ b/tests/ui/char_lit_as_u8_suggestions.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +#![warn(clippy::char_lit_as_u8)] + +fn main() { + let _ = b'a'; + let _ = b'\n'; + let _ = b'\0'; + let _ = b'\x01'; +} diff --git a/tests/ui/char_lit_as_u8_suggestions.rs b/tests/ui/char_lit_as_u8_suggestions.rs new file mode 100644 index 00000000000..d379a023494 --- /dev/null +++ b/tests/ui/char_lit_as_u8_suggestions.rs @@ -0,0 +1,10 @@ +// run-rustfix + +#![warn(clippy::char_lit_as_u8)] + +fn main() { + let _ = 'a' as u8; + let _ = '\n' as u8; + let _ = '\0' as u8; + let _ = '\x01' as u8; +} diff --git a/tests/ui/char_lit_as_u8_suggestions.stderr b/tests/ui/char_lit_as_u8_suggestions.stderr new file mode 100644 index 00000000000..bf7cb1607b4 --- /dev/null +++ b/tests/ui/char_lit_as_u8_suggestions.stderr @@ -0,0 +1,35 @@ +error: casting a character literal to `u8` truncates + --> $DIR/char_lit_as_u8_suggestions.rs:6:13 + | +LL | let _ = 'a' as u8; + | ^^^^^^^^^ help: use a byte literal instead: `b'a'` + | + = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` + = note: `char` is four bytes wide, but `u8` is a single byte + +error: casting a character literal to `u8` truncates + --> $DIR/char_lit_as_u8_suggestions.rs:7:13 + | +LL | let _ = '/n' as u8; + | ^^^^^^^^^^ help: use a byte literal instead: `b'/n'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: casting a character literal to `u8` truncates + --> $DIR/char_lit_as_u8_suggestions.rs:8:13 + | +LL | let _ = '/0' as u8; + | ^^^^^^^^^^ help: use a byte literal instead: `b'/0'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: casting a character literal to `u8` truncates + --> $DIR/char_lit_as_u8_suggestions.rs:9:13 + | +LL | let _ = '/x01' as u8; + | ^^^^^^^^^^^^ help: use a byte literal instead: `b'/x01'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: aborting due to 4 previous errors + From 14d1d040b435d089d6240dc50a789eccdf857afb Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 4 Sep 2019 15:33:14 +0200 Subject: [PATCH 2/2] Run update_lints --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b7a6e486f0b..d9be47f649b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -171,7 +171,7 @@ pub const ALL_LINTS: [Lint; 311] = [ Lint { name: "char_lit_as_u8", group: "complexity", - desc: "casting a character literal to u8", + desc: "casting a character literal to u8 truncates", deprecation: None, module: "types", },