From d33ad45d7da3da94514351b322aba5052a393202 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 11 Nov 2019 17:42:12 -0500 Subject: [PATCH] trigger string_lit_as_bytes when literal has escapes --- clippy_lints/src/strings.rs | 87 ++++++++++++++--------------- tests/ui/string_lit_as_bytes.fixed | 2 + tests/ui/string_lit_as_bytes.rs | 2 + tests/ui/string_lit_as_bytes.stderr | 8 ++- 4 files changed, 52 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index a3d1193052e..00e2441becf 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -4,6 +4,8 @@ use rustc::{declare_lint_pass, declare_tool_lint}; use rustc_errors::Applicability; use syntax::source_map::Spanned; +use if_chain::if_chain; + use crate::utils::SpanlessEq; use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; @@ -146,53 +148,46 @@ declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { use crate::utils::{snippet, snippet_with_applicability}; - use syntax::ast::{LitKind, StrStyle}; + use syntax::ast::LitKind; - if let ExprKind::MethodCall(ref path, _, ref args) = e.kind { - if path.ident.name == sym!(as_bytes) { - if let ExprKind::Lit(ref lit) = args[0].kind { - if let LitKind::Str(ref lit_content, style) = lit.node { - let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#); - let expanded = if let StrStyle::Raw(n) = style { - let term = "#".repeat(usize::from(n)); - format!("r{0}\"{1}\"{0}", term, lit_content.as_str()) - } else { - format!("\"{}\"", lit_content.as_str()) - }; - let mut applicability = Applicability::MachineApplicable; - if callsite.starts_with("include_str!") { - span_lint_and_sugg( - cx, - STRING_LIT_AS_BYTES, - e.span, - "calling `as_bytes()` on `include_str!(..)`", - "consider using `include_bytes!(..)` instead", - snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen( - "include_str", - "include_bytes", - 1, - ), - applicability, - ); - } else if callsite == expanded - && lit_content.as_str().chars().all(|c| c.is_ascii()) - && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT - && !args[0].span.from_expansion() - { - span_lint_and_sugg( - cx, - STRING_LIT_AS_BYTES, - e.span, - "calling `as_bytes()` on a string literal", - "consider using a byte string literal instead", - format!( - "b{}", - snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability) - ), - applicability, - ); - } - } + if_chain! { + if let ExprKind::MethodCall(path, _, args) = &e.kind; + if path.ident.name == sym!(as_bytes); + if let ExprKind::Lit(lit) = &args[0].kind; + if let LitKind::Str(lit_content, _) = &lit.node; + then { + let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#); + let mut applicability = Applicability::MachineApplicable; + if callsite.starts_with("include_str!") { + span_lint_and_sugg( + cx, + STRING_LIT_AS_BYTES, + e.span, + "calling `as_bytes()` on `include_str!(..)`", + "consider using `include_bytes!(..)` instead", + snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen( + "include_str", + "include_bytes", + 1, + ), + applicability, + ); + } else if lit_content.as_str().is_ascii() + && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT + && !args[0].span.from_expansion() + { + span_lint_and_sugg( + cx, + STRING_LIT_AS_BYTES, + e.span, + "calling `as_bytes()` on a string literal", + "consider using a byte string literal instead", + format!( + "b{}", + snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability) + ), + applicability, + ); } } } diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index c8d1479f120..7ad272ade5f 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -15,6 +15,8 @@ fn str_lit_as_bytes() { let strify = stringify!(foobar).as_bytes(); let includestr = include_bytes!("entry_unfixable.rs"); + + let _ = b"string with newline\t\n"; } fn main() {} diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index f0066d5d177..1bf4538b7c9 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -15,6 +15,8 @@ fn str_lit_as_bytes() { let strify = stringify!(foobar).as_bytes(); let includestr = include_str!("entry_unfixable.rs").as_bytes(); + + let _ = "string with newline\t\n".as_bytes(); } fn main() {} diff --git a/tests/ui/string_lit_as_bytes.stderr b/tests/ui/string_lit_as_bytes.stderr index d6c6c52709f..ff6e3346dfc 100644 --- a/tests/ui/string_lit_as_bytes.stderr +++ b/tests/ui/string_lit_as_bytes.stderr @@ -18,5 +18,11 @@ error: calling `as_bytes()` on `include_str!(..)` LL | let includestr = include_str!("entry_unfixable.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry_unfixable.rs")` -error: aborting due to 3 previous errors +error: calling `as_bytes()` on a string literal + --> $DIR/string_lit_as_bytes.rs:19:13 + | +LL | let _ = "string with newline/t/n".as_bytes(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"` + +error: aborting due to 4 previous errors