Skip to content

Commit 510cfe3

Browse files
committed
Auto merge of rust-lang#13067 - Jarcho:misc_small3, r=Manishearth
Misc refactorings part 3 And some more changes. Same general idea of checking the HIR tree first when linting. changelog: none
2 parents dfb9253 + 5ae33c7 commit 510cfe3

11 files changed

+120
-161
lines changed

clippy_lints/src/inherent_to_string.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,6 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S
9191

9292
impl<'tcx> LateLintPass<'tcx> for InherentToString {
9393
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
94-
if impl_item.span.from_expansion() {
95-
return;
96-
}
97-
9894
// Check if item is a method called `to_string` and has a parameter 'self'
9995
if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
10096
// #11201
@@ -106,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
106102
&& decl.implicit_self.has_implicit_self()
107103
&& decl.inputs.len() == 1
108104
&& impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
105+
&& !impl_item.span.from_expansion()
109106
// Check if return type is String
110107
&& is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
111108
// Filters instances of to_string which are required by a trait

clippy_lints/src/inline_fn_without_body.rs

+18-23
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
33
use clippy_utils::diagnostics::span_lint_and_then;
44
use clippy_utils::sugg::DiagExt;
5-
use rustc_ast::ast::Attribute;
65
use rustc_errors::Applicability;
76
use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
87
use rustc_lint::{LateContext, LateLintPass};
98
use rustc_session::declare_lint_pass;
10-
use rustc_span::{sym, Symbol};
9+
use rustc_span::sym;
1110

1211
declare_clippy_lint! {
1312
/// ### What it does
@@ -34,27 +33,23 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
3433

3534
impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
3635
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
37-
if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind {
38-
let attrs = cx.tcx.hir().attrs(item.hir_id());
39-
check_attrs(cx, item.ident.name, attrs);
36+
if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
37+
&& let Some(attr) = cx
38+
.tcx
39+
.hir()
40+
.attrs(item.hir_id())
41+
.iter()
42+
.find(|a| a.has_name(sym::inline))
43+
{
44+
span_lint_and_then(
45+
cx,
46+
INLINE_FN_WITHOUT_BODY,
47+
attr.span,
48+
format!("use of `#[inline]` on trait method `{}` which has no body", item.ident),
49+
|diag| {
50+
diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
51+
},
52+
);
4053
}
4154
}
4255
}
43-
44-
fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
45-
for attr in attrs {
46-
if !attr.has_name(sym::inline) {
47-
continue;
48-
}
49-
50-
span_lint_and_then(
51-
cx,
52-
INLINE_FN_WITHOUT_BODY,
53-
attr.span,
54-
format!("use of `#[inline]` on trait method `{name}` which has no body"),
55-
|diag| {
56-
diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
57-
},
58-
);
59-
}
60-
}

clippy_lints/src/instant_subtraction.rs

+7-14
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,19 @@ impl LateLintPass<'_> for InstantSubtraction {
8585
lhs,
8686
rhs,
8787
) = expr.kind
88+
&& let typeck = cx.typeck_results()
89+
&& ty::is_type_diagnostic_item(cx, typeck.expr_ty(lhs), sym::Instant)
8890
{
91+
let rhs_ty = typeck.expr_ty(rhs);
92+
8993
if is_instant_now_call(cx, lhs)
90-
&& is_an_instant(cx, rhs)
94+
&& ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant)
9195
&& let Some(sugg) = Sugg::hir_opt(cx, rhs)
9296
{
9397
print_manual_instant_elapsed_sugg(cx, expr, sugg);
94-
} else if !expr.span.from_expansion()
98+
} else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration)
99+
&& !expr.span.from_expansion()
95100
&& self.msrv.meets(msrvs::TRY_FROM)
96-
&& is_an_instant(cx, lhs)
97-
&& is_a_duration(cx, rhs)
98101
{
99102
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
100103
}
@@ -115,16 +118,6 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
115118
}
116119
}
117120

