about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-09-04 13:33:47 +0000
committerbors <bors@rust-lang.org>2019-09-04 13:33:47 +0000
commit9d2772207ebe378fece31bfdcff4f50eff24c19d (patch)
tree6b0674625066150f6d51be253454ee7552797ea3
parentffe57fad85ffa8561bd5ead77353337d7de23139 (diff)
parent14d1d040b435d089d6240dc50a789eccdf857afb (diff)
downloadrust-9d2772207ebe378fece31bfdcff4f50eff24c19d.tar.gz
rust-9d2772207ebe378fece31bfdcff4f50eff24c19d.zip
Auto merge of #4418 - euclio:byte-lit-suggestion, r=flip1995
use a structured suggestion for char-lit-as-u8

changelog: use a structured suggestion for char-lit-as-u8
-rw-r--r--clippy_lints/src/types.rs48
-rw-r--r--src/lintlist/mod.rs2
-rw-r--r--tests/ui/char_lit_as_u8.rs4
-rw-r--r--tests/ui/char_lit_as_u8.stderr7
-rw-r--r--tests/ui/char_lit_as_u8_suggestions.fixed10
-rw-r--r--tests/ui/char_lit_as_u8_suggestions.rs10
-rw-r--r--tests/ui/char_lit_as_u8_suggestions.stderr35
7 files changed, 90 insertions, 26 deletions
diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs
index 3c2111c55fb..c210cf82a30 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();
@@ -1487,29 +1486,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 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);
-                    }
-                }
+        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);
+
+                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/src/lintlist/mod.rs b/src/lintlist/mod.rs
index be09ac321d2..1435e9968dd 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -171,7 +171,7 @@ pub const ALL_LINTS: [Lint; 313] = [
     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",
     },
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
+