]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / missing_trait_methods.rs
CommitLineData
2b03887a
FG
1use clippy_utils::diagnostics::span_lint_and_help;
2use clippy_utils::is_lint_allowed;
3use clippy_utils::macros::span_is_local;
4use rustc_hir::def_id::DefIdMap;
5use rustc_hir::{Impl, Item, ItemKind};
6use rustc_lint::{LateContext, LateLintPass};
7use rustc_middle::ty::AssocItem;
8use rustc_session::{declare_lint_pass, declare_tool_lint};
9
10declare_clippy_lint! {
11 /// ### What it does
12 /// Checks if a provided method is used implicitly by a trait
13 /// implementation. A usage example would be a wrapper where every method
14 /// should perform some operation before delegating to the inner type's
49aad941 15 /// implementation.
2b03887a
FG
16 ///
17 /// This lint should typically be enabled on a specific trait `impl` item
18 /// rather than globally.
19 ///
20 /// ### Why is this bad?
21 /// Indicates that a method is missing.
22 ///
23 /// ### Example
24 /// ```rust
25 /// trait Trait {
26 /// fn required();
27 ///
28 /// fn provided() {}
29 /// }
30 ///
31 /// # struct Type;
32 /// #[warn(clippy::missing_trait_methods)]
33 /// impl Trait for Type {
34 /// fn required() { /* ... */ }
35 /// }
36 /// ```
37 /// Use instead:
38 /// ```rust
39 /// trait Trait {
40 /// fn required();
41 ///
42 /// fn provided() {}
43 /// }
44 ///
45 /// # struct Type;
46 /// #[warn(clippy::missing_trait_methods)]
47 /// impl Trait for Type {
48 /// fn required() { /* ... */ }
49 ///
50 /// fn provided() { /* ... */ }
51 /// }
52 /// ```
53 #[clippy::version = "1.66.0"]
54 pub MISSING_TRAIT_METHODS,
55 restriction,
56 "trait implementation uses default provided method"
57}
58declare_lint_pass!(MissingTraitMethods => [MISSING_TRAIT_METHODS]);
59
60impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
61 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
62 if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id())
63 && span_is_local(item.span)
64 && let ItemKind::Impl(Impl {
65 items,
66 of_trait: Some(trait_ref),
67 ..
68 }) = item.kind
69 && let Some(trait_id) = trait_ref.trait_def_id()
70 {
71 let mut provided: DefIdMap<&AssocItem> = cx
72 .tcx
73 .provided_trait_methods(trait_id)
74 .map(|assoc| (assoc.def_id, assoc))
75 .collect();
76
77 for impl_item in *items {
78 if let Some(def_id) = impl_item.trait_item_def_id {
79 provided.remove(&def_id);
80 }
81 }
82
9c376795
FG
83 cx.tcx.with_stable_hashing_context(|hcx| {
84 for assoc in provided.values_sorted(&hcx, true) {
85 let source_map = cx.tcx.sess.source_map();
86 let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
2b03887a 87
9c376795
FG
88 span_lint_and_help(
89 cx,
90 MISSING_TRAIT_METHODS,
91 source_map.guess_head_span(item.span),
92 &format!("missing trait method provided by default: `{}`", assoc.name),
93 Some(definition_span),
94 "implement the method",
95 );
96 }
9ffffee4 97 });
2b03887a
FG
98 }
99 }
100}