Skip to content

Commit ca5c281

Browse files
committed
items_after_statements: Do less work in the default case.
1 parent aef0710 commit ca5c281

File tree

1 file changed

+29
-30
lines changed

1 file changed

+29
-30
lines changed

clippy_lints/src/items_after_statements.rs

Lines changed: 29 additions & 30 deletions
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
}

0 commit comments

Comments
 (0)