//! lint when items are used after statements
use crate::utils::span_lint;
-use matches::matches;
use rustc_ast::ast::{Block, ItemKind, StmtKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
///
/// **Example:**
/// ```rust
+ /// // Bad
/// fn foo() {
/// println!("cake");
/// }
/// foo(); // prints "foo"
/// }
/// ```
+ ///
+ /// ```rust
+ /// // Good
+ /// fn foo() {
+ /// println!("cake");
+ /// }
+ ///
+ /// fn main() {
+ /// fn foo() {
+ /// println!("foo");
+ /// }
+ /// foo(); // prints "foo"
+ /// foo(); // prints "foo"
+ /// }
+ /// ```
pub ITEMS_AFTER_STATEMENTS,
pedantic,
"blocks where an item comes after a statement"
impl EarlyLintPass for ItemsAfterStatements {
fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
- if item.span.from_expansion() {
+ if in_external_macro(cx.sess(), item.span) {
return;
}
- // skip initial items
+ // skip initial items and trailing semicolons
let stmts = item
.stmts
.iter()
.map(|stmt| &stmt.kind)
- .skip_while(|s| matches!(**s, StmtKind::Item(..)));
+ .skip_while(|s| matches!(**s, StmtKind::Item(..) | StmtKind::Empty));
// lint on all further items
for stmt in stmts {
if let StmtKind::Item(ref it) = *stmt {
- if it.span.from_expansion() {
+ if in_external_macro(cx.sess(), it.span) {
return;
}
if let ItemKind::MacroDef(..) = it.kind {