Skip to content

Commit b2fc5ed

Browse files
committed
Add lint PathBufPushOverwrite
1 parent fbb3a47 commit b2fc5ed

File tree

6 files changed

+83
-1
lines changed

6 files changed

+83
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,7 @@ All notable changes to this project will be documented in this file.
10151015
[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
10161016
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
10171017
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
1018+
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
10181019
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
10191020
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
10201021
[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
99

10-
[There are 298 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
10+
[There are 299 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1111

1212
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1313

clippy_lints/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ pub mod open_options;
235235
pub mod overflow_check_conditional;
236236
pub mod panic_unimplemented;
237237
pub mod partialeq_ne_impl;
238+
pub mod path_buf_push_overwrite;
238239
pub mod precedence;
239240
pub mod ptr;
240241
pub mod ptr_offset_with_cast;
@@ -572,6 +573,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
572573
reg.register_late_lint_pass(box assertions_on_constants::AssertionsOnConstants);
573574
reg.register_late_lint_pass(box missing_const_for_fn::MissingConstForFn);
574575
reg.register_late_lint_pass(box transmuting_null::Pass);
576+
reg.register_late_lint_pass(box path_buf_push_overwrite::PathBufPushOverwrite);
575577

576578
reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![
577579
arithmetic::FLOAT_ARITHMETIC,
@@ -806,6 +808,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
806808
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
807809
panic_unimplemented::PANIC_PARAMS,
808810
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
811+
path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
809812
precedence::PRECEDENCE,
810813
ptr::CMP_NULL,
811814
ptr::MUT_FROM_REF,
@@ -936,6 +939,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
936939
non_expressive_names::MANY_SINGLE_CHAR_NAMES,
937940
ok_if_let::IF_LET_SOME_RESULT,
938941
panic_unimplemented::PANIC_PARAMS,
942+
path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
939943
ptr::CMP_NULL,
940944
ptr::PTR_ARG,
941945
question_mark::QUESTION_MARK,
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use crate::utils::{match_type, paths, span_help_and_lint, walk_ptrs_ty};
2+
use if_chain::if_chain;
3+
use rustc::hir::*;
4+
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
5+
use rustc::{declare_lint_pass, declare_tool_lint};
6+
use std::path::Path;
7+
use syntax::ast::LitKind;
8+
9+
declare_clippy_lint! {
10+
/// **What it does:*** Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
11+
/// calls on `PathBuf` that can cause overwrites.
12+
///
13+
/// **Why is this bad?** Calling `push` with a root path at the start can overwrite the
14+
/// previous defined path.
15+
///
16+
/// **Known problems:** None.
17+
///
18+
/// **Example:**
19+
/// ```rust
20+
/// let mut x = PathBuf::from("/foo");
21+
/// x.push("/bar");
22+
/// assert!(x.display(), "/bar")
23+
/// ```
24+
/// Could be written:
25+
///
26+
/// ```rust
27+
/// let mut x = PathBuf::from("/foo");
28+
/// x.push("bar");
29+
/// assert!(x.display(), "/foo/bar");
30+
/// ```
31+
pub PATH_BUF_PUSH_OVERWRITE,
32+
correctness,
33+
"calling `push` with file system root on `PathBuf` can overwrite it"
34+
}
35+
36+
declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]);
37+
38+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathBufPushOverwrite {
39+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
40+
if_chain! {
41+
if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
42+
if path.ident.name == "push";
43+
if args.len() == 2;
44+
if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::PATH_BUF);
45+
if let Some(get_index_arg) = args.get(1);
46+
if let ExprKind::Lit(ref lit) = get_index_arg.node;
47+
if let LitKind::Str(ref r, _) = lit.node;
48+
if Path::new(&r.as_str()).has_root();
49+
then {
50+
span_help_and_lint(
51+
cx,
52+
PATH_BUF_PUSH_OVERWRITE,
53+
expr.span,
54+
"Calling `push` with '/' (file system root) can overwrite the previous path definition",
55+
"Remove the '/' (file system root) from the start of the path instead"
56+
);
57+
}
58+
}
59+
}
60+
}

tests/ui/path_buf_push_overwrite.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use std::path::PathBuf;
2+
3+
fn main() {
4+
let mut x = PathBuf::from("/foo");
5+
x.push("/bar");
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: Calling `push` with '/' (file system root) can overwrite the previous path definition
2+
--> $DIR/path_buf_push_overwrite.rs:5:5
3+
|
4+
LL | x.push("/bar");
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: #[deny(clippy::path_buf_push_overwrite)] on by default
8+
= help: Remove the '/' (file system root) from the start of the path instead
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)