Skip to content

Commit c78cc7a

Browse files
committed
Add is_trait_item, refactor or_fun_call and unwrap_or_else_default
1 parent 11ef047 commit c78cc7a

File tree

5 files changed

+29
-32
lines changed

5 files changed

+29
-32
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,12 +313,12 @@ declare_clippy_lint! {
313313

314314
declare_clippy_lint! {
315315
/// ### What it does
316-
/// Checks for usages of `_.unwrap_or_else(Default::default)` on Option and
317-
/// Result values.
316+
/// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
317+
/// `Result` values.
318318
///
319319
/// ### Why is this bad?
320-
/// Readability, these can be written as `option.unwrap_or_default` or
321-
/// `result.unwrap_or_default`.
320+
/// Readability, these can be written as `_.unwrap_or_default`, which is
321+
/// simpler and more concise.
322322
///
323323
/// ### Examples
324324
/// ```rust

clippy_lints/src/methods/or_fun_call.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::eager_or_lazy::is_lazyness_candidate;
3+
use clippy_utils::is_trait_item;
34
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite};
4-
use clippy_utils::ty::{implements_trait, qpath_target_trait};
5+
use clippy_utils::ty::implements_trait;
56
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
67
use clippy_utils::{contains_return, last_path_segment, paths};
78
use if_chain::if_chain;
@@ -35,9 +36,7 @@ pub(super) fn check<'tcx>(
3536
or_has_args: bool,
3637
span: Span,
3738
) -> bool {
38-
let is_default_default = |qpath, default_trait_id| {
39-
qpath_target_trait(cx, qpath, fun.hir_id).map_or(false, |target_trait| target_trait == default_trait_id)
40-
};
39+
let is_default_default = || is_trait_item(cx, fun, sym::Default);
4140

4241
let implements_default = |arg, default_trait_id| {
4342
let arg_ty = cx.typeck_results().expr_ty(arg);
@@ -52,7 +51,7 @@ pub(super) fn check<'tcx>(
5251
let path = last_path_segment(qpath).ident.name;
5352
// needs to target Default::default in particular or be *::new and have a Default impl
5453
// available
55-
if (matches!(path, kw::Default) && is_default_default(qpath, default_trait_id))
54+
if (matches!(path, kw::Default) && is_default_default())
5655
|| (matches!(path, sym::new) && implements_default(arg, default_trait_id));
5756

5857
then {

clippy_lints/src/methods/unwrap_or_else_default.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
33
use super::UNWRAP_OR_ELSE_DEFAULT;
44
use clippy_utils::{
5-
diagnostics::span_lint_and_sugg,
6-
source::snippet_with_applicability,
7-
ty::{is_type_diagnostic_item, qpath_target_trait},
5+
diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item,
86
};
97
use rustc_errors::Applicability;
108
use rustc_hir as hir;
@@ -26,10 +24,7 @@ pub(super) fn check<'tcx>(
2624

2725
if_chain! {
2826
if is_option || is_result;
29-
if let hir::ExprKind::Path(ref qpath) = u_arg.kind;
30-
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
31-
if let Some(target_trait) = qpath_target_trait(cx, qpath, u_arg.hir_id);
32-
if target_trait == default_trait_id;
27+
if is_trait_item(cx, u_arg, sym::Default);
3328
then {
3429
let mut applicability = Applicability::MachineApplicable;
3530

clippy_utils/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,25 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
326326
.map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
327327
}
328328

329+
/// Checks if the given expression is a path referring an item on the trait
330+
/// that is marked with the given diagnostic item.
331+
///
332+
/// For checking method call expressions instead of path expressions, use
333+
/// [`is_trait_method`].
334+
///
335+
/// For example, to find if an expression like `u64::default` refers to an item
336+
/// of the trait `Default`, which is marked `#[rustc_diagnostic_item = "Default"]`,
337+
/// a `diag_item` of `sym::Default` should be used.
338+
pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
339+
if let hir::ExprKind::Path(ref qpath) = expr.kind {
340+
cx.qpath_res(qpath, expr.hir_id)
341+
.opt_def_id()
342+
.map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
343+
} else {
344+
false
345+
}
346+
}
347+
329348
pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
330349
match *path {
331350
QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),

clippy_utils/src/ty.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
#![allow(clippy::module_name_repetitions)]
44

5-
use hir::{HirId, QPath};
65
use rustc_ast::ast::Mutability;
76
use rustc_data_structures::fx::FxHashMap;
87
use rustc_hir as hir;
@@ -137,21 +136,6 @@ pub fn implements_trait<'tcx>(
137136
})
138137
}
139138

140-
/// Gets the trait that a path targets. For example `<SomeTy as Trait>::a` would return the
141-
/// [`DefId`] for `Trait`.
142-
///
143-
/// `cx` must be in a body.
144-
pub fn qpath_target_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, expr_id: HirId) -> Option<DefId> {
145-
let method_res = cx.typeck_results().qpath_res(qpath, expr_id);
146-
let method_id = match method_res {
147-
hir::def::Res::Def(_kind, id) => Some(id),
148-
_ => None,
149-
};
150-
let method_id = method_id?;
151-
152-
cx.tcx.trait_of_item(method_id)
153-
}
154-
155139
/// Checks whether this type implements `Drop`.
156140
pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
157141
match ty.ty_adt_def() {

0 commit comments

Comments
 (0)