| use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; |
| use clippy_utils::res::MaybeDef; |
| use clippy_utils::source::SpanRangeExt; |
| |
| use rustc_errors::Applicability; |
| use rustc_hir::{Expr, ExprKind}; |
| use rustc_lint::LateContext; |
| use rustc_middle::ty::Ty; |
| use rustc_span::{Span, sym}; |
| |
| use super::UNNECESSARY_GET_THEN_CHECK; |
| |
| fn is_a_std_set_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { |
| ty.is_diag_item(cx, sym::HashSet) || ty.is_diag_item(cx, sym::BTreeSet) |
| } |
| |
| fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { |
| ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) |
| } |
| |
| pub(super) fn check( |
| cx: &LateContext<'_>, |
| call_span: Span, |
| get_call: &Expr<'_>, |
| get_caller: &Expr<'_>, |
| arg: &Expr<'_>, |
| is_some: bool, |
| ) { |
| let caller_ty = cx.typeck_results().expr_ty(get_caller); |
| |
| let is_set = is_a_std_set_type(cx, caller_ty); |
| let is_map = is_a_std_map_type(cx, caller_ty); |
| |
| if !is_set && !is_map { |
| return; |
| } |
| let ExprKind::MethodCall(path, _, _, get_call_span) = get_call.kind else { |
| return; |
| }; |
| let both_calls_span = get_call_span.with_hi(call_span.hi()); |
| if let Some(snippet) = both_calls_span.get_source_text(cx) |
| && let Some(arg_snippet) = arg.span.get_source_text(cx) |
| { |
| let generics_snippet = if let Some(generics) = path.args |
| && let Some(generics_snippet) = generics.span_ext.get_source_text(cx) |
| { |
| format!("::{generics_snippet}") |
| } else { |
| String::new() |
| }; |
| let suggestion = if is_set { |
| format!("contains{generics_snippet}({arg_snippet})") |
| } else { |
| format!("contains_key{generics_snippet}({arg_snippet})") |
| }; |
| if is_some { |
| span_lint_and_sugg( |
| cx, |
| UNNECESSARY_GET_THEN_CHECK, |
| both_calls_span, |
| format!("unnecessary use of `{snippet}`"), |
| "replace it with", |
| suggestion, |
| Applicability::MaybeIncorrect, |
| ); |
| } else if let Some(caller_snippet) = get_caller.span.get_source_text(cx) { |
| let full_span = get_caller.span.with_hi(call_span.hi()); |
| |
| span_lint_and_then( |
| cx, |
| UNNECESSARY_GET_THEN_CHECK, |
| both_calls_span, |
| format!("unnecessary use of `{snippet}`"), |
| |diag| { |
| diag.span_suggestion( |
| full_span, |
| "replace it with", |
| format!("{}{caller_snippet}.{suggestion}", if is_some { "" } else { "!" }), |
| Applicability::MaybeIncorrect, |
| ); |
| }, |
| ); |
| } |
| } |
| } |