1 use clippy_utils::diagnostics::span_lint_and_help; 2 use clippy_utils::is_lint_allowed; 3 use clippy_utils::macros::span_is_local; 4 use rustc_hir::def_id::DefIdMap; 5 use rustc_hir::{Impl, Item, ItemKind}; 6 use rustc_lint::{LateContext, LateLintPass}; 7 use rustc_middle::ty::AssocItem; 8 use rustc_session::{declare_lint_pass, declare_tool_lint}; 9 10 declare_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 15 /// implementation. 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 } 58 declare_lint_pass!(MissingTraitMethods => [MISSING_TRAIT_METHODS]); 59 60 impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>)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 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)); 87 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 } 97 }); 98 } 99 } 100 } 101