diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index d980831d3b..3d74001ecf 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -305,19 +305,16 @@ where self.semantic.flags -= SemanticModelFlags::IMPORT_BOUNDARY; } - // Track whether we've seen docstrings, non-imports, etc. + // Track whether we've seen module docstrings, non-imports, etc. match stmt { Stmt::Expr(ast::StmtExpr { value, .. }) - if !self - .semantic - .flags - .intersects(SemanticModelFlags::MODULE_DOCSTRING) + if !self.semantic.seen_module_docstring_boundary() && value.is_string_literal_expr() => { - self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING; + self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING_BOUNDARY; } Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. }) => { - self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING; + self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING_BOUNDARY; // Allow __future__ imports until we see a non-__future__ import. if let Some("__future__") = module.as_deref() { @@ -332,11 +329,11 @@ where } } Stmt::Import(_) => { - self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING; + self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING_BOUNDARY; self.semantic.flags |= SemanticModelFlags::FUTURES_BOUNDARY; } _ => { - self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING; + self.semantic.flags |= SemanticModelFlags::MODULE_DOCSTRING_BOUNDARY; self.semantic.flags |= SemanticModelFlags::FUTURES_BOUNDARY; if !(self.semantic.seen_import_boundary() || helpers::is_assignment_to_a_dunder(stmt) diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index df5e3ab7d0..516c59d1f6 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -1499,6 +1499,12 @@ impl<'a> SemanticModel<'a> { self.flags.intersects(SemanticModelFlags::FUTURES_BOUNDARY) } + /// Return `true` if the model has traversed past the module docstring boundary. + pub const fn seen_module_docstring_boundary(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::MODULE_DOCSTRING_BOUNDARY) + } + /// Return `true` if `__future__`-style type annotations are enabled. pub const fn future_annotations(&self) -> bool { self.flags @@ -1807,7 +1813,7 @@ bitflags! { /// /// x: int = 1 /// ``` - const MODULE_DOCSTRING = 1 << 16; + const MODULE_DOCSTRING_BOUNDARY = 1 << 16; /// The model is in a type parameter definition. ///