@@ -49,6 +49,7 @@ mod iter_skip_next;
4949mod iter_skip_zero;
5050mod iter_with_drain;
5151mod iterator_step_by_zero;
52+ mod join_absolute_paths;
5253mod manual_next_back;
5354mod manual_ok_or;
5455mod manual_saturating_arithmetic;
@@ -3682,6 +3683,42 @@ declare_clippy_lint! {
36823683 "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented"
36833684}
36843685
3686+ declare_clippy_lint ! {
3687+ /// Checks for calls to `Path::join` that start with a path separator, like `\\` or `/`..
3688+ ///
3689+ /// ### Why is this bad?
3690+ /// `.join()` arguments starting with a separator (`/` or `\\`) can replace the entire path.
3691+ /// If this is intentional, prefer using `Path::new()` instead.
3692+ ///
3693+ /// See [`Path::join()`](https://doc.rust-lang.org/std/path/struct.Path.html#method.join)
3694+ ///
3695+ /// ### Example
3696+ /// ```rust
3697+ /// # use std::path::{Path, PathBuf};
3698+ /// let path = Path::new("/bin");
3699+ /// let joined_path = path.join("/sh");
3700+ /// assert_eq!(joined_path, PathBuf::from("/sh"));
3701+ /// ```
3702+ ///
3703+ /// Use instead;
3704+ /// ```rust
3705+ /// # use std::path::{Path, PathBuf};
3706+ /// let path = Path::new("/bin");
3707+ ///
3708+ /// // If this was unintentional, remove the leading separator
3709+ /// let joined_path = path.join("sh");
3710+ /// assert_eq!(joined_path, PathBuf::from("/bin/sh"));
3711+ ///
3712+ /// // If this was intentional, create a new path instead
3713+ /// let new = Path::new("/sh");
3714+ /// assert_eq!(new, PathBuf::from("/sh"));
3715+ /// ```
3716+ #[ clippy:: version = "1.75.0" ]
3717+ pub JOIN_ABSOLUTE_PATHS ,
3718+ correctness,
3719+ "arg to .join called on a `Path` contains leading separator"
3720+ }
3721+
36853722pub struct Methods {
36863723 avoid_breaking_exported_api : bool ,
36873724 msrv : Msrv ,
@@ -3829,6 +3866,7 @@ impl_lint_pass!(Methods => [
38293866 REDUNDANT_AS_STR ,
38303867 WAKER_CLONE_WAKE ,
38313868 UNNECESSARY_FALLIBLE_CONVERSIONS ,
3869+ JOIN_ABSOLUTE_PATHS ,
38323870] ) ;
38333871
38343872/// Extracts a method call name, args, and `Span` of the method name.
@@ -4231,6 +4269,8 @@ impl Methods {
42314269 ( "join" , [ join_arg] ) => {
42324270 if let Some ( ( "collect" , _, _, span, _) ) = method_call ( recv) {
42334271 unnecessary_join:: check ( cx, expr, recv, join_arg, span) ;
4272+ } else {
4273+ join_absolute_paths:: check ( cx, recv, join_arg) ;
42344274 }
42354275 } ,
42364276 ( "last" , [ ] ) => {
0 commit comments