Skip to content

Commit 43c88c6

Browse files
committed
Move char_lit_as_u8 to its own module
1 parent f33bb3d commit 43c88c6

File tree

3 files changed

+75
-70
lines changed

3 files changed

+75
-70
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use rustc_ast::LitKind;
2+
use rustc_errors::Applicability;
3+
use rustc_hir::{Expr, ExprKind};
4+
use rustc_lint::LateContext;
5+
use rustc_middle::ty::{self, UintTy};
6+
7+
use if_chain::if_chain;
8+
9+
use crate::utils::{snippet_with_applicability, span_lint_and_then};
10+
11+
use super::CHAR_LIT_AS_U8;
12+
13+
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
14+
if_chain! {
15+
if let ExprKind::Cast(e, _) = &expr.kind;
16+
if let ExprKind::Lit(l) = &e.kind;
17+
if let LitKind::Char(c) = l.node;
18+
if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind();
19+
then {
20+
let mut applicability = Applicability::MachineApplicable;
21+
let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
22+
23+
span_lint_and_then(
24+
cx,
25+
CHAR_LIT_AS_U8,
26+
expr.span,
27+
"casting a character literal to `u8` truncates",
28+
|diag| {
29+
diag.note("`char` is four bytes wide, but `u8` is a single byte");
30+
31+
if c.is_ascii() {
32+
diag.span_suggestion(
33+
expr.span,
34+
"use a byte literal instead",
35+
format!("b{}", snippet),
36+
applicability,
37+
);
38+
}
39+
});
40+
}
41+
}
42+
}

clippy_lints/src/casts/mod.rs

Lines changed: 33 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod cast_precision_loss;
55
mod cast_ptr_alignment;
66
mod cast_ref_to_mut;
77
mod cast_sign_loss;
8+
mod char_lit_as_u8;
89
mod fn_to_numeric_cast;
910
mod fn_to_numeric_cast_with_truncation;
1011
mod unnecessary_cast;
@@ -13,19 +14,16 @@ mod utils;
1314
use std::borrow::Cow;
1415

1516
use if_chain::if_chain;
16-
use rustc_ast::LitKind;
1717
use rustc_errors::Applicability;
1818
use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
1919
use rustc_lint::{LateContext, LateLintPass, LintContext};
2020
use rustc_middle::lint::in_external_macro;
21-
use rustc_middle::ty::{self, TypeAndMut, UintTy};
21+
use rustc_middle::ty::{self, TypeAndMut};
2222
use rustc_semver::RustcVersion;
2323
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
2424

2525
use crate::utils::sugg::Sugg;
26-
use crate::utils::{
27-
is_hir_ty_cfg_dependant, meets_msrv, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then,
28-
};
26+
use crate::utils::{is_hir_ty_cfg_dependant, meets_msrv, span_lint_and_sugg};
2927

3028
declare_clippy_lint! {
3129
/// **What it does:** Checks for casts from any numerical to a float type where
@@ -290,17 +288,45 @@ declare_clippy_lint! {
290288
"a cast of reference to a mutable pointer"
291289
}
292290

291+
declare_clippy_lint! {
292+
/// **What it does:** Checks for expressions where a character literal is cast
293+
/// to `u8` and suggests using a byte literal instead.
294+
///
295+
/// **Why is this bad?** In general, casting values to smaller types is
296+
/// error-prone and should be avoided where possible. In the particular case of
297+
/// converting a character literal to u8, it is easy to avoid by just using a
298+
/// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
299+
/// than `'a' as u8`.
300+
///
301+
/// **Known problems:** None.
302+
///
303+
/// **Example:**
304+
/// ```rust,ignore
305+
/// 'x' as u8
306+
/// ```
307+
///
308+
/// A better version, using the byte literal:
309+
///
310+
/// ```rust,ignore
311+
/// b'x'
312+
/// ```
313+
pub CHAR_LIT_AS_U8,
314+
complexity,
315+
"casting a character literal to `u8` truncates"
316+
}
317+
293318
declare_lint_pass!(Casts => [
294319
CAST_PRECISION_LOSS,
295320
CAST_SIGN_LOSS,
296321
CAST_POSSIBLE_TRUNCATION,
297322
CAST_POSSIBLE_WRAP,
298323
CAST_LOSSLESS,
299324
CAST_REF_TO_MUT,
300-
UNNECESSARY_CAST,
301325
CAST_PTR_ALIGNMENT,
326+
UNNECESSARY_CAST,
302327
FN_TO_NUMERIC_CAST,
303328
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
329+
CHAR_LIT_AS_U8,
304330
]);
305331

306332
impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -335,74 +361,12 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
335361
}
336362

337363
cast_ptr_alignment::check(cx, expr);
364+
char_lit_as_u8::check(cx, expr);
338365
}
339366
}
340367

341368
const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0);
342369

343-
declare_clippy_lint! {
344-
/// **What it does:** Checks for expressions where a character literal is cast
345-
/// to `u8` and suggests using a byte literal instead.
346-
///
347-
/// **Why is this bad?** In general, casting values to smaller types is
348-
/// error-prone and should be avoided where possible. In the particular case of
349-
/// converting a character literal to u8, it is easy to avoid by just using a
350-
/// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
351-
/// than `'a' as u8`.
352-
///
353-
/// **Known problems:** None.
354-
///
355-
/// **Example:**
356-
/// ```rust,ignore
357-
/// 'x' as u8
358-
/// ```
359-
///
360-
/// A better version, using the byte literal:
361-
///
362-
/// ```rust,ignore
363-
/// b'x'
364-
/// ```
365-
pub CHAR_LIT_AS_U8,
366-
complexity,
367-
"casting a character literal to `u8` truncates"
368-
}
369-
370-
declare_lint_pass!(CharLitAsU8 => [CHAR_LIT_AS_U8]);
371-
372-
impl<'tcx> LateLintPass<'tcx> for CharLitAsU8 {
373-
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
374-
if_chain! {
375-
if !expr.span.from_expansion();
376-
if let ExprKind::Cast(e, _) = &expr.kind;
377-
if let ExprKind::Lit(l) = &e.kind;
378-
if let LitKind::Char(c) = l.node;
379-
if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind();
380-
then {
381-
let mut applicability = Applicability::MachineApplicable;
382-
let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
383-
384-
span_lint_and_then(
385-
cx,
386-
CHAR_LIT_AS_U8,
387-
expr.span,
388-
"casting a character literal to `u8` truncates",
389-
|diag| {
390-
diag.note("`char` is four bytes wide, but `u8` is a single byte");
391-
392-
if c.is_ascii() {
393-
diag.span_suggestion(
394-
expr.span,
395-
"use a byte literal instead",
396-
format!("b{}", snippet),
397-
applicability,
398-
);
399-
}
400-
});
401-
}
402-
}
403-
}
404-
}
405-
406370
declare_clippy_lint! {
407371
/// **What it does:**
408372
/// Checks for `as` casts between raw pointers without changing its mutability,

clippy_lints/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11081108
store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
11091109
store.register_late_pass(|| box strings::StringLitAsBytes);
11101110
store.register_late_pass(|| box derive::Derive);
1111-
store.register_late_pass(|| box casts::CharLitAsU8);
11121111
store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
11131112
store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
11141113
store.register_late_pass(|| box empty_enum::EmptyEnum);

0 commit comments

Comments
 (0)