From 4596d618c54b12fdc837a312776bd684f3968c2f Mon Sep 17 00:00:00 2001 From: pwygab Date: Thu, 19 Jan 2023 10:49:25 +0800 Subject: [PATCH 1/7] add lint paths_from_format --- CHANGELOG.md | 1 + clippy_dev/src/update_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/paths_from_format.rs | 124 ++++++++++++++++++++++++++ tests/ui/paths_from_format.rs | 19 ++++ tests/ui/paths_from_format.stderr | 102 +++++++++++++++++++++ 6 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/paths_from_format.rs create mode 100644 tests/ui/paths_from_format.rs create mode 100644 tests/ui/paths_from_format.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index d3cb880df57b..1b4fa67722b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4656,6 +4656,7 @@ Released 2018-09-13 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite +[`paths_from_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#paths_from_format [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 837618c9294b..693d7bf19033 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -397,7 +397,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) { let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{name}`"); return; }; let mod_path = { - let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); + let mut mod_path = Path::new("clippy_lints").join("src").join(&lint.module); if mod_path.is_dir() { mod_path = mod_path.join("mod"); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5c4b60410441..67d166467b6d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -235,6 +235,7 @@ mod partial_pub_fields; mod partialeq_ne_impl; mod partialeq_to_none; mod pass_by_ref_or_value; +mod paths_from_format; mod pattern_type_mismatch; mod permissions_set_readonly_false; mod precedence; @@ -910,6 +911,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock)); + store.register_late_pass(|_| Box::new(paths_from_format::PathsFromFormat)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/paths_from_format.rs b/clippy_lints/src/paths_from_format.rs new file mode 100644 index 000000000000..c33680f96c61 --- /dev/null +++ b/clippy_lints/src/paths_from_format.rs @@ -0,0 +1,124 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::{root_macro_call, FormatArgsExpn}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; +use std::fmt::Write as _; +use std::path::Path; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `PathBuf::from(format!(..))` calls. + /// + /// ### Why is this bad? + /// It is not OS-agnostic, and can be harder to read. + /// + /// ### Known Problems + /// `.join()` introduces additional allocations that are not present when `PathBuf::push` is + /// used instead. + /// + /// ### Example + /// ```rust + /// use std::path::PathBuf; + /// let base_path = "/base"; + /// PathBuf::from(format!("{}/foo/bar", base_path)); + /// ``` + /// Use instead: + /// ```rust + /// use std::path::Path; + /// let base_path = "/base"; + /// Path::new(&base_path).join("foo").join("bar"); + /// ``` + #[clippy::version = "1.62.0"] + pub PATHS_FROM_FORMAT, + pedantic, + "builds a `PathBuf` from a format macro" +} + +declare_lint_pass!(PathsFromFormat => [PATHS_FROM_FORMAT]); + +impl<'tcx> LateLintPass<'tcx> for PathsFromFormat { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + if let ExprKind::Call(_, args) = expr.kind; + if let ty = cx.typeck_results().expr_ty(expr); + if is_type_diagnostic_item(cx, ty, sym::PathBuf); + if !args.is_empty(); + if let Some(macro_call) = root_macro_call(args[0].span); + if cx.tcx.item_name(macro_call.def_id) == sym::format; + if let Some(format_args) = FormatArgsExpn::find_nested(cx, &args[0], macro_call.expn); + then { + let format_string_parts = format_args.format_string.parts; + let format_value_args = format_args.args; + let string_parts: Vec<&str> = format_string_parts.iter().map(rustc_span::Symbol::as_str).collect(); + let mut applicability = Applicability::MachineApplicable; + let real_vars: Vec> = format_value_args.iter().map(|x| Sugg::hir_with_applicability(cx, x.param.value, "..", &mut applicability)).collect(); + let mut paths_zip = string_parts.iter().take(real_vars.len()).zip(real_vars.clone()); + let mut sugg = String::new(); + if let Some((part, arg)) = paths_zip.next() { + if is_valid_use_case(string_parts.first().unwrap_or(&""), string_parts.get(1).unwrap_or(&"")) { + return; + } + if part.is_empty() { + sugg = format!("Path::new(&{arg})"); + } + else { + push_comps(&mut sugg, part); + let _ = write!(sugg, ".join(&{arg})"); + } + } + for n in 1..real_vars.len() { + if let Some((part, arg)) = paths_zip.next() { + if is_valid_use_case(string_parts.get(n).unwrap_or(&""), string_parts.get(n+1).unwrap_or(&"")) { + return; + } + else if n < real_vars.len() { + push_comps(&mut sugg, part); + let _ = write!(sugg, ".join(&{arg})"); + } + else { + sugg = format!("{sugg}.join(&{arg})"); + } + } + } + if real_vars.len() < string_parts.len() { + push_comps(&mut sugg, string_parts[real_vars.len()]); + } + span_lint_and_sugg( + cx, + PATHS_FROM_FORMAT, + expr.span, + "`format!(..)` used to form `PathBuf`", + "consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability", + sugg, + Applicability::MaybeIncorrect, + ); + } + } + } +} + +fn push_comps(string: &mut String, path: &str) { + let mut path = path.to_string(); + if !string.is_empty() { + path = path.trim_start_matches(|c| c == '\\' || c == '/').to_string(); + } + for n in Path::new(&path).components() { + let mut x = n.as_os_str().to_string_lossy().to_string(); + if string.is_empty() { + let _ = write!(string, "Path::new(\"{x}\")"); + } else { + x = x.trim_end_matches(|c| c == '/' || c == '\\').to_string(); + let _ = write!(string, ".join(\"{x}\")"); + } + } +} + +fn is_valid_use_case(string: &str, string2: &str) -> bool { + !(string.is_empty() || string.ends_with('/') || string.ends_with('\\')) + || !(string2.is_empty() || string2.starts_with('/') || string2.starts_with('\\')) +} diff --git a/tests/ui/paths_from_format.rs b/tests/ui/paths_from_format.rs new file mode 100644 index 000000000000..718d63c64c08 --- /dev/null +++ b/tests/ui/paths_from_format.rs @@ -0,0 +1,19 @@ +#![warn(clippy::paths_from_format)] + +use std::path::PathBuf; + +fn main() { + let mut base_path1 = ""; + let mut base_path2 = ""; + PathBuf::from(format!("{base_path1}/foo/bar")); + PathBuf::from(format!("/foo/bar/{base_path1}")); + PathBuf::from(format!("/foo/{base_path1}/bar")); + PathBuf::from(format!("foo/{base_path1}/bar")); + PathBuf::from(format!("foo/foooo/{base_path1}/bar/barrr")); + PathBuf::from(format!("foo/foooo/{base_path1}/bar/barrr/{base_path2}")); + PathBuf::from(format!("{base_path2}/foo/{base_path1}/bar")); + PathBuf::from(format!("foo/{base_path1}a/bar")); + PathBuf::from(format!("foo/a{base_path1}/bar")); + PathBuf::from(format!(r"C:\{base_path2}\foo\{base_path1}\bar")); + PathBuf::from(format!("C:\\{base_path2}\\foo\\{base_path1}\\bar")); +} diff --git a/tests/ui/paths_from_format.stderr b/tests/ui/paths_from_format.stderr new file mode 100644 index 000000000000..2754d87b435b --- /dev/null +++ b/tests/ui/paths_from_format.stderr @@ -0,0 +1,102 @@ +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:8:5 + | +LL | PathBuf::from(format!("{base_path1}/foo/bar")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::paths-from-format` implied by `-D warnings` +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new(&base_path1).join("foo").join("bar"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:9:5 + | +LL | PathBuf::from(format!("/foo/bar/{base_path1}")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new("/").join("foo").join("bar").join(&base_path1); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:10:5 + | +LL | PathBuf::from(format!("/foo/{base_path1}/bar")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new("/").join("foo").join(&base_path1).join("bar"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:11:5 + | +LL | PathBuf::from(format!("foo/{base_path1}/bar")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new("foo").join(&base_path1).join("bar"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:12:5 + | +LL | PathBuf::from(format!("foo/foooo/{base_path1}/bar/barrr")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new("foo").join("foooo").join(&base_path1).join("bar").join("barrr"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:13:5 + | +LL | PathBuf::from(format!("foo/foooo/{base_path1}/bar/barrr/{base_path2}")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new("foo").join("foooo").join(&base_path1).join("bar").join("barrr").join(&base_path2); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:14:5 + | +LL | PathBuf::from(format!("{base_path2}/foo/{base_path1}/bar")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new(&base_path2).join("foo").join(&base_path1).join("bar"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:17:5 + | +LL | PathBuf::from(format!(r"C:/{base_path2}/foo/{base_path1}/bar")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new("C:/").join(&base_path2).join("foo").join(&base_path1).join("bar"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `format!(..)` used to form `PathBuf` + --> $DIR/paths_from_format.rs:18:5 + | +LL | PathBuf::from(format!("C:/{base_path2}/foo/{base_path1}/bar")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `Path::new()` and `.join()` to make it OS-agnostic and improve code readability + | +LL | Path::new("C:/").join(&base_path2).join("foo").join(&base_path1).join("bar"); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 9 previous errors + From 6c2f56fd947a5a0eef3dbd89cca6e20e5a4233e9 Mon Sep 17 00:00:00 2001 From: pwygab Date: Fri, 20 Jan 2023 21:30:49 +0800 Subject: [PATCH 2/7] formatting, [args,..] and registering the lint --- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/paths_from_format.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 36a366fc9747..20ea5f12f159 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -495,6 +495,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO, crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO, crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO, + crate::paths_from_format::PATHS_FROM_FORMAT_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, crate::precedence::PRECEDENCE_INFO, diff --git a/clippy_lints/src/paths_from_format.rs b/clippy_lints/src/paths_from_format.rs index c33680f96c61..a006ad46410e 100644 --- a/clippy_lints/src/paths_from_format.rs +++ b/clippy_lints/src/paths_from_format.rs @@ -44,7 +44,7 @@ declare_lint_pass!(PathsFromFormat => [PATHS_FROM_FORMAT]); impl<'tcx> LateLintPass<'tcx> for PathsFromFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(_, args) = expr.kind; + if let ExprKind::Call(_, [args, ..]) = expr.kind; if let ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, ty, sym::PathBuf); if !args.is_empty(); @@ -54,9 +54,15 @@ impl<'tcx> LateLintPass<'tcx> for PathsFromFormat { then { let format_string_parts = format_args.format_string.parts; let format_value_args = format_args.args; - let string_parts: Vec<&str> = format_string_parts.iter().map(rustc_span::Symbol::as_str).collect(); + let string_parts: Vec<&str> = format_string_parts + .iter() + .map(rustc_span::Symbol::as_str) + .collect(); let mut applicability = Applicability::MachineApplicable; - let real_vars: Vec> = format_value_args.iter().map(|x| Sugg::hir_with_applicability(cx, x.param.value, "..", &mut applicability)).collect(); + let real_vars: Vec> = format_value_args + .iter() + .map(|x| Sugg::hir_with_applicability(cx, x.param.value, "..", &mut applicability)) + .collect(); let mut paths_zip = string_parts.iter().take(real_vars.len()).zip(real_vars.clone()); let mut sugg = String::new(); if let Some((part, arg)) = paths_zip.next() { From 5a6ca6bd839cc8cbe40854fc5245ee1756a347f6 Mon Sep 17 00:00:00 2001 From: pwygab Date: Fri, 20 Jan 2023 21:34:54 +0800 Subject: [PATCH 3/7] docs for valid use --- clippy_lints/src/paths_from_format.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clippy_lints/src/paths_from_format.rs b/clippy_lints/src/paths_from_format.rs index a006ad46410e..6d742ffc6e1f 100644 --- a/clippy_lints/src/paths_from_format.rs +++ b/clippy_lints/src/paths_from_format.rs @@ -124,6 +124,8 @@ fn push_comps(string: &mut String, path: &str) { } } +// In essence, this checks if the format!() used is made for concatenation of the filenames / folder names itself. +// This returns true when it is something like `PathBuf::from(format!("/x/folder{}/textfile.txt", folder_number)) fn is_valid_use_case(string: &str, string2: &str) -> bool { !(string.is_empty() || string.ends_with('/') || string.ends_with('\\')) || !(string2.is_empty() || string2.starts_with('/') || string2.starts_with('\\')) From 47e4a4558c573d9eca9a8dc87d41e83dcf012b43 Mon Sep 17 00:00:00 2001 From: pwygab Date: Sat, 21 Jan 2023 10:57:00 +0800 Subject: [PATCH 4/7] fix minor issue regarding `args`/`arg` --- clippy_lints/src/paths_from_format.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/paths_from_format.rs b/clippy_lints/src/paths_from_format.rs index 6d742ffc6e1f..ea2434b96ba1 100644 --- a/clippy_lints/src/paths_from_format.rs +++ b/clippy_lints/src/paths_from_format.rs @@ -44,13 +44,12 @@ declare_lint_pass!(PathsFromFormat => [PATHS_FROM_FORMAT]); impl<'tcx> LateLintPass<'tcx> for PathsFromFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(_, [args, ..]) = expr.kind; + if let ExprKind::Call(_, [arg, ..]) = expr.kind; if let ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, ty, sym::PathBuf); - if !args.is_empty(); - if let Some(macro_call) = root_macro_call(args[0].span); + if let Some(macro_call) = root_macro_call(arg.span); if cx.tcx.item_name(macro_call.def_id) == sym::format; - if let Some(format_args) = FormatArgsExpn::find_nested(cx, &args[0], macro_call.expn); + if let Some(format_args) = FormatArgsExpn::find_nested(cx, &arg, macro_call.expn); then { let format_string_parts = format_args.format_string.parts; let format_value_args = format_args.args; From 798035014b62f8c6b5e670b63d08e3fed60df0db Mon Sep 17 00:00:00 2001 From: pwygab Date: Sat, 21 Jan 2023 10:59:26 +0800 Subject: [PATCH 5/7] cargo dev update_lints --- README.md | 2 +- book/src/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab44db694835..95f6d2cc45c8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/book/src/README.md b/book/src/README.md index 23867df8efe1..df4a1f2702e4 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how From 1a35d49b0c486d1708c09c8f6496a34731bf84a7 Mon Sep 17 00:00:00 2001 From: pwygab Date: Sat, 21 Jan 2023 11:02:14 +0800 Subject: [PATCH 6/7] cargo fmt --- clippy_lints/src/paths_from_format.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/paths_from_format.rs b/clippy_lints/src/paths_from_format.rs index ea2434b96ba1..6d4130b28bae 100644 --- a/clippy_lints/src/paths_from_format.rs +++ b/clippy_lints/src/paths_from_format.rs @@ -123,8 +123,9 @@ fn push_comps(string: &mut String, path: &str) { } } -// In essence, this checks if the format!() used is made for concatenation of the filenames / folder names itself. -// This returns true when it is something like `PathBuf::from(format!("/x/folder{}/textfile.txt", folder_number)) +// In essence, this checks if the format!() used is made for concatenation of the filenames / folder +// names itself. This returns true when it is something like +// `PathBuf::from(format!("/x/folder{}/textfile.txt", folder_number))` fn is_valid_use_case(string: &str, string2: &str) -> bool { !(string.is_empty() || string.ends_with('/') || string.ends_with('\\')) || !(string2.is_empty() || string2.starts_with('/') || string2.starts_with('\\')) From 29384d7431611df2bba7ec9e2eb3c7f504f086a5 Mon Sep 17 00:00:00 2001 From: pwygab Date: Sat, 21 Jan 2023 11:08:54 +0800 Subject: [PATCH 7/7] dogfood --- clippy_lints/src/paths_from_format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/paths_from_format.rs b/clippy_lints/src/paths_from_format.rs index 6d4130b28bae..07a5a30775f3 100644 --- a/clippy_lints/src/paths_from_format.rs +++ b/clippy_lints/src/paths_from_format.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for PathsFromFormat { if is_type_diagnostic_item(cx, ty, sym::PathBuf); if let Some(macro_call) = root_macro_call(arg.span); if cx.tcx.item_name(macro_call.def_id) == sym::format; - if let Some(format_args) = FormatArgsExpn::find_nested(cx, &arg, macro_call.expn); + if let Some(format_args) = FormatArgsExpn::find_nested(cx, arg, macro_call.expn); then { let format_string_parts = format_args.format_string.parts; let format_value_args = format_args.args;