mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 23:24:24 +00:00
Move RepeatOnce
into Methods
lint pass
This commit is contained in:
parent
fd5376194a
commit
06d752e28d
7 changed files with 92 additions and 94 deletions
|
@ -197,6 +197,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(methods::OR_FUN_CALL),
|
||||
LintId::of(methods::OR_THEN_UNWRAP),
|
||||
LintId::of(methods::RANGE_ZIP_WITH_LEN),
|
||||
LintId::of(methods::REPEAT_ONCE),
|
||||
LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
|
||||
LintId::of(methods::SEARCH_IS_SOME),
|
||||
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
|
||||
|
@ -287,7 +288,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
||||
LintId::of(reference::DEREF_ADDROF),
|
||||
LintId::of(regex::INVALID_REGEX),
|
||||
LintId::of(repeat_once::REPEAT_ONCE),
|
||||
LintId::of(returns::LET_AND_RETURN),
|
||||
LintId::of(returns::NEEDLESS_RETURN),
|
||||
LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
|
||||
|
|
|
@ -52,6 +52,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
|
|||
LintId::of(methods::OPTION_FILTER_MAP),
|
||||
LintId::of(methods::OR_THEN_UNWRAP),
|
||||
LintId::of(methods::RANGE_ZIP_WITH_LEN),
|
||||
LintId::of(methods::REPEAT_ONCE),
|
||||
LintId::of(methods::SEARCH_IS_SOME),
|
||||
LintId::of(methods::SKIP_WHILE_NEXT),
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
|
@ -80,7 +81,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
|
|||
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
|
||||
LintId::of(redundant_slicing::REDUNDANT_SLICING),
|
||||
LintId::of(reference::DEREF_ADDROF),
|
||||
LintId::of(repeat_once::REPEAT_ONCE),
|
||||
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
|
||||
LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
|
||||
LintId::of(swap::MANUAL_SWAP),
|
||||
|
|
|
@ -346,6 +346,7 @@ store.register_lints(&[
|
|||
methods::OR_THEN_UNWRAP,
|
||||
methods::PATH_BUF_PUSH_OVERWRITE,
|
||||
methods::RANGE_ZIP_WITH_LEN,
|
||||
methods::REPEAT_ONCE,
|
||||
methods::RESULT_MAP_OR_INTO_OPTION,
|
||||
methods::SEARCH_IS_SOME,
|
||||
methods::SHOULD_IMPLEMENT_TRAIT,
|
||||
|
@ -489,7 +490,6 @@ store.register_lints(&[
|
|||
reference::DEREF_ADDROF,
|
||||
regex::INVALID_REGEX,
|
||||
regex::TRIVIAL_REGEX,
|
||||
repeat_once::REPEAT_ONCE,
|
||||
return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
|
||||
returns::LET_AND_RETURN,
|
||||
returns::NEEDLESS_RETURN,
|
||||
|
|
|
@ -343,7 +343,6 @@ mod redundant_static_lifetimes;
|
|||
mod ref_option_ref;
|
||||
mod reference;
|
||||
mod regex;
|
||||
mod repeat_once;
|
||||
mod return_self_not_must_use;
|
||||
mod returns;
|
||||
mod same_name_method;
|
||||
|
@ -824,7 +823,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
|
||||
store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
|
||||
store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive));
|
||||
store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
|
||||
store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
|
||||
store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
|
||||
store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
|
||||
|
|
|
@ -65,6 +65,7 @@ mod or_fun_call;
|
|||
mod or_then_unwrap;
|
||||
mod path_buf_push_overwrite;
|
||||
mod range_zip_with_len;
|
||||
mod repeat_once;
|
||||
mod search_is_some;
|
||||
mod single_char_add_str;
|
||||
mod single_char_insert_string;
|
||||
|
@ -2760,6 +2761,38 @@ declare_clippy_lint! {
|
|||
"zipping iterator with a range when `enumerate()` would do"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `.repeat(1)` and suggest the following method for each types.
|
||||
/// - `.to_string()` for `str`
|
||||
/// - `.clone()` for `String`
|
||||
/// - `.to_vec()` for `slice`
|
||||
///
|
||||
/// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
|
||||
/// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
|
||||
/// the string is the intention behind this, `clone()` should be used.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// let x = String::from("hello world").repeat(1);
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// let x = String::from("hello world").clone();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.47.0"]
|
||||
pub REPEAT_ONCE,
|
||||
complexity,
|
||||
"using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Option<RustcVersion>,
|
||||
|
@ -2875,6 +2908,7 @@ impl_lint_pass!(Methods => [
|
|||
NONSENSICAL_OPEN_OPTIONS,
|
||||
PATH_BUF_PUSH_OVERWRITE,
|
||||
RANGE_ZIP_WITH_LEN,
|
||||
REPEAT_ONCE,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
|
@ -3263,6 +3297,9 @@ impl Methods {
|
|||
("push", [arg]) => {
|
||||
path_buf_push_overwrite::check(cx, expr, arg);
|
||||
},
|
||||
("repeat", [arg]) => {
|
||||
repeat_once::check(cx, expr, recv, arg);
|
||||
},
|
||||
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
|
||||
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
|
||||
suspicious_splitn::check(cx, name, expr, recv, count);
|
||||
|
|
52
clippy_lints/src/methods/repeat_once.rs
Normal file
52
clippy_lints/src/methods/repeat_once.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use clippy_utils::consts::{constant_context, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::REPEAT_ONCE;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
recv: &'tcx Expr<'_>,
|
||||
repeat_arg: &'tcx Expr<'_>,
|
||||
) {
|
||||
if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) {
|
||||
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
if ty.is_str() {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REPEAT_ONCE,
|
||||
expr.span,
|
||||
"calling `repeat(1)` on str",
|
||||
"consider using `.to_string()` instead",
|
||||
format!("{}.to_string()", snippet(cx, recv.span, r#""...""#)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if ty.builtin_index().is_some() {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REPEAT_ONCE,
|
||||
expr.span,
|
||||
"calling `repeat(1)` on slice",
|
||||
"consider using `.to_vec()` instead",
|
||||
format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::String) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REPEAT_ONCE,
|
||||
expr.span,
|
||||
"calling `repeat(1)` on a string literal",
|
||||
"consider using `.clone()` instead",
|
||||
format!("{}.clone()", snippet(cx, recv.span, r#""...""#)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
use clippy_utils::consts::{constant_context, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `.repeat(1)` and suggest the following method for each types.
|
||||
/// - `.to_string()` for `str`
|
||||
/// - `.clone()` for `String`
|
||||
/// - `.to_vec()` for `slice`
|
||||
///
|
||||
/// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
|
||||
/// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
|
||||
/// the string is the intention behind this, `clone()` should be used.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// let x = String::from("hello world").repeat(1);
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// let x = String::from("hello world").clone();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.47.0"]
|
||||
pub REPEAT_ONCE,
|
||||
complexity,
|
||||
"using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
|
||||
}
|
||||
|
||||
declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(path, [receiver, count], _) = &expr.kind;
|
||||
if path.ident.name == sym!(repeat);
|
||||
if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1));
|
||||
if !receiver.span.from_expansion();
|
||||
then {
|
||||
let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
|
||||
if ty.is_str() {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REPEAT_ONCE,
|
||||
expr.span,
|
||||
"calling `repeat(1)` on str",
|
||||
"consider using `.to_string()` instead",
|
||||
format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if ty.builtin_index().is_some() {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REPEAT_ONCE,
|
||||
expr.span,
|
||||
"calling `repeat(1)` on slice",
|
||||
"consider using `.to_vec()` instead",
|
||||
format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::String) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REPEAT_ONCE,
|
||||
expr.span,
|
||||
"calling `repeat(1)` on a string literal",
|
||||
"consider using `.clone()` instead",
|
||||
format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue