| use clippy_utils::diagnostics::span_lint_and_then; | |
| use clippy_utils::res::MaybeDef; | |
| use rustc_errors::Applicability; | |
| use rustc_hir::{Expr, ExprKind, QPath}; | |
| use rustc_lint::LateContext; | |
| use rustc_span::{Symbol, sym}; | |
| use super::NEEDLESS_OPTION_TAKE; | |
| pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { | |
| // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place | |
| if !recv.is_syntactic_place_expr() | |
| && is_expr_option(cx, recv) | |
| && let Some(function_name) = source_of_temporary_value(recv) | |
| { | |
| span_lint_and_then( | |
| cx, | |
| NEEDLESS_OPTION_TAKE, | |
| expr.span, | |
| "called `Option::take()` on a temporary value", | |
| |diag| { | |
| diag.note(format!( | |
| "`{function_name}` creates a temporary value, so calling take() has no effect" | |
| )); | |
| diag.span_suggestion( | |
| expr.span.with_lo(recv.span.hi()), | |
| "remove", | |
| "", | |
| Applicability::MachineApplicable, | |
| ); | |
| }, | |
| ); | |
| } | |
| } | |
| fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | |
| let expr_type = cx.typeck_results().expr_ty(expr); | |
| expr_type.is_diag_item(cx, sym::Option) | |
| } | |
| /// Returns the string of the function call that creates the temporary. | |
| /// When this function is called, we are reasonably certain that the `ExprKind` is either | |
| /// `Call` or `MethodCall` because we already checked that the expression is not | |
| /// `is_syntactic_place_expr()`. | |
| fn source_of_temporary_value(expr: &Expr<'_>) -> Option<Symbol> { | |
| match expr.peel_borrows().kind { | |
| ExprKind::Call(function, _) => { | |
| if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind | |
| && !func_path.segments.is_empty() | |
| { | |
| return Some(func_path.segments[0].ident.name); | |
| } | |
| if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind { | |
| return Some(func_path_segment.ident.name); | |
| } | |
| None | |
| }, | |
| ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name), | |
| _ => None, | |
| } | |
| } |