diff --git a/CHANGELOG.md b/CHANGELOG.md index 559b560dde4b..b868f1db606c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4814,6 +4814,7 @@ Released 2018-09-13 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite +[`path_join_correction`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_join_correction [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f24dab627809..c3e51a354aa5 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -376,6 +376,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OR_FUN_CALL_INFO, crate::methods::OR_THEN_UNWRAP_INFO, crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO, + crate::methods::PATH_JOIN_CORRECTION_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c213030f6a8f..4fdc0384f2d4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,3 +1,4 @@ +mod path_join_correction; mod bind_instead_of_map; mod bytecount; mod bytes_count_to_len; @@ -3216,6 +3217,25 @@ declare_clippy_lint! { "calling `drain` in order to `clear` a container" } +declare_clippy_lint! { + /// ### What it does + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + #[clippy::version = "1.70.0"] + pub PATH_JOIN_CORRECTION, + pedantic, + "default lint description" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3345,6 +3365,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, CLEAR_WITH_DRAIN, + PATH_JOIN_CORRECTION, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3655,7 +3676,11 @@ impl Methods { if let Some(("collect", _, _, span, _)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); } + else {path_join_correction::check(cx, expr, join_arg, span);} }, + /*("join", [join_arg]) => { + path_join_correction::check(cx, expr, join_arg, span); + },*/ ("last", []) | ("skip", [_]) => { if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { diff --git a/clippy_lints/src/methods/path_join_correction.rs b/clippy_lints/src/methods/path_join_correction.rs new file mode 100644 index 000000000000..aa2d2a644ff9 --- /dev/null +++ b/clippy_lints/src/methods/path_join_correction.rs @@ -0,0 +1,35 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_lint::{LateContext}; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_span::Span; + +use super::PATH_JOIN_CORRECTION; + +// TODO: Adjust the parameters as necessary + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + join_arg: &'tcx Expr<'tcx>, + span: Span, +) { + let applicability = Applicability::MachineApplicable; + if_chain!( + if let ExprKind::Lit(spanned) = &join_arg.kind; + if let LitKind::Str(symbol, _) = spanned.node; + if symbol.as_str().starts_with('/'); + then { + span_lint_and_sugg( + cx, + PATH_JOIN_CORRECTION, + span.with_hi(expr.span.hi()), + r#"argument in join called on path contains a starting '/'"#, + "try removing first '/'", + "join(\"your/path/here\")".to_owned(), + applicability + ); + } + ); +} diff --git a/tests/ui/path_join_correction.rs b/tests/ui/path_join_correction.rs new file mode 100644 index 000000000000..aaa33b9fb4db --- /dev/null +++ b/tests/ui/path_join_correction.rs @@ -0,0 +1,15 @@ +#![allow(unused)] +#![warn(clippy::path_join_correction)] + +fn main() { + // should be linted + let path = std::path::Path::new("/bin"); + path.join("/sh"); + println!("{}", path.display()); + + //should not be linted + let path = std::path::Path::new("/bin"); + path.join("sh"); + println!("{}", path.display()); + +} diff --git a/tests/ui/path_join_correction.stderr b/tests/ui/path_join_correction.stderr new file mode 100644 index 000000000000..c73dff01e28a --- /dev/null +++ b/tests/ui/path_join_correction.stderr @@ -0,0 +1,10 @@ +error: argument in join called on path contains a starting '/' + --> $DIR/path_join_correction.rs:7:8 + | +LL | path.join("/sh"); + | ^^^^^^^^^^^ help: try removing first '/': `join("your/path/here")` + | + = note: `-D clippy::path-join-correction` implied by `-D warnings` + +error: aborting due to previous error +