Auto merge of #6896 - TaKO8Ki:refactor-lints-in-methods-module, r=phansch
Refactor lints in methods module This PR refactors methods lints other than the lints I refactored in https://github.com/rust-lang/rust-clippy/pull/6826 and moves some functions to methods/utils.rs. Basically, I follow the instruction described in #6680. **For ease of review, I refactored step by step, keeping each commit small.** closes https://github.com/rust-lang/rust-clippy/issues/6886 cc: `@phansch,` `@flip1995,` `@Y-Nak` changelog: Move lints in methods module to their own modules and some function to methods/utils.rs.
This commit is contained in:
commit
029777f029
54
clippy_lints/src/methods/chars_cmp.rs
Normal file
54
clippy_lints/src/methods/chars_cmp.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{method_chain_args, single_segment_path};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_lint::Lint;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
info: &crate::methods::BinaryExprInfo<'_>,
|
||||
chain_methods: &[&str],
|
||||
lint: &'static Lint,
|
||||
suggest: &str,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind;
|
||||
if arg_char.len() == 1;
|
||||
if let hir::ExprKind::Path(ref qpath) = fun.kind;
|
||||
if let Some(segment) = single_segment_path(qpath);
|
||||
if segment.ident.name == sym::Some;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
|
||||
|
||||
if *self_ty.kind() != ty::Str {
|
||||
return false;
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
lint,
|
||||
info.expr.span,
|
||||
&format!("you should use the `{}` method", suggest),
|
||||
"like this",
|
||||
format!("{}{}.{}({})",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
|
||||
suggest,
|
||||
snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)),
|
||||
applicability,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
44
clippy_lints/src/methods/chars_cmp_with_unwrap.rs
Normal file
44
clippy_lints/src/methods/chars_cmp_with_unwrap.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_lint::Lint;
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
info: &crate::methods::BinaryExprInfo<'_>,
|
||||
chain_methods: &[&str],
|
||||
lint: &'static Lint,
|
||||
suggest: &str,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprKind::Lit(ref lit) = info.other.kind;
|
||||
if let ast::LitKind::Char(c) = lit.node;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
lint,
|
||||
info.expr.span,
|
||||
&format!("you should use the `{}` method", suggest),
|
||||
"like this",
|
||||
format!("{}{}.{}('{}')",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
|
||||
suggest,
|
||||
c),
|
||||
applicability,
|
||||
);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
13
clippy_lints/src/methods/chars_last_cmp.rs
Normal file
13
clippy_lints/src/methods/chars_last_cmp.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use crate::methods::chars_cmp;
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::CHARS_LAST_CMP;
|
||||
|
||||
/// Checks for the `CHARS_LAST_CMP` lint.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
|
||||
true
|
||||
} else {
|
||||
chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
|
||||
}
|
||||
}
|
13
clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
Normal file
13
clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use crate::methods::chars_cmp_with_unwrap;
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::CHARS_LAST_CMP;
|
||||
|
||||
/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
|
||||
true
|
||||
} else {
|
||||
chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
|
||||
}
|
||||
}
|
8
clippy_lints/src/methods/chars_next_cmp.rs
Normal file
8
clippy_lints/src/methods/chars_next_cmp.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::CHARS_NEXT_CMP;
|
||||
|
||||
/// Checks for the `CHARS_NEXT_CMP` lint.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
|
||||
}
|
8
clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
Normal file
8
clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::CHARS_NEXT_CMP;
|
||||
|
||||
/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
|
||||
}
|
@ -4,14 +4,20 @@ use clippy_utils::ty::is_copy;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use std::iter;
|
||||
|
||||
use super::CLONE_DOUBLE_REF;
|
||||
use super::CLONE_ON_COPY;
|
||||
|
||||
/// Checks for the `CLONE_ON_COPY` lint.
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
|
||||
if !(args.len() == 1 && method_name == sym::clone) {
|
||||
return;
|
||||
}
|
||||
let arg = &args[0];
|
||||
let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if let ty::Ref(_, inner, _) = arg_ty.kind() {
|
||||
if let ty::Ref(_, innermost, _) = inner.kind() {
|
||||
|
@ -6,11 +6,15 @@ use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use super::CLONE_ON_REF_PTR;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
|
||||
if !(args.len() == 1 && method_name == sym::clone) {
|
||||
return;
|
||||
}
|
||||
let arg = &args[0];
|
||||
let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
|
||||
|
||||
if let ty::Adt(_, subst) = obj_ty.kind() {
|
||||
|
@ -7,12 +7,7 @@ use rustc_span::sym;
|
||||
use super::FILTER_MAP;
|
||||
|
||||
/// lint use of `filter().flat_map()` for `Iterators`
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
_filter_args: &'tcx [hir::Expr<'_>],
|
||||
_map_args: &'tcx [hir::Expr<'_>],
|
||||
) {
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
// lint if caller of `.filter().flat_map()` is an Iterator
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
let msg = "called `filter(..).flat_map(..)` on an `Iterator`";
|
||||
|
@ -7,12 +7,7 @@ use rustc_span::sym;
|
||||
use super::FILTER_MAP;
|
||||
|
||||
/// lint use of `filter_map().flat_map()` for `Iterators`
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
_filter_args: &'tcx [hir::Expr<'_>],
|
||||
_map_args: &'tcx [hir::Expr<'_>],
|
||||
) {
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
// lint if caller of `.filter_map().flat_map()` is an Iterator
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`";
|
||||
|
@ -7,12 +7,7 @@ use rustc_span::sym;
|
||||
use super::FILTER_MAP;
|
||||
|
||||
/// lint use of `filter_map().map()` for `Iterators`
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
_filter_args: &'tcx [hir::Expr<'_>],
|
||||
_map_args: &'tcx [hir::Expr<'_>],
|
||||
) {
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
// lint if caller of `.filter_map().map()` is an Iterator
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
let msg = "called `filter_map(..).map(..)` on an `Iterator`";
|
||||
|
@ -1,20 +1,22 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_trait_def_id, paths, sugg};
|
||||
use clippy_utils::{get_trait_def_id, match_qpath, paths, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::ExprKind;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::FROM_ITER_INSTEAD_OF_COLLECT;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func_kind: &ExprKind<'_>) {
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Path(path) = func_kind;
|
||||
if match_qpath(path, &["from_iter"]);
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
|
||||
if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR);
|
||||
if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::methods::derefs_to_slice;
|
||||
use super::utils::derefs_to_slice;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
|
||||
|
@ -1,4 +1,3 @@
|
||||
use super::INEFFICIENT_TO_STRING;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth};
|
||||
@ -8,14 +7,18 @@ use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use super::INEFFICIENT_TO_STRING;
|
||||
|
||||
/// Checks for the `INEFFICIENT_TO_STRING` lint
|
||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) {
|
||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
|
||||
if_chain! {
|
||||
if args.len() == 1 && method_name == sym!(to_string);
|
||||
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
||||
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
|
||||
if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
|
||||
let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
|
||||
let self_ty = substs.type_at(0);
|
||||
let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
|
||||
if deref_count >= 1;
|
||||
@ -32,7 +35,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr
|
||||
self_ty, deref_self_ty
|
||||
));
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let arg_snippet = snippet_with_applicability(cx, arg.span, "..", &mut applicability);
|
||||
let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"try dereferencing the receiver",
|
||||
|
@ -1,32 +1,43 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::ty::has_iter_method;
|
||||
use clippy_utils::{match_trait_method, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use super::INTO_ITER_ON_REF;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) {
|
||||
if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) {
|
||||
return;
|
||||
}
|
||||
if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
INTO_ITER_ON_REF,
|
||||
method_span,
|
||||
&format!(
|
||||
"this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`",
|
||||
method_name, kind,
|
||||
),
|
||||
"call directly",
|
||||
method_name.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
method_span: Span,
|
||||
method_name: Symbol,
|
||||
args: &[hir::Expr<'_>],
|
||||
) {
|
||||
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
|
||||
if_chain! {
|
||||
if let ty::Ref(..) = self_ty.kind();
|
||||
if method_name == sym::into_iter;
|
||||
if is_trait_method(cx, expr, sym::IntoIterator);
|
||||
if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
INTO_ITER_ON_REF,
|
||||
method_span,
|
||||
&format!(
|
||||
"this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`",
|
||||
method_name, kind,
|
||||
),
|
||||
"call directly",
|
||||
method_name.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::methods::derefs_to_slice;
|
||||
use crate::methods::utils::derefs_to_slice;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::methods::derefs_to_slice;
|
||||
use super::utils::derefs_to_slice;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::paths;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::methods::derefs_to_slice;
|
||||
use super::utils::derefs_to_slice;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
@ -47,12 +47,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, ite
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type)
|
||||
|| matches!(
|
||||
&cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
|
||||
ty::Array(_, _)
|
||||
)
|
||||
{
|
||||
} else if is_vec_or_array(cx, caller_expr) {
|
||||
// caller is a Vec or an Array
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
@ -69,3 +64,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, ite
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_vec_or_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool {
|
||||
is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type)
|
||||
|| matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::methods::derefs_to_slice;
|
||||
use super::utils::derefs_to_slice;
|
||||
use crate::methods::iter_nth_zero;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
|
@ -12,14 +12,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir
|
||||
// lint if caller of skip is an Iterator
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
if let [caller, n] = skip_args {
|
||||
let hint = format!(".nth({})", snippet(cx, n.span, ".."));
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ITER_SKIP_NEXT,
|
||||
expr.span.trim_start(caller.span).unwrap(),
|
||||
"called `skip(..).next()` on an iterator",
|
||||
"use `nth` instead",
|
||||
hint,
|
||||
format!(".nth({})", snippet(cx, n.span, "..")),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
mod bind_instead_of_map;
|
||||
mod bytes_nth;
|
||||
mod chars_cmp;
|
||||
mod chars_cmp_with_unwrap;
|
||||
mod chars_last_cmp;
|
||||
mod chars_last_cmp_with_unwrap;
|
||||
mod chars_next_cmp;
|
||||
mod chars_next_cmp_with_unwrap;
|
||||
mod clone_on_copy;
|
||||
mod clone_on_ref_ptr;
|
||||
mod expect_fun_call;
|
||||
@ -36,6 +42,7 @@ mod option_map_or_none;
|
||||
mod option_map_unwrap_or;
|
||||
mod or_fun_call;
|
||||
mod search_is_some;
|
||||
mod single_char_add_str;
|
||||
mod single_char_insert_string;
|
||||
mod single_char_pattern;
|
||||
mod single_char_push_string;
|
||||
@ -48,23 +55,21 @@ mod unnecessary_fold;
|
||||
mod unnecessary_lazy_eval;
|
||||
mod unwrap_used;
|
||||
mod useless_asref;
|
||||
mod utils;
|
||||
mod wrong_self_convention;
|
||||
mod zst_offset;
|
||||
|
||||
use bind_instead_of_map::BindInsteadOfMap;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::{
|
||||
contains_return, get_trait_def_id, in_macro, iter_input_pats, match_def_path, match_qpath, method_calls,
|
||||
method_chain_args, paths, return_ty, single_segment_path, SpanlessEq,
|
||||
contains_return, get_trait_def_id, in_macro, iter_input_pats, match_qpath, method_calls, paths, return_ty,
|
||||
SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, TraitRef, Ty, TyS};
|
||||
use rustc_semver::RustcVersion;
|
||||
@ -1718,11 +1723,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]),
|
||||
["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]),
|
||||
["map", "filter"] => filter_map::check(cx, expr, false),
|
||||
["map", "filter_map"] => filter_map_map::check(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["map", "filter_map"] => filter_map_map::check(cx, expr),
|
||||
["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()),
|
||||
["map", "find"] => filter_map::check(cx, expr, true),
|
||||
["flat_map", "filter"] => filter_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["flat_map", "filter"] => filter_flat_map::check(cx, expr),
|
||||
["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr),
|
||||
["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]),
|
||||
["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]),
|
||||
[option_check_method, "find"] if "is_some" == *option_check_method || "is_none" == *option_check_method => {
|
||||
@ -1809,46 +1814,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
|
||||
match expr.kind {
|
||||
hir::ExprKind::Call(ref func, ref args) => {
|
||||
if let hir::ExprKind::Path(path) = &func.kind {
|
||||
if match_qpath(path, &["from_iter"]) {
|
||||
from_iter_instead_of_collect::check(cx, expr, args);
|
||||
}
|
||||
}
|
||||
from_iter_instead_of_collect::check(cx, expr, args, &func.kind);
|
||||
},
|
||||
hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => {
|
||||
or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
|
||||
expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
|
||||
|
||||
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
|
||||
if args.len() == 1 && method_call.ident.name == sym::clone {
|
||||
clone_on_copy::check(cx, expr, &args[0], self_ty);
|
||||
clone_on_ref_ptr::check(cx, expr, &args[0]);
|
||||
}
|
||||
if args.len() == 1 && method_call.ident.name == sym!(to_string) {
|
||||
inefficient_to_string::check(cx, expr, &args[0], self_ty);
|
||||
}
|
||||
|
||||
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
|
||||
single_char_push_string::check(cx, expr, args);
|
||||
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
|
||||
single_char_insert_string::check(cx, expr, args);
|
||||
}
|
||||
}
|
||||
|
||||
match self_ty.kind() {
|
||||
ty::Ref(_, ty, _) if *ty.kind() == ty::Str => {
|
||||
for &(method, pos) in &PATTERN_METHODS {
|
||||
if method_call.ident.name.as_str() == method && args.len() > pos {
|
||||
single_char_pattern::check(cx, expr, &args[pos]);
|
||||
}
|
||||
}
|
||||
},
|
||||
ty::Ref(..) if method_call.ident.name == sym::into_iter => {
|
||||
into_iter_on_ref::check(cx, expr, self_ty, *method_span);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
clone_on_copy::check(cx, expr, method_call.ident.name, args);
|
||||
clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
|
||||
inefficient_to_string::check(cx, expr, method_call.ident.name, args);
|
||||
single_char_add_str::check(cx, expr, args);
|
||||
into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args);
|
||||
single_char_pattern::check(cx, expr, method_call.ident.name, args);
|
||||
},
|
||||
hir::ExprKind::Binary(op, ref lhs, ref rhs)
|
||||
if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
|
||||
@ -2015,47 +1991,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn derefs_to_slice<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<&'tcx hir::Expr<'tcx>> {
|
||||
fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Slice(_) => true,
|
||||
ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
|
||||
ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type),
|
||||
ty::Array(_, size) => size
|
||||
.try_eval_usize(cx.tcx, cx.param_env)
|
||||
.map_or(false, |size| size < 32),
|
||||
ty::Ref(_, inner, _) => may_slice(cx, inner),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
|
||||
if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
|
||||
Some(&args[0])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
match ty.kind() {
|
||||
ty::Slice(_) => Some(expr),
|
||||
ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
|
||||
ty::Ref(_, inner, _) => {
|
||||
if may_slice(cx, inner) {
|
||||
Some(expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for `lint_binary_expr_with_method_call`.
|
||||
#[derive(Copy, Clone)]
|
||||
struct BinaryExprInfo<'a> {
|
||||
@ -2068,7 +2003,7 @@ struct BinaryExprInfo<'a> {
|
||||
/// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
|
||||
fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) {
|
||||
macro_rules! lint_with_both_lhs_and_rhs {
|
||||
($func:ident, $cx:expr, $info:ident) => {
|
||||
($func:expr, $cx:expr, $info:ident) => {
|
||||
if !$func($cx, $info) {
|
||||
::std::mem::swap(&mut $info.chain, &mut $info.other);
|
||||
if $func($cx, $info) {
|
||||
@ -2078,145 +2013,10 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr
|
||||
};
|
||||
}
|
||||
|
||||
lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
|
||||
lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info);
|
||||
lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info);
|
||||
lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
|
||||
}
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
|
||||
fn lint_chars_cmp(
|
||||
cx: &LateContext<'_>,
|
||||
info: &BinaryExprInfo<'_>,
|
||||
chain_methods: &[&str],
|
||||
lint: &'static Lint,
|
||||
suggest: &str,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind;
|
||||
if arg_char.len() == 1;
|
||||
if let hir::ExprKind::Path(ref qpath) = fun.kind;
|
||||
if let Some(segment) = single_segment_path(qpath);
|
||||
if segment.ident.name == sym::Some;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
|
||||
|
||||
if *self_ty.kind() != ty::Str {
|
||||
return false;
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
lint,
|
||||
info.expr.span,
|
||||
&format!("you should use the `{}` method", suggest),
|
||||
"like this",
|
||||
format!("{}{}.{}({})",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
|
||||
suggest,
|
||||
snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)),
|
||||
applicability,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks for the `CHARS_NEXT_CMP` lint.
|
||||
fn lint_chars_next_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
|
||||
lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
|
||||
}
|
||||
|
||||
/// Checks for the `CHARS_LAST_CMP` lint.
|
||||
fn lint_chars_last_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
|
||||
if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
|
||||
true
|
||||
} else {
|
||||
lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
|
||||
fn lint_chars_cmp_with_unwrap<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
info: &BinaryExprInfo<'_>,
|
||||
chain_methods: &[&str],
|
||||
lint: &'static Lint,
|
||||
suggest: &str,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprKind::Lit(ref lit) = info.other.kind;
|
||||
if let ast::LitKind::Char(c) = lit.node;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
lint,
|
||||
info.expr.span,
|
||||
&format!("you should use the `{}` method", suggest),
|
||||
"like this",
|
||||
format!("{}{}.{}('{}')",
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
|
||||
suggest,
|
||||
c),
|
||||
applicability,
|
||||
);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
|
||||
fn lint_chars_next_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
|
||||
lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
|
||||
}
|
||||
|
||||
/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
|
||||
fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
|
||||
if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
|
||||
true
|
||||
} else {
|
||||
lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hint_if_single_char_arg(
|
||||
cx: &LateContext<'_>,
|
||||
arg: &hir::Expr<'_>,
|
||||
applicability: &mut Applicability,
|
||||
) -> Option<String> {
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Lit(lit) = &arg.kind;
|
||||
if let ast::LitKind::Str(r, style) = lit.node;
|
||||
let string = r.as_str();
|
||||
if string.chars().count() == 1;
|
||||
then {
|
||||
let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
|
||||
let ch = if let ast::StrStyle::Raw(nhash) = style {
|
||||
let nhash = nhash as usize;
|
||||
// for raw string: r##"a"##
|
||||
&snip[(nhash + 2)..(snip.len() - 1 - nhash)]
|
||||
} else {
|
||||
// for regular string: "a"
|
||||
&snip[1..(snip.len() - 1)]
|
||||
};
|
||||
let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
|
||||
Some(hint)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info);
|
||||
lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info);
|
||||
lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info);
|
||||
lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info);
|
||||
}
|
||||
|
||||
const FN_HEADER: hir::FnHeader = hir::FnHeader {
|
||||
|
14
clippy_lints/src/methods/single_char_add_str.rs
Normal file
14
clippy_lints/src/methods/single_char_add_str.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use crate::methods::{single_char_insert_string, single_char_push_string};
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
|
||||
single_char_push_string::check(cx, expr, args);
|
||||
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
|
||||
single_char_insert_string::check(cx, expr, args);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use crate::methods::get_hint_if_single_char_arg;
|
||||
use super::utils::get_hint_if_single_char_arg;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -1,23 +1,35 @@
|
||||
use crate::methods::get_hint_if_single_char_arg;
|
||||
use super::utils::get_hint_if_single_char_arg;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
use super::SINGLE_CHAR_PATTERN;
|
||||
|
||||
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
|
||||
pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
SINGLE_CHAR_PATTERN,
|
||||
arg.span,
|
||||
"single-character string constant used as pattern",
|
||||
"try using a `char` instead",
|
||||
hint,
|
||||
applicability,
|
||||
);
|
||||
pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
|
||||
for &(method, pos) in &crate::methods::PATTERN_METHODS {
|
||||
if_chain! {
|
||||
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind();
|
||||
if *ty.kind() == ty::Str;
|
||||
if method_name.as_str() == method && args.len() > pos;
|
||||
let arg = &args[pos];
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
SINGLE_CHAR_PATTERN,
|
||||
arg.span,
|
||||
"single-character string constant used as pattern",
|
||||
"try using a `char` instead",
|
||||
hint,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::methods::get_hint_if_single_char_arg;
|
||||
use super::utils::get_hint_if_single_char_arg;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -12,34 +12,35 @@ use super::STRING_EXTEND_CHARS;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||
let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
|
||||
if is_type_diagnostic_item(cx, obj_ty, sym::string_type) {
|
||||
let arg = &args[1];
|
||||
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
|
||||
let target = &arglists[0][0];
|
||||
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
||||
let ref_str = if *self_ty.kind() == ty::Str {
|
||||
""
|
||||
} else if is_type_diagnostic_item(cx, self_ty, sym::string_type) {
|
||||
"&"
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
if !is_type_diagnostic_item(cx, obj_ty, sym::string_type) {
|
||||
return;
|
||||
}
|
||||
let arg = &args[1];
|
||||
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
|
||||
let target = &arglists[0][0];
|
||||
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
||||
let ref_str = if *self_ty.kind() == ty::Str {
|
||||
""
|
||||
} else if is_type_diagnostic_item(cx, self_ty, sym::string_type) {
|
||||
"&"
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_EXTEND_CHARS,
|
||||
expr.span,
|
||||
"calling `.extend(_.chars())`",
|
||||
"try this",
|
||||
format!(
|
||||
"{}.push_str({}{})",
|
||||
snippet_with_applicability(cx, args[0].span, "..", &mut applicability),
|
||||
ref_str,
|
||||
snippet_with_applicability(cx, target.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_EXTEND_CHARS,
|
||||
expr.span,
|
||||
"calling `.extend(_.chars())`",
|
||||
"try this",
|
||||
format!(
|
||||
"{}.push_str({}{})",
|
||||
snippet_with_applicability(cx, args[0].span, "..", &mut applicability),
|
||||
ref_str,
|
||||
snippet_with_applicability(cx, target.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
78
clippy_lints/src/methods/utils.rs
Normal file
78
clippy_lints/src/methods/utils.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
pub(super) fn derefs_to_slice<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<&'tcx hir::Expr<'tcx>> {
|
||||
fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Slice(_) => true,
|
||||
ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
|
||||
ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type),
|
||||
ty::Array(_, size) => size
|
||||
.try_eval_usize(cx.tcx, cx.param_env)
|
||||
.map_or(false, |size| size < 32),
|
||||
ty::Ref(_, inner, _) => may_slice(cx, inner),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
|
||||
if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
|
||||
Some(&args[0])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
match ty.kind() {
|
||||
ty::Slice(_) => Some(expr),
|
||||
ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
|
||||
ty::Ref(_, inner, _) => {
|
||||
if may_slice(cx, inner) {
|
||||
Some(expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_hint_if_single_char_arg(
|
||||
cx: &LateContext<'_>,
|
||||
arg: &hir::Expr<'_>,
|
||||
applicability: &mut Applicability,
|
||||
) -> Option<String> {
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Lit(lit) = &arg.kind;
|
||||
if let ast::LitKind::Str(r, style) = lit.node;
|
||||
let string = r.as_str();
|
||||
if string.chars().count() == 1;
|
||||
then {
|
||||
let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
|
||||
let ch = if let ast::StrStyle::Raw(nhash) = style {
|
||||
let nhash = nhash as usize;
|
||||
// for raw string: r##"a"##
|
||||
&snip[(nhash + 2)..(snip.len() - 1 - nhash)]
|
||||
} else {
|
||||
// for regular string: "a"
|
||||
&snip[1..(snip.len() - 1)]
|
||||
};
|
||||
let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
|
||||
Some(hint)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user