items_after_statements: Do less work in the default case.

This commit is contained in:
Jason Newcomb 2024-06-12 20:14:50 -04:00
parent aef0710054
commit ca5c2813eb

View file

@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
impl LateLintPass<'_> for ItemsAfterStatements {
fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
if in_external_macro(cx.sess(), block.span) {
return;
}
// skip initial items
let stmts = block
.stmts
.iter()
.skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)));
// lint on all further items
for stmt in stmts {
if let StmtKind::Item(item_id) = stmt.kind {
let item = cx.tcx.hir().item(item_id);
if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) {
return;
}
if let ItemKind::Macro(..) = item.kind {
// do not lint `macro_rules`, but continue processing further statements
continue;
}
span_lint_hir(
cx,
ITEMS_AFTER_STATEMENTS,
item.hir_id(),
item.span,
"adding items after statements is confusing, since items exist from the \
start of the scope",
);
}
if block.stmts.len() > 1 {
let ctxt = block.span.ctxt();
let mut in_external = None;
block
.stmts
.iter()
.skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)))
.filter_map(|stmt| match stmt.kind {
StmtKind::Item(id) => Some(cx.tcx.hir().item(id)),
_ => None,
})
// Ignore macros since they can only see previously defined locals.
.filter(|item| !matches!(item.kind, ItemKind::Macro(..)))
// Stop linting if macros define items.
.take_while(|item| item.span.ctxt() == ctxt)
// Don't use `next` due to the complex filter chain.
.for_each(|item| {
// Only do the macro check once, but delay it until it's needed.
if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) {
span_lint_hir(
cx,
ITEMS_AFTER_STATEMENTS,
item.hir_id(),
item.span,
"adding items after statements is confusing, since items exist from the \
start of the scope",
);
}
});
}
}
}