@@ -49,6 +49,7 @@ mod iter_skip_next;
49
49
mod iter_skip_zero;
50
50
mod iter_with_drain;
51
51
mod iterator_step_by_zero;
52
+ mod join_absolute_paths;
52
53
mod manual_next_back;
53
54
mod manual_ok_or;
54
55
mod manual_saturating_arithmetic;
@@ -3684,6 +3685,46 @@ declare_clippy_lint! {
3684
3685
"calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented"
3685
3686
}
3686
3687
3688
+ declare_clippy_lint ! {
3689
+ /// ### What it does
3690
+ /// Checks for calls to `Path::join` that start with a path separator (`\\` or `/`).
3691
+ ///
3692
+ /// ### Why is this bad?
3693
+ /// If the argument to `Path::join` starts with a separator, it will overwrite
3694
+ /// the original path. If this is intentional, prefer using `Path::new` instead.
3695
+ ///
3696
+ /// Note the behavior is platform dependent. A leading `\\` will be accepted
3697
+ /// on unix systems as part of the file name
3698
+ ///
3699
+ /// See [`Path::join`](https://doc.rust-lang.org/std/path/struct.Path.html#method.join)
3700
+ ///
3701
+ /// ### Example
3702
+ /// ```rust
3703
+ /// # use std::path::{Path, PathBuf};
3704
+ /// let path = Path::new("/bin");
3705
+ /// let joined_path = path.join("/sh");
3706
+ /// assert_eq!(joined_path, PathBuf::from("/sh"));
3707
+ /// ```
3708
+ ///
3709
+ /// Use instead;
3710
+ /// ```rust
3711
+ /// # use std::path::{Path, PathBuf};
3712
+ /// let path = Path::new("/bin");
3713
+ ///
3714
+ /// // If this was unintentional, remove the leading separator
3715
+ /// let joined_path = path.join("sh");
3716
+ /// assert_eq!(joined_path, PathBuf::from("/bin/sh"));
3717
+ ///
3718
+ /// // If this was intentional, create a new path instead
3719
+ /// let new = Path::new("/sh");
3720
+ /// assert_eq!(new, PathBuf::from("/sh"));
3721
+ /// ```
3722
+ #[ clippy:: version = "1.75.0" ]
3723
+ pub JOIN_ABSOLUTE_PATHS ,
3724
+ suspicious,
3725
+ "calls to `Path::join` which will overwrite the original path"
3726
+ }
3727
+
3687
3728
pub struct Methods {
3688
3729
avoid_breaking_exported_api : bool ,
3689
3730
msrv : Msrv ,
@@ -3833,6 +3874,7 @@ impl_lint_pass!(Methods => [
3833
3874
REDUNDANT_AS_STR ,
3834
3875
WAKER_CLONE_WAKE ,
3835
3876
UNNECESSARY_FALLIBLE_CONVERSIONS ,
3877
+ JOIN_ABSOLUTE_PATHS ,
3836
3878
] ) ;
3837
3879
3838
3880
/// Extracts a method call name, args, and `Span` of the method name.
@@ -4235,6 +4277,8 @@ impl Methods {
4235
4277
( "join" , [ join_arg] ) => {
4236
4278
if let Some ( ( "collect" , _, _, span, _) ) = method_call ( recv) {
4237
4279
unnecessary_join:: check ( cx, expr, recv, join_arg, span) ;
4280
+ } else {
4281
+ join_absolute_paths:: check ( cx, recv, join_arg, expr. span ) ;
4238
4282
}
4239
4283
} ,
4240
4284
( "last" , [ ] ) => {
0 commit comments