Port #[must_use] to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
This commit is contained in:
parent
953bf2be89
commit
b92cccb977
4 changed files with 40 additions and 20 deletions
|
|
@ -15,6 +15,9 @@ use clippy_utils::ty::is_must_use_ty;
|
|||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{return_ty, trait_ref_of_method};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_attr_data_structures::find_attr;
|
||||
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
|
|
@ -22,7 +25,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
|
|||
|
||||
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
let attrs = cx.tcx.hir_attrs(item.hir_id());
|
||||
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
|
||||
let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
|
||||
if let hir::ItemKind::Fn {
|
||||
ref sig,
|
||||
body: ref body_id,
|
||||
|
|
@ -31,8 +34,8 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
|
|||
{
|
||||
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
if let Some(attr) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
|
||||
if let Some((attr_span, reason)) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig);
|
||||
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
|
||||
check_must_use_candidate(
|
||||
cx,
|
||||
|
|
@ -52,9 +55,9 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
|
|||
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
let attrs = cx.tcx.hir_attrs(item.hir_id());
|
||||
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
|
||||
if let Some(attr) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
|
||||
let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
|
||||
if let Some((attr_span, reason)) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig);
|
||||
} else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() {
|
||||
check_must_use_candidate(
|
||||
cx,
|
||||
|
|
@ -75,9 +78,9 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
|
|||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
|
||||
let attrs = cx.tcx.hir_attrs(item.hir_id());
|
||||
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
|
||||
if let Some(attr) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
|
||||
let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
|
||||
if let Some((attr_span, reason)) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig);
|
||||
} else if let hir::TraitFn::Provided(eid) = *eid {
|
||||
let body = cx.tcx.hir_body(eid);
|
||||
if attr.is_none() && is_public && !is_proc_macro(attrs) {
|
||||
|
|
@ -103,7 +106,8 @@ fn check_needless_must_use(
|
|||
item_id: hir::OwnerId,
|
||||
item_span: Span,
|
||||
fn_header_span: Span,
|
||||
attr: &Attribute,
|
||||
attr_span: Span,
|
||||
reason: Option<Symbol>,
|
||||
attrs: &[Attribute],
|
||||
sig: &FnSig<'_>,
|
||||
) {
|
||||
|
|
@ -119,7 +123,7 @@ fn check_needless_must_use(
|
|||
"this unit-returning function has a `#[must_use]` attribute",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
attr.span(),
|
||||
attr_span,
|
||||
"remove the attribute",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
|
|
@ -137,11 +141,11 @@ fn check_needless_must_use(
|
|||
MUST_USE_UNIT,
|
||||
fn_header_span,
|
||||
"this unit-returning function has a `#[must_use]` attribute",
|
||||
Some(attr.span()),
|
||||
Some(attr_span),
|
||||
"remove `must_use`",
|
||||
);
|
||||
}
|
||||
} else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
|
||||
} else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
|
||||
// Ignore async functions unless Future::Output type is a must_use type
|
||||
if sig.header.is_async() {
|
||||
let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ use rustc_hir::intravisit::FnKind;
|
|||
use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_span::{Span};
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::find_attr;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -74,7 +76,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
|
|||
// We only show this warning for public exported methods.
|
||||
&& cx.effective_visibilities.is_exported(fn_def)
|
||||
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
|
||||
&& !cx.tcx.hir_attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use))
|
||||
&& !find_attr!(
|
||||
cx.tcx.hir_attrs(owner_id.into()),
|
||||
AttributeKind::MustUse { .. }
|
||||
)
|
||||
&& cx.tcx.visibility(fn_def.to_def_id()).is_public()
|
||||
&& let ret_ty = return_ty(cx, owner_id)
|
||||
&& let self_arg = nth_arg(cx, owner_id, 0)
|
||||
|
|
|
|||
|
|
@ -1886,7 +1886,10 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
|||
_ => None,
|
||||
};
|
||||
|
||||
did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use))
|
||||
did.is_some_and(|did| find_attr!(
|
||||
cx.tcx.get_all_attrs(did),
|
||||
AttributeKind::MustUse { ..}
|
||||
))
|
||||
}
|
||||
|
||||
/// Checks if a function's body represents the identity function. Looks for bodies of the form:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause};
|
|||
use std::assert_matches::debug_assert_matches;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::iter;
|
||||
use rustc_attr_data_structures::find_attr;
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
|
||||
use crate::path_res;
|
||||
use crate::paths::{PathNS, lookup_path_str};
|
||||
|
|
@ -326,8 +328,14 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
// Returns whether the type has #[must_use] attribute
|
||||
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
|
||||
ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
|
||||
ty::Adt(adt, _) => find_attr!(
|
||||
cx.tcx.get_all_attrs(adt.did()),
|
||||
AttributeKind::MustUse { ..}
|
||||
),
|
||||
ty::Foreign(did) => find_attr!(
|
||||
cx.tcx.get_all_attrs(*did),
|
||||
AttributeKind::MustUse { ..}
|
||||
),
|
||||
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => {
|
||||
// for the Array case we don't need to care for the len == 0 case
|
||||
// because we don't want to lint functions returning empty arrays
|
||||
|
|
@ -337,7 +345,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
|
||||
for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
|
||||
if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
|
||||
&& cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id), AttributeKind::MustUse { ..})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -347,7 +355,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
ty::Dynamic(binder, _, _) => {
|
||||
for predicate in *binder {
|
||||
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
|
||||
&& cx.tcx.has_attr(trait_ref.def_id, sym::must_use)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { ..})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue