use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
use clippy_utils::{
- can_move_expr_to_closure, in_constant, is_allowed, is_else_clause, is_lang_ctor, match_var, peel_hir_expr_refs,
+ can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id,
+ peel_hir_expr_refs,
};
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind};
+use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, MatchSource, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{
- symbol::{sym, Ident},
- SyntaxContext,
-};
+use rustc_span::{sym, SyntaxContext};
declare_clippy_lint! {
- /// **What it does:** Checks for usages of `match` which could be implemented using `map`
- ///
- /// **Why is this bad?** Using the `map` method is clearer and more concise.
- ///
- /// **Known problems:** None.
+ /// ### What it does
+ /// Checks for usages of `match` which could be implemented using `map`
///
- /// **Example:**
+ /// ### Why is this bad?
+ /// Using the `map` method is clearer and more concise.
///
+ /// ### Example
/// ```rust
/// match Some(0) {
/// Some(x) => Some(x + 1),
None => return,
};
+ // These two lints will go back and forth with each other.
if cx.typeck_results().expr_ty(some_expr) == cx.tcx.types.unit
- && !is_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
+ && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
{
return;
}
+ // `map` won't perform any adjustments.
+ if !cx.typeck_results().expr_adjustments(some_expr).is_empty() {
+ return;
+ }
+
if !can_move_expr_to_closure(cx, some_expr) {
return;
}
scrutinee_str.into()
};
- let body_str = if let PatKind::Binding(annotation, _, some_binding, None) = some_pat.kind {
- match can_pass_as_func(cx, some_binding, some_expr) {
+ let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
+ match can_pass_as_func(cx, id, some_expr) {
Some(func) if func.span.ctxt() == some_expr.span.ctxt() => {
snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
},
_ => {
- if match_var(some_expr, some_binding.name)
- && !is_allowed(cx, MATCH_AS_REF, expr.hir_id)
+ if path_to_local_id(some_expr, id)
+ && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
&& binding_ref.is_some()
{
return;
// Checks whether the expression could be passed as a function, or whether a closure is needed.
// Returns the function to be passed to `map` if it exists.
-fn can_pass_as_func(cx: &LateContext<'tcx>, binding: Ident, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
match expr.kind {
ExprKind::Call(func, [arg])
- if match_var(arg, binding.name) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
+ if path_to_local_id(arg, binding) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
{
Some(func)
},