Auto merge of #9670 - Alexendoo:missing-trait-methods, r=Jarcho
Add `missing_trait_methods` lint Closes #9661 changelog: new lint: [`missing_trait_methods`]
This commit is contained in:
commit
4612fdfa7b
9 changed files with 221 additions and 0 deletions
|
|
@ -407,6 +407,7 @@ store.register_lints(&[
|
|||
missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
|
||||
missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
|
||||
missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
|
||||
missing_trait_methods::MISSING_TRAIT_METHODS,
|
||||
mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION,
|
||||
mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
|
||||
module_style::MOD_MODULE_FILES,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
|
|||
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
|
||||
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
|
||||
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
|
||||
LintId::of(missing_trait_methods::MISSING_TRAIT_METHODS),
|
||||
LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
|
||||
LintId::of(module_style::MOD_MODULE_FILES),
|
||||
LintId::of(module_style::SELF_NAMED_MODULE_FILES),
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ mod missing_const_for_fn;
|
|||
mod missing_doc;
|
||||
mod missing_enforced_import_rename;
|
||||
mod missing_inline;
|
||||
mod missing_trait_methods;
|
||||
mod mixed_read_write_in_expression;
|
||||
mod module_style;
|
||||
mod multi_assignments;
|
||||
|
|
@ -916,6 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(box_default::BoxDefault));
|
||||
store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
|
||||
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
|
||||
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
|||
98
clippy_lints/src/missing_trait_methods.rs
Normal file
98
clippy_lints/src/missing_trait_methods.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use clippy_utils::macros::span_is_local;
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::{Impl, Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::AssocItem;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks if a provided method is used implicitly by a trait
|
||||
/// implementation. A usage example would be a wrapper where every method
|
||||
/// should perform some operation before delegating to the inner type's
|
||||
/// implemenation.
|
||||
///
|
||||
/// This lint should typically be enabled on a specific trait `impl` item
|
||||
/// rather than globally.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Indicates that a method is missing.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// trait Trait {
|
||||
/// fn required();
|
||||
///
|
||||
/// fn provided() {}
|
||||
/// }
|
||||
///
|
||||
/// # struct Type;
|
||||
/// #[warn(clippy::missing_trait_methods)]
|
||||
/// impl Trait for Type {
|
||||
/// fn required() { /* ... */ }
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// trait Trait {
|
||||
/// fn required();
|
||||
///
|
||||
/// fn provided() {}
|
||||
/// }
|
||||
///
|
||||
/// # struct Type;
|
||||
/// #[warn(clippy::missing_trait_methods)]
|
||||
/// impl Trait for Type {
|
||||
/// fn required() { /* ... */ }
|
||||
///
|
||||
/// fn provided() { /* ... */ }
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub MISSING_TRAIT_METHODS,
|
||||
restriction,
|
||||
"trait implementation uses default provided method"
|
||||
}
|
||||
declare_lint_pass!(MissingTraitMethods => [MISSING_TRAIT_METHODS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id())
|
||||
&& span_is_local(item.span)
|
||||
&& let ItemKind::Impl(Impl {
|
||||
items,
|
||||
of_trait: Some(trait_ref),
|
||||
..
|
||||
}) = item.kind
|
||||
&& let Some(trait_id) = trait_ref.trait_def_id()
|
||||
{
|
||||
let mut provided: DefIdMap<&AssocItem> = cx
|
||||
.tcx
|
||||
.provided_trait_methods(trait_id)
|
||||
.map(|assoc| (assoc.def_id, assoc))
|
||||
.collect();
|
||||
|
||||
for impl_item in *items {
|
||||
if let Some(def_id) = impl_item.trait_item_def_id {
|
||||
provided.remove(&def_id);
|
||||
}
|
||||
}
|
||||
|
||||
for assoc in provided.values() {
|
||||
let source_map = cx.tcx.sess.source_map();
|
||||
let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
|
||||
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
MISSING_TRAIT_METHODS,
|
||||
source_map.guess_head_span(item.span),
|
||||
&format!("missing trait method provided by default: `{}`", assoc.name),
|
||||
Some(definition_span),
|
||||
"implement the method",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue