Auto merge of #10483 - samueltardieu:issue-10480, r=llogiq
New lint to detect `&std::path::MAIN_SEPARATOR.to_string()` Fixes #10480 changelog: [`manual_main_separator_str`] new lint
This commit is contained in:
commit
d3c8442d4d
@ -4662,6 +4662,7 @@ Released 2018-09-13
|
||||
[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
|
||||
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
|
||||
[`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
|
||||
[`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str
|
||||
[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
|
||||
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
|
||||
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
||||
|
@ -263,6 +263,7 @@
|
||||
crate::manual_clamp::MANUAL_CLAMP_INFO,
|
||||
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
|
||||
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
|
||||
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
|
||||
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
|
||||
crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
|
||||
crate::manual_retain::MANUAL_RETAIN_INFO,
|
||||
|
@ -180,6 +180,7 @@
|
||||
mod manual_clamp;
|
||||
mod manual_is_ascii_check;
|
||||
mod manual_let_else;
|
||||
mod manual_main_separator_str;
|
||||
mod manual_non_exhaustive;
|
||||
mod manual_rem_euclid;
|
||||
mod manual_retain;
|
||||
@ -936,6 +937,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock));
|
||||
store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
|
||||
store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
|
||||
store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
72
clippy_lints/src/manual_main_separator_str.rs
Normal file
72
clippy_lints/src/manual_main_separator_str.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::*;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for references on `std::path::MAIN_SEPARATOR.to_string()` used
|
||||
/// to build a `&str`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// There exists a `std::path::MAIN_SEPARATOR_STR` which does not require
|
||||
/// an extra memory allocation.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let s: &str = &std::path::MAIN_SEPARATOR.to_string();
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let s: &str = std::path::MAIN_SEPARATOR_STR;
|
||||
/// ```
|
||||
#[clippy::version = "1.70.0"]
|
||||
pub MANUAL_MAIN_SEPARATOR_STR,
|
||||
complexity,
|
||||
"`&std::path::MAIN_SEPARATOR.to_string()` can be replaced by `std::path::MAIN_SEPARATOR_STR`"
|
||||
}
|
||||
|
||||
pub struct ManualMainSeparatorStr {
|
||||
msrv: Msrv,
|
||||
}
|
||||
|
||||
impl ManualMainSeparatorStr {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]);
|
||||
|
||||
impl LateLintPass<'_> for ManualMainSeparatorStr {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) &&
|
||||
let (target, _) = peel_hir_expr_refs(expr) &&
|
||||
is_trait_method(cx, target, sym::ToString) &&
|
||||
let ExprKind::MethodCall(path, receiver, &[], _) = target.kind &&
|
||||
path.ident.name == sym::to_string &&
|
||||
let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind &&
|
||||
let Res::Def(DefKind::Const, receiver_def_id) = path.res &&
|
||||
match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) &&
|
||||
let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() &&
|
||||
ty.is_str()
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_MAIN_SEPARATOR_STR,
|
||||
expr.span,
|
||||
"taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`",
|
||||
"replace with",
|
||||
"std::path::MAIN_SEPARATOR_STR".to_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ macro_rules! msrv_aliases {
|
||||
|
||||
// names may refer to stabilized feature flags or library items
|
||||
msrv_aliases! {
|
||||
1,68,0 { PATH_MAIN_SEPARATOR_STR }
|
||||
1,65,0 { LET_ELSE }
|
||||
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
|
||||
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
|
||||
|
@ -67,6 +67,7 @@
|
||||
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"];
|
||||
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
|
||||
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
|
||||
pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"];
|
||||
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
|
||||
pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
|
||||
pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
|
||||
|
39
tests/ui/manual_main_separator_str.fixed
Normal file
39
tests/ui/manual_main_separator_str.fixed
Normal file
@ -0,0 +1,39 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::manual_main_separator_str)]
|
||||
|
||||
use std::path::MAIN_SEPARATOR;
|
||||
|
||||
fn len(s: &str) -> usize {
|
||||
s.len()
|
||||
}
|
||||
|
||||
struct U<'a> {
|
||||
f: &'a str,
|
||||
g: &'a String,
|
||||
}
|
||||
|
||||
struct V<T> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Should lint
|
||||
let _: &str = std::path::MAIN_SEPARATOR_STR;
|
||||
let _ = len(std::path::MAIN_SEPARATOR_STR);
|
||||
let _: Vec<u16> = std::path::MAIN_SEPARATOR_STR.encode_utf16().collect();
|
||||
|
||||
// Should lint for field `f` only
|
||||
let _ = U {
|
||||
f: std::path::MAIN_SEPARATOR_STR,
|
||||
g: &MAIN_SEPARATOR.to_string(),
|
||||
};
|
||||
|
||||
// Should not lint
|
||||
let _: &String = &MAIN_SEPARATOR.to_string();
|
||||
let _ = &MAIN_SEPARATOR.to_string();
|
||||
let _ = V {
|
||||
f: &MAIN_SEPARATOR.to_string(),
|
||||
};
|
||||
}
|
39
tests/ui/manual_main_separator_str.rs
Normal file
39
tests/ui/manual_main_separator_str.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::manual_main_separator_str)]
|
||||
|
||||
use std::path::MAIN_SEPARATOR;
|
||||
|
||||
fn len(s: &str) -> usize {
|
||||
s.len()
|
||||
}
|
||||
|
||||
struct U<'a> {
|
||||
f: &'a str,
|
||||
g: &'a String,
|
||||
}
|
||||
|
||||
struct V<T> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Should lint
|
||||
let _: &str = &MAIN_SEPARATOR.to_string();
|
||||
let _ = len(&MAIN_SEPARATOR.to_string());
|
||||
let _: Vec<u16> = MAIN_SEPARATOR.to_string().encode_utf16().collect();
|
||||
|
||||
// Should lint for field `f` only
|
||||
let _ = U {
|
||||
f: &MAIN_SEPARATOR.to_string(),
|
||||
g: &MAIN_SEPARATOR.to_string(),
|
||||
};
|
||||
|
||||
// Should not lint
|
||||
let _: &String = &MAIN_SEPARATOR.to_string();
|
||||
let _ = &MAIN_SEPARATOR.to_string();
|
||||
let _ = V {
|
||||
f: &MAIN_SEPARATOR.to_string(),
|
||||
};
|
||||
}
|
28
tests/ui/manual_main_separator_str.stderr
Normal file
28
tests/ui/manual_main_separator_str.stderr
Normal file
@ -0,0 +1,28 @@
|
||||
error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
|
||||
--> $DIR/manual_main_separator_str.rs:23:19
|
||||
|
|
||||
LL | let _: &str = &MAIN_SEPARATOR.to_string();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
|
||||
|
|
||||
= note: `-D clippy::manual-main-separator-str` implied by `-D warnings`
|
||||
|
||||
error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
|
||||
--> $DIR/manual_main_separator_str.rs:24:17
|
||||
|
|
||||
LL | let _ = len(&MAIN_SEPARATOR.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
|
||||
|
||||
error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
|
||||
--> $DIR/manual_main_separator_str.rs:25:23
|
||||
|
|
||||
LL | let _: Vec<u16> = MAIN_SEPARATOR.to_string().encode_utf16().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
|
||||
|
||||
error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
|
||||
--> $DIR/manual_main_separator_str.rs:29:12
|
||||
|
|
||||
LL | f: &MAIN_SEPARATOR.to_string(),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user