118-
fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
119-
let expr_ty = cx.typeck_results().expr_ty(expr);
120-
ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant)
121-
}
122-
123-
fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
124-
let expr_ty = cx.typeck_results().expr_ty(expr);
125-
ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration)
126-
}
127-
128121
fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
129122
span_lint_and_sugg(
130123
cx,

clippy_lints/src/items_after_statements.rs

+29-30
Original file line numberDiff line numberDiff line change
@@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
5454

5555
impl LateLintPass<'_> for ItemsAfterStatements {
5656
fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
57-
if in_external_macro(cx.sess(), block.span) {
58-
return;
59-
}
60-
61-
// skip initial items
62-
let stmts = block
63-
.stmts
64-
.iter()
65-
.skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)));
66-
67-
// lint on all further items
68-
for stmt in stmts {
69-
if let StmtKind::Item(item_id) = stmt.kind {
70-
let item = cx.tcx.hir().item(item_id);
71-
if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) {
72-
return;
73-
}
74-
if let ItemKind::Macro(..) = item.kind {
75-
// do not lint `macro_rules`, but continue processing further statements
76-
continue;
77-
}
78-
span_lint_hir(
79-
cx,
80-
ITEMS_AFTER_STATEMENTS,
81-
item.hir_id(),
82-
item.span,
83-
"adding items after statements is confusing, since items exist from the \
84-
start of the scope",
85-
);
86-
}
57+
if block.stmts.len() > 1 {
58+
let ctxt = block.span.ctxt();
59+
let mut in_external = None;
60+
block
61+
.stmts
62+
.iter()
63+
.skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)))
64+
.filter_map(|stmt| match stmt.kind {
65+
StmtKind::Item(id) => Some(cx.tcx.hir().item(id)),
66+
_ => None,
67+
})
68+
// Ignore macros since they can only see previously defined locals.
69+
.filter(|item| !matches!(item.kind, ItemKind::Macro(..)))
70+
// Stop linting if macros define items.
71+
.take_while(|item| item.span.ctxt() == ctxt)
72+
// Don't use `next` due to the complex filter chain.
73+
.for_each(|item| {
74+
// Only do the macro check once, but delay it until it's needed.
75+
if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) {
76+
span_lint_hir(
77+
cx,
78+
ITEMS_AFTER_STATEMENTS,
79+
item.hir_id(),
80+
item.span,
81+
"adding items after statements is confusing, since items exist from the \
82+
start of the scope",
83+
);
84+
}
85+
});
8786
}
8887
}
8988
}

clippy_lints/src/iter_not_returning_iterator.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId;
44
use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
55
use rustc_lint::{LateContext, LateLintPass};
66
use rustc_session::declare_lint_pass;
7-
use rustc_span::symbol::sym;
7+
use rustc_span::{sym, Symbol};
88

99
declare_clippy_lint! {
1010
/// ### What it does
@@ -43,30 +43,27 @@ declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
4343

4444
impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
4545
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
46-
let name = item.ident.name.as_str();
47-
if matches!(name, "iter" | "iter_mut") {
48-
if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
49-
check_sig(cx, name, fn_sig, item.owner_id.def_id);
50-
}
46+
if let TraitItemKind::Fn(fn_sig, _) = &item.kind
47+
&& matches!(item.ident.name, sym::iter | sym::iter_mut)
48+
{
49+
check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
5150
}
5251
}
5352

5453
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
55-
let name = item.ident.name.as_str();
56-
if matches!(name, "iter" | "iter_mut")
54+
if let ImplItemKind::Fn(fn_sig, _) = &item.kind
55+
&& matches!(item.ident.name, sym::iter | sym::iter_mut)
5756
&& !matches!(
5857
cx.tcx.parent_hir_node(item.hir_id()),
5958
Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some()
6059
)
6160
{
62-
if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
63-
check_sig(cx, name, fn_sig, item.owner_id.def_id);
64-
}
61+
check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
6562
}
6663
}
6764
}
6865

