about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-25 13:02:52 +0000
committerbors <bors@rust-lang.org>2023-04-25 13:02:52 +0000
commitabd2c1e8e43f16249a6eebd0e666461ee11d89fa (patch)
tree62699f9b8b0ae27937cd83d3748112b15c74db86
parentc4f2c48d9bed4146b1b317e17854f1cefcaf0f42 (diff)
parent14a6fa4a34d24ec81fe562b71966471efcbb32b2 (diff)
downloadrust-abd2c1e8e43f16249a6eebd0e666461ee11d89fa.tar.gz
rust-abd2c1e8e43f16249a6eebd0e666461ee11d89fa.zip
Auto merge of #10665 - Centri3:string_lit_as_bytes_changes, r=giraffate
Don't apply `string_lit_as_bytes` if in macro expansion

The following code will emit a warning on both w! and h!, despite there being nothing the user (or library author) could do about it:
```rust
#![warn(clippy::string_lit_as_bytes)]

use windows::w;
use windows::h;

fn main() {
    let _w = w!("example");
    let _h = h!("example");
}
```
This is because windows-rs will create a binding `const INPUT: &[u8] = $s.as_bytes()`, and changing this to b"$s" is, well, suboptimal. I don't know enough about Rust to know if this is something that can be detected though if it can be I'm happy with closing this in favor of implementing that.

I'm not sure whether this is how it should be done though, as this simply tells clippy to not invoke this even if it's applicable (this also affects the other string lints, but didn't cause any tests to fail).

changelog: [`string_lit_as_bytes`]: Don't lint if in external macro
-rw-r--r--clippy_lints/src/strings.rs1
-rw-r--r--tests/ui/auxiliary/macro_rules.rs7
-rw-r--r--tests/ui/string_lit_as_bytes.fixed14
-rw-r--r--tests/ui/string_lit_as_bytes.rs14
-rw-r--r--tests/ui/string_lit_as_bytes.stderr25
5 files changed, 54 insertions, 7 deletions
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index b2f4b310915..5b588e914fd 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -292,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
+            if !in_external_macro(cx.sess(), e.span);
             if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
             if path.ident.name == sym!(as_bytes);
             if let ExprKind::Lit(lit) = &receiver.kind;
diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs
index a9bb61451dc..e5bb906663c 100644
--- a/tests/ui/auxiliary/macro_rules.rs
+++ b/tests/ui/auxiliary/macro_rules.rs
@@ -22,6 +22,13 @@ macro_rules! string_add {
 }
 
 #[macro_export]
+macro_rules! string_lit_as_bytes {
+    ($s:literal) => {
+        const C: &[u8] = $s.as_bytes();
+    };
+}
+
+#[macro_export]
 macro_rules! mut_mut {
     () => {
         let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;
diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed
index 058f2aa54da..3fc11b8b088 100644
--- a/tests/ui/string_lit_as_bytes.fixed
+++ b/tests/ui/string_lit_as_bytes.fixed
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = b"warning";
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = b"hello there";
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = b"lit to string".to_vec();
     let bs = b"lit to owned".to_vec();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs
index b550bea001f..7d54acf630e 100644
--- a/tests/ui/string_lit_as_bytes.rs
+++ b/tests/ui/string_lit_as_bytes.rs
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = $b.as_bytes();
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = "hello there".as_bytes();
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = "lit to string".to_string().into_bytes();
     let bs = "lit to owned".to_owned().into_bytes();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/tests/ui/string_lit_as_bytes.stderr b/tests/ui/string_lit_as_bytes.stderr
index f47d6161c6c..61b4e210e0f 100644
--- a/tests/ui/string_lit_as_bytes.stderr
+++ b/tests/ui/string_lit_as_bytes.stderr
@@ -1,5 +1,5 @@
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:7:14
+  --> $DIR/string_lit_as_bytes.rs:17:14
    |
 LL |     let bs = "hello there".as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"`
@@ -7,34 +7,45 @@ LL |     let bs = "hello there".as_bytes();
    = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:9:14
+  --> $DIR/string_lit_as_bytes.rs:19:14
    |
 LL |     let bs = r###"raw string with 3# plus " ""###.as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:11:14
+  --> $DIR/string_lit_as_bytes.rs:21:14
    |
 LL |     let bs = "lit to string".to_string().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:12:14
+  --> $DIR/string_lit_as_bytes.rs:22:14
    |
 LL |     let bs = "lit to owned".to_owned().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()`
 
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:12:26
+   |
+LL |         const B: &[u8] = $b.as_bytes();
+   |                          ^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"warning"`
+...
+LL |     b!("warning");
+   |     ------------- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: calling `as_bytes()` on `include_str!(..)`
-  --> $DIR/string_lit_as_bytes.rs:25:22
+  --> $DIR/string_lit_as_bytes.rs:39:22
    |
 LL |     let includestr = include_str!("string_lit_as_bytes.rs").as_bytes();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:27:13
+  --> $DIR/string_lit_as_bytes.rs:41: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 6 previous errors
+error: aborting due to 7 previous errors