Skip to content

Commit 36ec166

Browse files
committed
second suggestion
1 parent e897196 commit 36ec166

File tree

3 files changed

+60
-42
lines changed

3 files changed

+60
-42
lines changed

clippy_lints/src/path_from_format.rs

+37-40
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::snippet;
1+
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_help};
2+
use clippy_utils::source::snippet_with_applicability;
33
use clippy_utils::ty::is_type_diagnostic_item;
44
use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
55
use rustc_errors::Applicability;
66
use rustc_hir::{Expr, ExprKind};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_session::{declare_lint_pass, declare_tool_lint};
99
use rustc_span::sym;
10-
use std::fmt::Write as _;
1110

1211
declare_clippy_lint! {
1312
/// ### What it does
@@ -46,55 +45,53 @@ impl<'tcx> LateLintPass<'tcx> for PathFromFormat {
4645
if let Some(macro_call) = root_macro_call(args[0].span);
4746
if cx.tcx.item_name(macro_call.def_id) == sym::format;
4847
if let Some(format_args) = FormatArgsExpn::find_nested(cx, &args[0], macro_call.expn);
48+
let mut applicability = Applicability::MachineApplicable;
49+
let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
50+
if let Some(end_of_literal) = format_args_snip.find("\",");
4951
then {
50-
let full_expr = snippet(cx, expr.span, "error").to_string();
51-
let split_expr: Vec<&str> = full_expr.split('!').collect();
52-
let args_to_macro = split_expr[1];
53-
let replaced = args_to_macro.replace('(', "").replace(')', "");
54-
let unformatted: Vec<&str> = replaced.split(',').collect();
55-
let mut push_targets: Vec<String> = Vec::new();
56-
let mut temp_string = String::new();
57-
for c in unformatted[0].chars() {
58-
if c == '/' || c == '\\' {
59-
push_targets.push(temp_string.clone());
60-
temp_string = String::new();
61-
}
62-
else if c == '}' {
63-
temp_string.push_str(&unformatted[1].replace(' ', ""));
64-
}
65-
else if c != '{' && c != '"' {
66-
temp_string.push(c);
67-
}
68-
}
69-
if !temp_string.is_empty() {
70-
push_targets.push(temp_string.clone());
71-
temp_string = String::new();
52+
let (literal, vars) = format_args_snip.split_at(end_of_literal);
53+
let mut literal = literal.to_string();
54+
literal.remove(0);
55+
let v: Vec<&str> = literal.split("{}").collect();
56+
let real_vars = vars.strip_prefix("\", ").unwrap_or(vars);
57+
if v.len() != 2 || real_vars.contains(',') {
58+
span_lint_and_help(
59+
cx,
60+
PATH_FROM_FORMAT,
61+
expr.span,
62+
"`format!(..)` used to form `PathBuf`",
63+
None,
64+
"consider using `.join()` to avoid the extra allocation",
65+
);
66+
return;
7267
}
73-
for target in push_targets {
74-
let target_processed =
75-
if target == unformatted[1].replace(' ', "") {
76-
target
68+
let sugg = {
69+
if v[0].is_empty() {
70+
let mut str1 = v[1].to_string();
71+
if str1.starts_with('\\') || str1.starts_with('/') {
72+
str1.remove(0);
7773
}
78-
else {
79-
let mut s = String::from("\"");
80-
s.push_str(&target);
81-
s.push('"');
82-
s
83-
};
84-
if temp_string.is_empty() {
85-
let _ = write!(temp_string, "Path::new({})", target_processed);
74+
format!("Path::new({real_vars}).join(\"{str1}\")")
75+
}
76+
else if v[1].is_empty() {
77+
let str1 = v[0].to_string();
78+
format!("Path::new(\"{str1}\").join({real_vars})")
8679
}
8780
else {
88-
let _ = write!(temp_string, ".join({})", target_processed);
81+
let (str1, mut str2) = (v[0].to_string(), v[1].to_string());
82+
if str2.starts_with('\\') || str2.starts_with('/') {
83+
str2.remove(0);
84+
}
85+
format!("Path::new(\"{str1}\").join({real_vars}).join(\"{str2}\")")
8986
}
90-
}
87+
};
9188
span_lint_and_sugg(
9289
cx,
9390
PATH_FROM_FORMAT,
9491
expr.span,
9592
"`format!(..)` used to form `PathBuf`",
9693
"consider using `.join()` to avoid the extra allocation",
97-
temp_string,
94+
sugg,
9895
Applicability::MaybeIncorrect,
9996
);
10097
}

tests/ui/path_from_format.rs

+3
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ use std::path::PathBuf;
55
fn main() {
66
let mut base_path1 = "";
77
PathBuf::from(format!("{}/foo/bar", base_path1));
8+
PathBuf::from(format!("/foo/bar/{}", base_path1));
9+
PathBuf::from(format!("/foo/{}/bar", base_path1));
10+
PathBuf::from(format!("foo/{}/bar", base_path1));
811
}

tests/ui/path_from_format.stderr

+20-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,27 @@ error: `format!(..)` used to form `PathBuf`
22
--> $DIR/path_from_format.rs:7:5
33
|
44
LL | PathBuf::from(format!("{}/foo/bar", base_path1));
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.join()` to avoid the extra allocation: `Path::new(base_path1).join("foo").join("bar")`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.join()` to avoid the extra allocation: `Path::new(base_path1).join("foo/bar")`
66
|
77
= note: `-D clippy::path-from-format` implied by `-D warnings`
88

9-
error: aborting due to previous error
9+
error: `format!(..)` used to form `PathBuf`
10+
--> $DIR/path_from_format.rs:8:5
11+
|
12+
LL | PathBuf::from(format!("/foo/bar/{}", base_path1));
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.join()` to avoid the extra allocation: `Path::new("/foo/bar/").join(base_path1)`
14+
15+
error: `format!(..)` used to form `PathBuf`
16+
--> $DIR/path_from_format.rs:9:5
17+
|
18+
LL | PathBuf::from(format!("/foo/{}/bar", base_path1));
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.join()` to avoid the extra allocation: `Path::new("/foo/").join(base_path1).join("bar")`
20+
21+
error: `format!(..)` used to form `PathBuf`
22+
--> $DIR/path_from_format.rs:10:5
23+
|
24+
LL | PathBuf::from(format!("foo/{}/bar", base_path1));
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.join()` to avoid the extra allocation: `Path::new("foo/").join(base_path1).join("bar")`
26+
27+
error: aborting due to 4 previous errors
1028

0 commit comments

Comments
 (0)