69-
fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
66+
fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDefId) {
7067
if sig.decl.implicit_self.has_implicit_self() {
7168
let ret_ty = cx
7269
.tcx

clippy_lints/src/iter_without_into_iter.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
125125

126126
impl LateLintPass<'_> for IterWithoutIntoIter {
127127
fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
128-
if !in_external_macro(cx.sess(), item.span)
129-
&& let ItemKind::Impl(imp) = item.kind
128+
if let ItemKind::Impl(imp) = item.kind
130129
&& let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
131130
&& let Some(trait_ref) = imp.of_trait
132131
&& trait_ref
133132
.trait_def_id()
134133
.is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
134+
&& !in_external_macro(cx.sess(), item.span)
135135
&& let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
136136
&& let expected_method_name = match mtbl {
137137
Mutability::Mut => sym::iter_mut,

clippy_lints/src/large_const_arrays.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
4646

4747
impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
4848
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
49-
if !item.span.from_expansion()
50-
&& let ItemKind::Const(_, generics, _) = &item.kind
49+
if let ItemKind::Const(_, generics, _) = &item.kind
5150
// Since static items may not have generics, skip generic const items.
5251
// FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
5352
// doesn't account for empty where-clauses that only consist of keyword `where` IINM.
5453
&& generics.params.is_empty() && !generics.has_where_clause_predicates
54+
&& !item.span.from_expansion()
5555
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
5656
&& let ty::Array(element_type, cst) = ty.kind()
5757
&& let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()

clippy_lints/src/large_enum_variant.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,12 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
7777

7878
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
7979
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
80-
if in_external_macro(cx.tcx.sess, item.span) {
81-
return;
82-
}
83-
if let ItemKind::Enum(ref def, _) = item.kind {
84-
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
85-
let ty::Adt(adt, subst) = ty.kind() else {
86-
panic!("already checked whether this is an enum")
87-
};
88-
if adt.variants().len() <= 1 {
89-
return;
90-
}
80+
if let ItemKind::Enum(ref def, _) = item.kind
81+
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
82+
&& let ty::Adt(adt, subst) = ty.kind()
83+
&& adt.variants().len() > 1
84+
&& !in_external_macro(cx.tcx.sess, item.span)
85+
{
9186
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
9287

9388
let mut difference = variants_size[0].size - variants_size[1].size;

clippy_lints/src/large_futures.rs

+20-23
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,26 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]);
5454

5555
impl<'tcx> LateLintPass<'tcx> for LargeFuture {
5656
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
57-
if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) {
58-
return;
59-
}
60-
if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind {
61-
if let ExprKind::Call(func, [expr, ..]) = expr.kind
62-
&& let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
63-
&& let ty = cx.typeck_results().expr_ty(expr)
64-
&& let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
65-
&& implements_trait(cx, ty, future_trait_def_id, &[])
66-
&& let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
67-
&& let size = layout.layout.size()
68-
&& size >= Size::from_bytes(self.future_size_threshold)
69-
{
70-
span_lint_and_sugg(
71-
cx,
72-
LARGE_FUTURES,
73-
expr.span,
74-
format!("large future with a size of {} bytes", size.bytes()),
75-
"consider `Box::pin` on it",
76-
format!("Box::pin({})", snippet(cx, expr.span, "..")),
77-
Applicability::Unspecified,
78-
);
79-
}
57+
if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind
58+
&& let ExprKind::Call(func, [arg, ..]) = scrutinee.kind
59+
&& let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
60+
&& !expr.span.from_expansion()
61+
&& let ty = cx.typeck_results().expr_ty(arg)
62+
&& let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
63+
&& implements_trait(cx, ty, future_trait_def_id, &[])
64+
&& let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
65+
&& let size = layout.layout.size()
66+
&& size >= Size::from_bytes(self.future_size_threshold)
67+
{
68+
span_lint_and_sugg(
69+
cx,
70+
LARGE_FUTURES,
71+
arg.span,
72+
format!("large future with a size of {} bytes", size.bytes()),
73+
"consider `Box::pin` on it",
74+
format!("Box::pin({})", snippet(cx, arg.span, "..")),
75+
Applicability::Unspecified,
76+
);
8077
}
8178
}
8279
}

clippy_lints/src/large_include_file.rs

+7-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use clippy_utils::diagnostics::span_lint_and_note;
2-
use clippy_utils::is_lint_allowed;
32
use clippy_utils::macros::root_macro_call_first_node;
43
use rustc_ast::LitKind;
54
use rustc_hir::{Expr, ExprKind};
@@ -52,24 +51,19 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
5251

5352
impl LateLintPass<'_> for LargeIncludeFile {
5453
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
55-
if let Some(macro_call) = root_macro_call_first_node(cx, expr)
56-
&& !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id)
57-
&& (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
58-
|| cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
59-
&& let ExprKind::Lit(lit) = &expr.kind
60-
{
61-
let len = match &lit.node {
54+
if let ExprKind::Lit(lit) = &expr.kind
55+
&& let len = match &lit.node {
6256
// include_bytes
6357
LitKind::ByteStr(bstr, _) => bstr.len(),
6458
// include_str
6559
LitKind::Str(sym, _) => sym.as_str().len(),
6660
_ => return,
67-
};
68-
69-
if len as u64 <= self.max_file_size {
70-
return;
7161
}
72-
62+
&& len as u64 > self.max_file_size
63+
&& let Some(macro_call) = root_macro_call_first_node(cx, expr)
64+
&& (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
65+
|| cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
66+
{
7367
span_lint_and_note(
7468
cx,
7569
LARGE_INCLUDE_FILE,

0 commit comments

Comments
 (0)