Skip to content

Commit 6ca627f

Browse files
committed
rebased
1 parent 3cc50a4 commit 6ca627f

File tree

7 files changed

+108
-0
lines changed

7 files changed

+108
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3649,6 +3649,7 @@ Released 2018-09-13
36493649
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
36503650
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
36513651
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
3652+
[`path_from_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_from_format
36523653
[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
36533654
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
36543655
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ store.register_lints(&[
435435
pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
436436
pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
437437
path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
438+
path_from_format::PATH_FROM_FORMAT,
438439
pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
439440
precedence::PRECEDENCE,
440441
ptr::CMP_NULL,

clippy_lints/src/lib.register_pedantic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
7676
LintId::of(non_expressive_names::SIMILAR_NAMES),
7777
LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
7878
LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
79+
LintId::of(path_from_format::PATH_FROM_FORMAT),
7980
LintId::of(ranges::RANGE_MINUS_ONE),
8081
LintId::of(ranges::RANGE_PLUS_ONE),
8182
LintId::of(redundant_else::REDUNDANT_ELSE),

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ mod panic_unimplemented;
339339
mod partialeq_ne_impl;
340340
mod pass_by_ref_or_value;
341341
mod path_buf_push_overwrite;
342+
mod path_from_format;
342343
mod pattern_type_mismatch;
343344
mod precedence;
344345
mod ptr;
@@ -906,6 +907,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
906907
store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
907908
store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
908909
store.register_late_pass(|| Box::new(get_first::GetFirst));
910+
store.register_late_pass(|| Box::new(path_from_format::PathFromFormat));
909911
// add lints here, do not remove this comment, it's used in `new_lint`
910912
}
911913

clippy_lints/src/path_from_format.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use clippy_utils::ty::is_type_diagnostic_item;
3+
use clippy_utils::{match_qpath, paths, peel_hir_expr_refs};
4+
use rustc_hir::{StmtKind,BorrowKind, Mutability, BindingAnnotation, PatKind, Expr, ExprKind};
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
use rustc_span::sym;
8+
9+
declare_clippy_lint! {
10+
/// ### What it does
11+
///
12+
/// ### Why is this bad?
13+
///
14+
/// ### Example
15+
/// ```rust
16+
/// // example code where clippy issues a warning
17+
/// ```
18+
/// Use instead:
19+
/// ```rust
20+
/// // example code which does not raise clippy warning
21+
/// ```
22+
#[clippy::version = "1.62.0"]
23+
pub PATH_FROM_FORMAT,
24+
pedantic,
25+
"default lint description"
26+
}
27+
28+
declare_lint_pass!(PathFromFormat => [PATH_FROM_FORMAT]);
29+
30+
impl<'tcx> LateLintPass<'tcx> for PathFromFormat {
31+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
32+
if_chain! {
33+
if let ExprKind::Call(func, args) = expr.kind;
34+
if let ExprKind::Path(ref qpath) = func.kind;
35+
if match_qpath(qpath, &["PathBuf", "from"]);
36+
// if args.len() == 1;
37+
if let Some(macro_def_id) = args[0].span.ctxt().outer_expn_data().macro_def_id;
38+
if cx.tcx.get_diagnostic_name(macro_def_id) == Some(sym::format_macro);
39+
// if let ExprKind::Block(block, None) = args[0].kind;
40+
// if block.stmts.len() == 1;
41+
// if let StmtKind::Local(local) = block.stmts[0].kind;
42+
// if let Some(init) = local.init;
43+
// if let ExprKind::Call(func1, args1) = init.kind;
44+
// if let ExprKind::Path(ref qpath1) = func1.kind;
45+
// if match_qpath(qpath1, &["$crate", "fmt", "format"]);
46+
// if args1.len() == 1;
47+
// if let ExprKind::Call(func2, args2) = args1[0].kind;
48+
// if let ExprKind::Path(ref qpath2) = func2.kind;
49+
// if match_qpath(qpath2, &["$crate", "fmt", "Arguments", "new_v1"]);
50+
// if args2.len() == 2;
51+
// if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args2[0].kind;
52+
// if let ExprKind::Array(elements) = inner.kind;
53+
// if elements.len() == 2;
54+
// if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[1].kind;
55+
// if let ExprKind::Array(elements1) = inner1.kind;
56+
// if elements1.len() == 1;
57+
// if let ExprKind::Call(func3, args3) = elements1[0].kind;
58+
// if let ExprKind::Path(ref qpath3) = func3.kind;
59+
// if match_qpath(qpath3, &["$crate", "fmt", "ArgumentV1", "new_display"]);
60+
// if args3.len() == 1;
61+
// if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args3[0].kind;
62+
// if let ExprKind::Path(ref qpath4) = inner2.kind;
63+
// if match_qpath(qpath4, &["base_path"]);
64+
// if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
65+
// if name.as_str() == "res";
66+
// if let Some(trailing_expr) = block.expr;
67+
// if let ExprKind::Path(ref qpath5) = trailing_expr.kind;
68+
// if match_qpath(qpath5, &["res"]);
69+
then {
70+
span_lint_and_help(
71+
cx,
72+
PATH_FROM_FORMAT,
73+
expr.span,
74+
"`format!(..)` used to form `PathBuf`",
75+
None,
76+
"consider using `.join()` or `.push()` to avoid the extra allocation",
77+
);
78+
// report your lint here
79+
}
80+
}
81+
}
82+
}

tests/ui/path_from_format.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![warn(clippy::path_from_format)]
2+
3+
use std::path::PathBuf;
4+
5+
fn main() {
6+
// let base_path = "";
7+
// PathBuf::from(format!("{}/foo/bar", base_path));
8+
let mut base_path1 = "";
9+
PathBuf::from(format!("{}/foo/bar", base_path1));
10+
}

tests/ui/path_from_format.stderr

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: `format!(..)` used to form `PathBuf`
2+
--> $DIR/path_from_format.rs:9:5
3+
|
4+
LL | PathBuf::from(format!("{}/foo/bar", base_path1));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::path-from-format` implied by `-D warnings`
8+
= help: consider using `.join()` or `.push()` to avoid the extra allocation
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)