mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-22 10:05:06 +03:00
0f5338cd90
The `restriction` group contains many lints which are not about necessarily “bad” things, but style choices — perhaps even style choices which contradict conventional Rust style — or are otherwise very situational. This results in silly wording like “Why is this bad? It isn't, but ...”, which I’ve seen confuse a newcomer at least once. To improve this situation, this commit replaces the “Why is this bad?” section heading with “Why restrict this?”, for most, but not all, restriction lints. I left alone the ones whose placement in the restriction group is more incidental. In order to make this make sense, I had to remove the “It isn't, but” texts from the contents of the sections. Sometimes further changes were needed, or there were obvious fixes to make, and I went ahead and made those changes without attempting to split them into another commit, even though many of them are not strictly necessary for the “Why restrict this?” project.
101 lines
3.2 KiB
Rust
101 lines
3.2 KiB
Rust
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_clippy_lint! {
|
|
/// ### What it does
|
|
/// Checks if a provided method is used implicitly by a trait
|
|
/// implementation.
|
|
///
|
|
/// ### Why restrict this?
|
|
/// To ensure that a certain implementation implements every method; for example,
|
|
/// a wrapper type where every method should delegate to the corresponding method of
|
|
/// the inner type's implementation.
|
|
///
|
|
/// This lint should typically be enabled on a specific trait `impl` item
|
|
/// rather than globally.
|
|
///
|
|
/// ### Example
|
|
/// ```no_run
|
|
/// trait Trait {
|
|
/// fn required();
|
|
///
|
|
/// fn provided() {}
|
|
/// }
|
|
///
|
|
/// # struct Type;
|
|
/// #[warn(clippy::missing_trait_methods)]
|
|
/// impl Trait for Type {
|
|
/// fn required() { /* ... */ }
|
|
/// }
|
|
/// ```
|
|
/// Use instead:
|
|
/// ```no_run
|
|
/// 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);
|
|
}
|
|
}
|
|
|
|
cx.tcx.with_stable_hashing_context(|hcx| {
|
|
for assoc in provided.values_sorted(&hcx, true) {
|
|
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",
|
|
);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|