about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2024-06-12 20:14:50 -0400
committerJason Newcomb <jsnewcomb@pm.me>2024-07-07 16:41:36 -0400
commitca5c2813eb7e988c4d2a25312f5749cf6686230e (patch)
tree6c68303b82baccd24776c56220de0553bdeba2b7
parentaef07100544f44c6813fc811e9f0440551ce418d (diff)
downloadrust-ca5c2813eb7e988c4d2a25312f5749cf6686230e.tar.gz
rust-ca5c2813eb7e988c4d2a25312f5749cf6686230e.zip
`items_after_statements`: Do less work in the default case.
-rw-r--r--clippy_lints/src/items_after_statements.rs59
1 files changed, 29 insertions, 30 deletions
diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs
index 39223c20470..a88d8e24fda 100644
--- a/clippy_lints/src/items_after_statements.rs
+++ b/clippy_lints/src/items_after_statements.rs
@@ -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",
+                        );
+                    }
+                });
         }
     }
 }