1 use clippy_utils::diagnostics::span_lint;
2 use clippy_utils::{match_function_call, paths};
3 use rustc_ast::{BorrowKind, LitKind};
4 use rustc_hir::{Expr, ExprKind};
5 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
7 use rustc_span::source_map::Spanned;
10 declare_clippy_lint! {
12 /// Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal
14 /// ### Why is this bad?
15 /// Creating such a `str` would result in undefined behavior
19 /// # #[allow(unused)]
21 /// std::str::from_utf8_unchecked(b"cl\x82ippy");
24 #[clippy::version = "1.64.0"]
25 pub INVALID_UTF8_IN_UNCHECKED,
27 "using a non UTF-8 literal in `std::std::from_utf8_unchecked`"
29 declare_lint_pass!(InvalidUtf8InUnchecked => [INVALID_UTF8_IN_UNCHECKED]);
31 impl<'tcx> LateLintPass<'tcx> for InvalidUtf8InUnchecked {
32 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
33 if let Some([arg]) = match_function_call(cx, expr, &paths::STR_FROM_UTF8_UNCHECKED) {
35 ExprKind::Lit(Spanned { node: lit, .. }) => {
36 if let LitKind::ByteStr(bytes) = &lit
37 && std::str::from_utf8(bytes).is_err()
42 ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => {
43 let elements = args.iter().map(|e|{
45 ExprKind::Lit(Spanned { node: lit, .. }) => match lit {
46 LitKind::Byte(b) => Some(*b),
47 #[allow(clippy::cast_possible_truncation)]
48 LitKind::Int(b, _) => Some(*b as u8),
53 }).collect::<Option<Vec<_>>>();
55 if let Some(elements) = elements
56 && std::str::from_utf8(&elements).is_err()
67 fn lint(cx: &LateContext<'_>, span: Span) {
70 INVALID_UTF8_IN_UNCHECKED,
72 "non UTF-8 literal in `std::str::from_utf8_unchecked`",