diff options
| author | Jane Lusby <jlusby42@gmail.com> | 2018-10-05 09:06:05 -0700 |
|---|---|---|
| committer | Jane Lusby <jlusby42@gmail.com> | 2018-10-26 09:12:01 -0700 |
| commit | c209fc9349ff750dc983ecfe23d8e0bb74f002df (patch) | |
| tree | b43d0e01088ba930cd7252068dd20d43c5b9ee56 /clippy_lints/src/strings.rs | |
| parent | 457e7f12e9fc028eae182f23b279194e5344b676 (diff) | |
| download | rust-c209fc9349ff750dc983ecfe23d8e0bb74f002df.tar.gz rust-c209fc9349ff750dc983ecfe23d8e0bb74f002df.zip | |
Fix string_lit_as_bytes lint for macros
Prior to this change, string_lit_as_bytes would trigger for constructs
like `include_str!("filename").as_bytes()` and would recommend fixing it
by rewriting as `binclude_str!("filename")`.
This change updates the lint to act as an EarlyLintPass lint. It then
differentiates between string literals and macros that have bytes
yielding alternatives.
Closes #3205
Diffstat (limited to 'clippy_lints/src/strings.rs')
| -rw-r--r-- | clippy_lints/src/strings.rs | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index f4798842205..9b6478fb9cd 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -92,7 +92,14 @@ impl LintPass for StringAdd { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if let ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) = e.node { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref left, + _, + ) = e.node + { if is_string(cx, left) { if !is_allowed(cx, STRING_ADD_ASSIGN, e.id) { let parent = get_parent_expr(cx, e); @@ -132,13 +139,15 @@ fn is_string(cx: &LateContext<'_, '_>, e: &Expr) -> bool { fn is_add(cx: &LateContext<'_, '_>, src: &Expr, target: &Expr) -> bool { match src.node { - ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), + ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref left, + _, + ) => SpanlessEq::new(cx).eq_expr(target, left), ExprKind::Block(ref block, _) => { - block.stmts.is_empty() - && block - .expr - .as_ref() - .map_or(false, |expr| is_add(cx, expr, target)) + block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)) }, _ => false, } @@ -162,7 +171,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { if path.ident.name == "as_bytes" { if let ExprKind::Lit(ref lit) = args[0].node { if let LitKind::Str(ref lit_content, _) = lit.node { - if lit_content.as_str().chars().all(|c| c.is_ascii()) && !in_macro(args[0].span) { + let callsite = snippet(cx, args[0].span.source_callsite(), ""); + let expanded = format!("\"{}\"", lit_content.as_str()); + 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(cx, args[0].span, r#""foo""#).replacen("include_str", "include_bytes", 1), + ); + } else if callsite == expanded + && lit_content.as_str().chars().all(|c| c.is_ascii()) + && !in_macro(args[0].span) + { span_lint_and_sugg( cx, STRING_LIT_AS_BYTES, |
