Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c209fc9

Browse files
committed
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 rust-lang#3205
1 parent 457e7f1 commit c209fc9

File tree

3 files changed

+36
-23
lines changed

3 files changed

+36
-23
lines changed

clippy_lints/src/strings.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,14 @@ impl LintPass for StringAdd {
9292

9393
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd {
9494
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
95-
if let ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) = e.node {
95+
if let ExprKind::Binary(
96+
Spanned {
97+
node: BinOpKind::Add, ..
98+
},
99+
ref left,
100+
_,
101+
) = e.node
102+
{
96103
if is_string(cx, left) {
97104
if !is_allowed(cx, STRING_ADD_ASSIGN, e.id) {
98105
let parent = get_parent_expr(cx, e);
@@ -132,13 +139,15 @@ fn is_string(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
132139

133140
fn is_add(cx: &LateContext<'_, '_>, src: &Expr, target: &Expr) -> bool {
134141
match src.node {
135-
ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
142+
ExprKind::Binary(
143+
Spanned {
144+
node: BinOpKind::Add, ..
145+
},
146+
ref left,
147+
_,
148+
) => SpanlessEq::new(cx).eq_expr(target, left),
136149
ExprKind::Block(ref block, _) => {
137-
block.stmts.is_empty()
138-
&& block
139-
.expr
140-
.as_ref()
141-
.map_or(false, |expr| is_add(cx, expr, target))
150+
block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
142151
},
143152
_ => false,
144153
}
@@ -162,7 +171,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
162171
if path.ident.name == "as_bytes" {
163172
if let ExprKind::Lit(ref lit) = args[0].node {
164173
if let LitKind::Str(ref lit_content, _) = lit.node {
165-
if lit_content.as_str().chars().all(|c| c.is_ascii()) && !in_macro(args[0].span) {
174+
let callsite = snippet(cx, args[0].span.source_callsite(), "");
175+
let expanded = format!("\"{}\"", lit_content.as_str());
176+
if callsite.starts_with("include_str!") {
177+
span_lint_and_sugg(
178+
cx,
179+
STRING_LIT_AS_BYTES,
180+
e.span,
181+
"calling `as_bytes()` on `include_str!(..)`",
182+
"consider using `include_bytes!(..)` instead",
183+
snippet(cx, args[0].span, r#""foo""#).replacen("include_str", "include_bytes", 1),
184+
);
185+
} else if callsite == expanded
186+
&& lit_content.as_str().chars().all(|c| c.is_ascii())
187+
&& !in_macro(args[0].span)
188+
{
166189
span_lint_and_sugg(
167190
cx,
168191
STRING_LIT_AS_BYTES,

tests/ui/strings.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111

1212

13-
1413
#[warn(clippy::string_add)]
1514
#[allow(clippy::string_add_assign)]
16-
fn add_only() { // ignores assignment distinction
15+
fn add_only() {
16+
// ignores assignment distinction
1717
let mut x = "".to_owned();
1818

1919
for _ in 1..3 {
@@ -63,6 +63,8 @@ fn str_lit_as_bytes() {
6363
let ubs = "☃".as_bytes();
6464

6565
let strify = stringify!(foobar).as_bytes();
66+
67+
let includestr = include_str!("entry.rs").as_bytes();
6668
}
6769

6870
fn main() {
@@ -72,6 +74,6 @@ fn main() {
7274

7375
// the add is only caught for `String`
7476
let mut x = 1;
75-
; x = x + 1;
77+
; x = x + 1;
7678
assert_eq!(2, x);
7779
}

tests/ui/strings.stderr

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,5 @@ error: calling `as_bytes()` on a string literal
6060
|
6161
= note: `-D clippy::string-lit-as-bytes` implied by `-D warnings`
6262

63-
error: calling `as_bytes()` on a string literal
64-
--> $DIR/strings.rs:65:18
65-
|
66-
65 | let strify = stringify!(foobar).as_bytes();
67-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `bstringify!(foobar)`
68-
69-
error: manual implementation of an assign operation
70-
--> $DIR/strings.rs:75:7
71-
|
72-
75 | ; x = x + 1;
73-
| ^^^^^^^^^ help: replace it with: `x += 1`
74-
7563
error: aborting due to 11 previous errors
7664

0 commit comments

Comments
 (0)